An encrypted personal cloud built on the AT Protocol.
Rust 100.0%
Other 0.1%
76 2 0

Clone this repository

https://tangled.org/sans-self.org/opake.app https://tangled.org/did:plc:wydyrngmxbcsqdvhmd7whmye/opake.app
git@knot.sans-self.org:sans-self.org/opake.app git@knot.sans-self.org:did:plc:wydyrngmxbcsqdvhmd7whmye/opake.app

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

Download tar.gz
README.md

Opake#

/oʊˈpɑːk/ — like "opaque," but Dutch-flavored.

An encrypted personal cloud built on the AT Protocol.

Opake uses your existing PDS as a storage and identity layer. Files are encrypted client-side with AES-256-GCM before upload — the PDS only ever sees ciphertext. Custom lexicons under app.opake.* give structure to documents, encryption metadata, and sharing grants.

Your data is opaque to everyone without the key. That's the point.

Issue Tracker · Architecture · Lexicons

Install#

Requires Rust 1.75+.

cargo install --path crates/opake-cli

This puts opake in your ~/.cargo/bin/.

How It Works#

plaintext file
  → encrypt with random AES-256-GCM key
  → upload ciphertext blob to PDS
  → wrap content key to owner's DID public key
  → store metadata as app.opake.document record

No modifications to the PDS. All crypto happens on your machine.

Build From Source#

Requires Rust 1.75+.

git clone <repo-url>
cd opake.dev
cargo build --release

Produces two binaries: target/release/opake (CLI) and target/release/opake-appview (indexer/API server).

Usage#

# authenticate (resolves PDS automatically, uses OAuth by default)
opake login alice.example.com

# explicit PDS override
opake login alice.example.com --pds https://pds.example.com

# force legacy password-based auth
opake login alice.example.com --legacy

# log in to a second account
opake login bob.other.com

# list accounts and switch default
opake accounts
opake set-default bob.other.com

# upload a file (encrypts + uploads)
opake upload photo.jpg --tags vacation,beach

# upload into a directory
opake upload photo.jpg --dir Photos

# organize files into directories
opake mkdir Photos
opake tree

# list your documents
opake ls
opake ls --long
opake ls --tag vacation

# use a specific account for any command
opake ls --as alice.example.com
opake upload doc.pdf --as did:plc:alice123

# download and decrypt (your own files)
opake download photo.jpg
opake download photo.jpg -o ~/Downloads/copy.jpg

# print a file to stdout (decrypt without saving)
opake cat notes.txt
opake cat Photos/notes.txt

# download a shared file from another user (via grant URI)
opake download --grant at://did:plc:abc/app.opake.grant/tid123

# delete (supports paths and recursive directory deletion)
opake rm photo.jpg
opake rm Photos/photo.jpg
opake rm -r Photos

# move a file to another directory
opake move photo.jpg Photos/

# view or edit document metadata
opake metadata show photo.jpg
opake metadata rename photo.jpg vacation-photo.jpg
opake metadata tag add photo.jpg travel
opake metadata tag remove photo.jpg travel
opake metadata describe photo.jpg "Beach sunset from last summer"
opake metadata describe photo.jpg --clear

# resolve a handle or DID to see their public key
opake resolve alice.example.com

# share a file with another user
opake share photo.jpg alice.example.com

# list grants you've shared
opake shared
opake shared --long

# revoke a share grant
opake revoke at://did:plc:abc/app.opake.grant/tid123

# check incoming grants (via AppView)
opake inbox --appview https://appview.example.com
opake inbox --long

# keyring-based group sharing
opake keyring create family-photos
opake keyring ls
opake keyring add-member family-photos alice.example.com
opake upload photo.jpg --keyring family-photos
opake download --keyring-member at://did:plc:abc/app.opake.document/tid456
opake keyring remove-member family-photos alice.example.com

# transfer encryption identity to a new device
opake pair request              # on the NEW device (polls for approval)
opake pair approve              # on the EXISTING device (select + approve)

# delete all Opake data from PDS (see what would go)
opake purge --dry-run

# delete everything (prompts for confirmation phrase)
opake purge

# skip confirmation and also remove local identity
opake purge --force

# remove an account (defaults to only account if just one)
opake logout
opake logout bob.other.com

Commands accept a filename, a path (Photos/beach.jpg), or an at:// URI. If a filename matches multiple documents, you'll be prompted to use the full URI.

The --as flag works with document commands (upload, download, ls, rm, move, cat, tree, metadata, share, shared, revoke) and accepts a handle or DID.

AppView#

The AppView is a separate binary (opake-appview) that indexes grants and keyrings from the AT Protocol firehose and serves them via a REST API. It enables grant discovery — "what's been shared with me?" — without scanning every PDS in the network.

See docs/appview.md for configuration, authentication, API endpoints, and deployment.

Architecture#

Four crates + a web frontend:

  • opake-core — platform-agnostic library (compiles to WASM). Encryption, records, XRPC client, document operations, Storage trait.
  • opake-cli — CLI binary. FileStorage (filesystem-backed), command dispatch.
  • opake-appview — Axum-based indexer and REST API. Jetstream firehose consumer, SQLite storage, DID-scoped Ed25519 auth.
  • opake-derive — Proc-macro crate. RedactedDebug derive macro for secret-safe Debug output.
  • web/ — React SPA (Vite + TanStack Router + Tailwind/daisyUI). Uses opake-core via WASM. IndexedDbStorage (IndexedDB-backed) implements the same Storage trait as the CLI.

See docs/ARCHITECTURE.md for the encryption model, crate structure, and design decisions. See docs/FLOWS.md for sequence diagrams of every operation.

Roadmap#

  • CLI foundation (auth, upload, download, ls, rm)
  • Client-side AES-256-GCM encryption
  • Asymmetric key wrapping (x25519-hkdf-a256kw)
  • Automatic token refresh
  • Multi-account support (--as flag, logout, set-default, accounts)
  • Public key auto-publish on login (app.opake.publicKey record)
  • DID resolution and public key extraction
  • Direct file sharing between DIDs
  • Cross-PDS shared file download (via --grant flag)
  • Grant listing (shared command)
  • AppView indexer (grants + keyrings from firehose)
  • AppView REST API with DID-scoped Ed25519 auth
  • Folder hierarchy (mkdir, tree, path-aware rm/mv/cat/upload)
  • Grant discovery (inbox command — queries AppView)
  • Keyring-based group sharing
  • Web UI — cabinet file browser (in progress, auth stubbed)
  • AT Protocol OAuth (DPoP) for CLI and browser authentication
  • Device-to-device identity pairing via PDS relay
  • Seed phrase key derivation for multi-device

Development#

cargo test           # run all Rust tests
cargo clippy         # lint
cargo fmt            # format

# web frontend
cd web
bun install          # install deps
bun run wasm:build   # build opake-core WASM module
bun run dev          # start Vite dev server
bun run test         # run Vitest suite

CI runs on Tangled via .tangled/workflows/test.yml.

See CONTRIBUTING.md for contribution guidelines.

Lexicons#

Custom AT Protocol schemas live in lexicons/. See lexicons/README.md for the full schema documentation and lexicons/EXAMPLES.md for annotated example records.

License#

AGPL-3.0