Encrypted, ephemeral, private memos on atproto
TypeScript 100.0%
34 1 0

Clone this repository

https://tangled.org/graham.systems/cistern
git@tangled.org:graham.systems/cistern

For self-hosted knots, clone URLs may differ based on your setup.

README.md

Cistern#

Cistern is a private, end-to-end encrypted quick-capture system built on AT Protocol. Items are encrypted using post-quantum cryptography and stored temporarily in your Personal Data Server (PDS), then automatically retrieved and deleted after consumption.

The system bridges the gap between where ideas are captured and where they are stored long-term. Create an encrypted item on your phone, and it automatically appears in your desktop application, decrypted and ready to use.

Architecture#

Cistern is a Deno monorepo consisting of five packages:

@cistern/crypto#

Core cryptographic operations using post-quantum algorithms. Implements X-Wing key encapsulation with XChaCha20-Poly1305 authenticated encryption and SHA3-512 integrity verification. Handles keypair generation, encryption, and decryption.

@cistern/lexicon#

AT Protocol schema definitions for Cistern record types. Defines app.cistern.lexicon.pubkey (public key records) and app.cistern.lexicon.item (encrypted item records). Includes code generation from JSON schemas.

@cistern/shared#

Common utilities and authentication logic. Handles DID resolution via Slingshot service and creates authenticated RPC clients using app passwords.

@cistern/producer#

Creates and encrypts items for storage. Manages public key selection, encrypts plaintext content, and uploads encrypted items to the PDS as AT Protocol records.

@cistern/consumer#

Retrieves, decrypts, and deletes items. Generates keypairs, manages private keys locally, retrieves items via polling or real-time streaming (Jetstream), and handles item deletion after consumption.

Security Model#

Private keys never leave the consumer device. Public keys are stored in the PDS as records, while private keys remain off-protocol. Only the holder of the matching private key can decrypt items encrypted with the corresponding public key.

Testing#

Run all unit tests:

deno test --allow-env

Run end-to-end tests (requires AT Protocol credentials):

CISTERN_HANDLE="your.bsky.social" \
CISTERN_APP_PASSWORD="xxxx-xxxx-xxxx-xxxx" \
deno test --allow-env --allow-net e2e.test.ts