ReactorcoremeltdownandClaude Opus 5.5 318bd68908 Collect Android browser sign-ins after the app was stopped
The Android app kept a pending browser sign-in in a thread inside the
login screen. Android often kills the process while the browser is in
front, so the approval reached the server but nothing collected it, and
the app came back signed out with nothing saved.

The pending device code is now kept in Prefs and collected whenever the
login screen resumes. The app passes return_url=keeporg://device-approved
when it starts the sign-in, and the server's approval page, after a
password or single sign-on, links back to it. Only the keeporg: scheme is
accepted. Against a server older than 0.9, which rejects the field, the
app retries without it.

Verified on an Android 15 emulator: approval collected after the process
was killed, and the fallback against the 0.8 server.

Server 0.9.0, Android 0.3.0 (versionCode 3).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:16:23 +01:00

KeepOrg

A synchronization adapter for KeePass. Your databases stay ordinary .kdbx files that KeePassXC, KeePass2 or KeePassDX opens directly; a server keeps them in step between everyone who has access.

When two people save at once, the server can merge both edits: it opens the two copies in memory, folds them together by KeePass's own rules and stores the result. Nothing is lost, and no one has to reconcile two files by hand.

Merging means decrypting, so a merge vault's password is kept on the server, encrypted under a master key held outside the data directory. That makes the server part of your trust boundary. Vaults on any other conflict strategy keep their key off the server entirely, exactly as before.

  • Server (keeporgd, Linux): hosts many KDBX databases, controls access with a tree of user groups, accepts registrations by invite link or OIDC, merges concurrent edits, and pushes updates to connected clients. Its web page at /web is for creating a vault and setting its password.
  • Desktop client (keeporg, Linux, macOS, Windows, BSD): a system tray application that mirrors every assigned database into one directory as a real file, pushes each save and applies what others push. The same binary is the command line for administration and for headless machines.
  • Android client: the same, published to every file picker as a storage provider.

No FUSE, and the server has no third-party dependencies and no cgo. The KDBX 4 codec, including ChaCha20, BLAKE2b and Argon2, is part of the repository and is tested against both the relevant RFCs and a real KeePassXC. The desktop client's one dependency is fyne.io/systray, for the tray icon.

Quick start

make check                 # gofmt, vet, tests
make all                   # keeporgd and keeporg for this host

# a server for trying it out, on 127.0.0.1:8765
KEEPORG_ADMIN_PASSWORD=dev-password-1 make run-server

# in another shell
build/linux-arm64/keeporg login -server http://127.0.0.1:8765 -user admin
build/linux-arm64/keeporg groups
build/linux-arm64/keeporg vault -create "Team Vault" -group <group-id>
build/linux-arm64/keeporg          # the tray; `keeporg run` without a desktop

Team Vault.kdbx appears in ~/KeepOrg; open it in KeePassXC with the vault password you just set. Every save is pushed, and a save that races with a colleague's is merged rather than refused.

The tray

Started without a command — from the applications menu, the DMG's KeepOrg.app, or keeporg-tray.exe on Windows — the client puts a padlock in the system tray:

Item What it does
status line signed-in account and whether everything is up to date, or what needs attention
Open Mirror Folder the directory holding the .kdbx files
Databases ▶ each database with its state; choosing one opens it in your KeePass application
Sync Now reconcile immediately instead of at the next rescan
Sign In… / Sign Out sign in by approving a code in the browser (password, second factor or SSO); sign out revokes the session and leaves the files
Open Web Interface /web on the server, for creating vaults and managing access
Open Config the settings file; a saved edit applies at once
Open Log the agent's log
Start at Login LaunchAgent on macOS, XDG autostart on Linux and BSD, the Run key on Windows
About, Quit

Conflicts, merges and failures raise a desktop notification.

Configuration

config.json in the user configuration directory (~/.config/keeporg, ~/Library/Application Support/keeporg, %AppData%\keeporg) holds every client setting. The first start writes it in full, and the tray reloads it when it is saved.

Key Default Meaning
server_url the server's base URL, as a browser sees it
username, token written by signing in
device_label host name this device in the server's session list
mirror_dir ~/KeepOrg where the .kdbx files are kept; ~ is expanded
poll_seconds 2 how often local saves are looked for
request_timeout_seconds 60 the limit on one API request (the event stream is exempt)
ca_file a PEM bundle trusted besides the system roots, for a private CA
log_file the log; empty means keeporg.log beside the config for the tray, standard error for keeporg run
notifications true desktop notifications from the tray

Or open http://127.0.0.1:8765/web and create the vault from the browser.

Packaging

make deb        # Debian packages for the client and the server
make docker     # server container image, scratch-based, about 9 MB
make dmg        # macOS disk image with an /Applications symlink (on macOS)
make windows    # Windows zip: keeporg-tray.exe, keeporg.exe and a Task Scheduler job
make android    # unsigned release APK (needs the Android SDK)
make help       # every target

Running the server in a container:

head -c 32 /dev/urandom | base64 > master.key
podman secret create keeporg_master_key master.key
podman run -d -p 8765:8765 \
  --secret keeporg_master_key \
  -e KEEPORG_MASTER_KEY_FILE=/run/secrets/keeporg_master_key \
  -e KEEPORG_ADMIN_PASSWORD=change-me \
  -v keeporg-data:/var/lib/keeporg \
  keeporgd:latest -addr :8765 -data /var/lib/keeporg -url https://keeporg.example.com

Keep that master key: it unwraps the vault keys, and without it the server can no longer merge. KEEPORG_MASTER_KEY takes the base64 key directly if your secret store injects variables instead of files. See packaging/docker/compose.yaml.

Server environment variables:

Variable Meaning
KEEPORG_MASTER_KEY the master key, base64; overrides the other two sources
KEEPORG_MASTER_KEY_FILE path to a file holding the master key (base64 or 32 raw bytes); never created, and if it is missing the server runs but cannot create or merge vaults
KEEPORG_EXTERNAL_URL the public base URL (external_url); -url overrides it
KEEPORG_ADMIN_PASSWORD the first admin password, read only on an empty server and by -reset-admin

Everything else is configured in server.json or by flag. The details, including the standard proxy and CA variables, are in docs/HANDOVER.md.

Documentation

S
Description
No description provided
Readme
902 KiB
Languages
Go 87.4%
Kotlin 8.3%
Makefile 1.8%
Shell 1.3%
Go Template 0.6%
Other 0.6%