Help us shape the future of Go! Take the 2026 Go Developer Survey

gtkls-bitwarden-client

module
v0.5.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 3, 2026 License: MIT

README

gtkls-bitwarden-client

A keyboard-driven GTK4 layer-shell Bitwarden client for Linux Wayland desktops.

The app runs as an overlay over your compositor instead of a regular window. It is built for fast vault search, copy-oriented workflows, and lightweight item editing without leaving the current workspace.

Build / Install Requirements

Dependency Version / Notes
Go 1.26.1 or later
GTK4 Runtime libraries for GTK4
gtk4-layer-shell Runtime library providing libgtk4-layer-shell.so.0
Compositor Wayland compositor with wlr-layer-shell support, such as Sway or Hyprland
Secret Service Linux Secret Service keyring, such as GNOME Keyring or KWallet
Install with Go
go install github.com/bnema/gtkls-bitwarden-client/cmd/gtkls-bitwarden-client@v0.2.0
Build from source
git clone https://github.com/bnema/gtkls-bitwarden-client.git
cd gtkls-bitwarden-client
make build
./dist/gtkls-bitwarden-client --version

Headless tests and non-GTK code can be built with the nogtk build tag:

go test -tags nogtk ./...

First Run / Config

Once installed, follow the interactive login flow:

gtkls-bitwarden-client login

Then launch it from the terminal, unlock with your previously defined PIN, and verify your vault sync succeeds:

gtkls-bitwarden-client

(Optional) Use it in your Wayland compositor like Niri for example

Mod+Ctrl+P hotkey-overlay-title="Password Manager: gtkls-bitwarden-client" { spawn "gtkls-bitwarden-client"; }

The default config path is:

~/.config/gtkls-bitwarden-client/config.toml

$XDG_CONFIG_HOME is respected. A missing config file is not an error; built-in defaults are used and the config can be written later through the CLI or GUI.

Optional starter config:

mkdir -p ~/.config/gtkls-bitwarden-client
cp configs/config.example.toml ~/.config/gtkls-bitwarden-client/config.toml

For non-interactive unlock flows, configure bitwarden.email first:

gtkls-bitwarden-client config set bitwarden.email you@example.com

Login / Unlock CLI Flow

Common commands:

gtkls-bitwarden-client login you@example.com --region us
gtkls-bitwarden-client login you@example.com --region eu
gtkls-bitwarden-client login you@example.com --region self_hosted --server-url https://vault.example.com
gtkls-bitwarden-client unlock
gtkls-bitwarden-client status
gtkls-bitwarden-client lock
gtkls-bitwarden-client lock --hard
gtkls-bitwarden-client logout

Auth flags:

--raw                 # print minimal output, such as "login ok" or "unlock ok"
--no-sync             # authenticate/unlock without waiting for initial sync
--passwordenv NAME    # login: read master password from an environment variable
--passwordfile PATH   # login: read master password from a file
--pinenv NAME         # unlock: read local PIN from an environment variable
--pinfile PATH        # unlock: read local PIN from a file

The app does not use the BW_SESSION environment variable. Access tokens, refresh tokens, raw PINs, vault keys, and vault content are never printed to stdout or stderr.

Environment Overrides

All config keys can be overridden through environment variables with the GTKLSBW_ prefix and dots replaced by underscores.

Environment variable Config key
GTKLSBW_BITWARDEN_EMAIL bitwarden.email
GTKLSBW_BITWARDEN_REGION bitwarden.region
GTKLSBW_BITWARDEN_SERVER_URL bitwarden.server_url
GTKLSBW_DEVICE_IDENTIFIER device.identifier
GTKLSBW_SYNC_REVISION_CHECK_INTERVAL sync.revision_check_interval
GTKLSBW_SECURITY_IDLE_RELOCK_AFTER security.idle_relock_after
GTKLSBW_SECURITY_RESIDENT_RELOCK_AFTER security.resident_relock_after
GTKLSBW_ACTIONS_CLIPBOARD_CLEAR_AFTER actions.clipboard_clear_after
GTKLSBW_APPEARANCE_UI_SCALE appearance.ui_scale
GTKLSBW_CACHE_TTL cache.ttl

Environment overrides take precedence over the config file.

Logging

Logs are written to a rotating file by default:

$XDG_STATE_HOME/gtkls-bitwarden-client/logs/gtkls-bitwarden-client.log

If $XDG_STATE_HOME is unset, Linux defaults to:

~/.local/state/gtkls-bitwarden-client/logs/gtkls-bitwarden-client.log

Default logging is file-only, level info, and JSON formatted. Set GTKLSBW_LOG_CONSOLE=true to mirror logs to stderr.

Environment variable Purpose
GTKLSBW_LOG_LEVEL trace, debug, info, warn, warning, error, fatal, panic, or disabled
GTKLSBW_LOG_FORMAT json or console
GTKLSBW_LOG_CONSOLE Mirror logs to stderr when true
GTKLSBW_LOG_PATH Override log file path
GTKLSBW_LOG_MAX_SIZE_MB Rotate after this many MiB
GTKLSBW_LOG_MAX_BACKUPS Number of rotated backups to keep
GTKLSBW_LOG_MAX_AGE_DAYS Maximum age of rotated logs in days

Invalid logging environment values fail startup with a clear error naming the invalid variable. The project follows a strict no-secret logging policy.

Compositor Hotkey

Bind a compositor hotkey to launch the overlay. Example for Sway:

# ~/.config/sway/config
bindsym $mod+Shift+b exec /path/to/gtkls-bitwarden-client

On Wayland, the launcher re-execs itself with libgtk4-layer-shell.so.0 in LD_PRELOAD before GTK initializes. This is required on compositors where gtk4-layer-shell's GDK hook must load before GTK.

Keyboard Shortcuts

Shortcut Context Action
Enter on unlock Unlock Authenticates with local PIN or master-password recovery flow
typing Search Live search with debounce
Up / Down Search Navigate result rows
Enter Search Perform configured primary action
Alt + Enter Search Copy username
Ctrl + Enter Search Open detail view
Ctrl + N Search Create a new login item
Escape Any Quit the overlay
Escape / Backspace Detail / Form Return to search view

Cache and Security Model

  • XDG paths: config, cache, outbox, state, and log paths are derived from one XDG path adapter.
  • Encrypted cache: vault snapshots and outbox data are encrypted on disk with a key derived from the master password using Argon2id and a persisted per-cache salt.
  • Secret Service storage: Bitwarden token bundles, PIN verifier profiles, and quick-unlock envelopes are stored in the Linux Secret Service keyring.
  • Local PIN model: the local PIN is verified with Argon2id and is never sent to Bitwarden. The quick-unlock envelope is bound to the current boot/session.
  • No plaintext search index: the search index is rebuilt in memory and dropped on relock.
  • Restrictive file permissions: config/cache directories use 0700; config/cache files use 0600.
  • No HTTP body dumps: make safety checks for accidental request/response dumps and unsafe persistence patterns.
  • No secret logging: passwords, tokens, PINs, vault keys, and vault content must never be written to logs.

Offline-First Sync / Outbox / Conflicts

Mutations are attempted against the remote server first. If the server is unreachable, the mutation is queued in an encrypted local outbox and replayed on the next successful sync.

If a local mutation conflicts with a remote change for the same item, the service records a conflict and marks the item. Conflict resolution primitives exist in the service layer; the full GUI conflict-resolution flow is still planned.

The sync CLI command is currently informational; background sync runs after unlock/login when enabled. Full-unlock sessions use the resident sync path, while PIN-unlock sessions use a cache-only sync path that refreshes encrypted cache/outbox state without leaving the full vault resident in service memory. Sync ticks that fire while the omnibox is in form/edit mode are skipped until the next interval.

Testing

# All tests
go test ./...

# Headless tests excluding GTK-dependent code
go test -tags nogtk ./...

# Race detection
go test -race -tags nogtk ./...

# Safety checks
make safety

# Full check suite
make check

No tests run against a live Bitwarden server by default. Tests use in-memory or local isolated data.

Dependency Policy

Dependencies are pinned in go.mod and go.sum. Public releases must not require local replace directives. No vendored dependency tree is committed.

github.com/bnema/puregotk transitively uses github.com/bnema/purego, a maintained fork of the cgo-free FFI library needed for the current GTK/layer-shell runtime path. If those patches are merged upstream, the dependency can move back to the upstream module.

Known Limitations

  • Attachments are not supported yet.
  • Clipboard integration uses the GTK/GDK clipboard backend.
  • open_url is accepted by config validation but not implemented in the GUI.
  • Conflict resolution service methods exist, but GUI conflict resolution is incomplete.
  • Editing existing items is supported, but adding custom fields in the form is not yet available.

License

MIT — see LICENSE.

Directories

Path Synopsis
cmd
internal
adapters/clipboard
Package clipboard implements out.Clipboard.
Package clipboard implements out.Clipboard.
adapters/compose
Package compose is the composition root for production adapters.
Package compose is the composition root for production adapters.
adapters/fileutil
Package fileutil contains small filesystem helpers shared by adapters.
Package fileutil contains small filesystem helpers shared by adapters.
adapters/gui/display
Package display provides shared UI display helpers for vault items.
Package display provides shared UI display helpers for vault items.
adapters/gui/omnibox
Package omnibox provides a keyboard-driven adapter for the GTK omnibox UI.
Package omnibox provides a keyboard-driven adapter for the GTK omnibox UI.
adapters/paths/xdg
Package xdg provides deterministic, XDG-compliant paths for application configuration, cache, outbox, and state/log files.
Package xdg provides deterministic, XDG-compliant paths for application configuration, cache, outbox, and state/log files.
adapters/remote/bitwarden
Package bitwarden implements the RemoteVault outbound port using the Bitwarden Go SDK (github.com/bnema/bitwarden-go-sdk/bitwarden).
Package bitwarden implements the RemoteVault outbound port using the Bitwarden Go SDK (github.com/bnema/bitwarden-go-sdk/bitwarden).
app
core/clipboard
Package clipboard defines the Policy type for clipboard auto-clear behaviour.
Package clipboard defines the Policy type for clipboard auto-clear behaviour.
core/logging
Package logging provides shared helpers for safe structured logging.
Package logging provides shared helpers for safe structured logging.
ports/in
Package in defines the inbound ports (driving interfaces) for the application.
Package in defines the inbound ports (driving interfaces) for the application.
ports/out
Package out defines the outbound ports (driven interfaces) for the application.
Package out defines the outbound ports (driven interfaces) for the application.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL