Skip to content

Repository files navigation

Keydrop

Keydrop delivers a small encrypted file through a short-lived, capability URL. The server stores only authenticated ciphertext; the password is created or supplied locally and never sent to the service. Decryption happens in Brave or Fennec with the existing offline-tested browser bundle.

file or stdin -> local Argon2id + XChaCha20 encryption -> private R2
                                                        |
Telegram or console <- URL with 256-bit fragment <- Worker + Durable Object
                                                        |
password file (0600, separate channel) -> browser decrypt -> repeatable until TTL

Automation may supply an already-known password through a dedicated inherited file descriptor:

keydrop send profile.toml \
  --endpoint https://drop.example/ \
  --token-file /run/secrets/keydrop-upload-token \
  --password-fd 3 3<password.pipe

--password-fd and --password-out are mutually exclusive. The file-descriptor mode does not create a password file; callers must use a private pipe and must not put the password in argv or environment variables.

Optional download filename

The CLI still prints exactly https://drop.example/#TOKEN. A trusted integration may append one client-side filename to the fragment before delivering the URL:

https://drop.example/#TOKEN/device-target-v0.7.1.toml

The browser decodes the suffix once, requires [A-Za-z0-9][A-Za-z0-9._-]{0,127}, fetches the same ciphertext, and presents it to the decryptor as device-target-v0.7.1.toml.enc. The decrypted download is therefore saved as device-target-v0.7.1.toml. The suffix stays in the URL fragment and is never sent to the Worker. Invalid names or extra fragment segments are rejected before a drop request. Existing #TOKEN links remain compatible and use delivery as the filename.

The repository contains:

  • keydrop: standalone Node.js 22 CLI; stdout is only the delivery URL;
  • worker/: Cloudflare Worker, private R2 binding, and Durable Object TTL state;
  • index.html, autoselect.js, decrypt.bundle.js: same-origin browser receiver;
  • scripts/check-keydrop-build.sh: pinned, integrity-checked, ephemeral CLI rebuild;
  • tests/smoke.sh: crypto round-trip, secret-lifecycle, race, API, and browser-flow tests.

Run the local suite from the repository root:

bash tests/smoke.sh

The suite builds cli/keydrop.mjs in a temporary directory with exact versions of esbuild-wasm and libsodium, verifies their registry SHA-512 values, and compares the result byte-for-byte with tracked keydrop. It leaves no dependency manifest or node_modules in the repository.

No Cloudflare resource is created by the tests. Production bootstrap, deployment, manual use, automation, rollback, and cleanup are documented in docs/PRODUCTION.md.

Security boundary

The URL is a bearer capability and must be treated as secret. Send the URL and password through different channels. The optional filename is descriptive metadata, not an authorization control. Any browser holding the token may fetch the authenticated ciphertext repeatedly until its fixed TTL. Browser download or decryption events never delete the server copy. A legacy acknowledgement is rejected with 409; the Worker alarm deletes the object after expiry. The upload-authenticated revoke route exists only for trusted operational cleanup and live canaries.

Limits: ciphertext is at most 16 MiB, TTL is 5 minutes to 12 hours, and the R2 lifecycle rule is a one-day orphan backstop. The CLI does not delete its input. Filesystems and SSDs do not promise secure erasure.

Third-party notice

The generated keydrop and decrypt.bundle.js include libsodium-wrappers-sumo / libsodium-sumo 0.8.4 under the ISC license:

Copyright (c) 2015-2026
Ahmad Ben Mrad <batikhsouri at gmail dot org>
Frank Denis <j at pureftpd dot org>
Ryan Lester <ryan at cyph dot com>

Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

About

Local-only browser decryption compatibility test with dummy data

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages