A zero-knowledge pastebin where the server never sees what you write. Built on Next.js 16 and evolved from PrivateBin's battle-tested security model, extended with asymmetric RSA key wrapping, Shamir's Secret Sharing for multi-party quorum control, and end-to-end encrypted real-time collaboration. (obsidian blocks are maaad tough to break in minecraft π)
- π Modernised Legacy Features β next-gen tech stack (Next.js 16, React 19, Tailwind v4, Web Crypto API) for legacy features
- π» Developer CLI Tool (
obsidian) β terminal client for encrypted pastes, RSA key management, whole-repo sharing, and Shamir quorum operations - ποΈ Zero-Knowledge Trust Visualizer β animated encryption explainer UI
- π₯ N-View Self-Destruct β atomic burn-after-reading with configurable view limits
- β³ Time-Locked Notes β Time Capsule mode for delayed message access
- π Asymmetric RSA-OAEP Key Wrapping β public-key mode for 1-to-1 recipient delivery
- π Shamir's Secret Sharing β k-of-n key splitting for multi-party threshold quorum
- π΄ Real-Time E2EE Collaboration β Pusher + BroadcastChannel for instant encrypted updates
- β¨οΈ Command Palette β Cmd+K shortcuts for power-user workflows
- π Paste Starter Templates β pre-built content templates
- ποΈ Encrypted Paste Vault β searchable collection of saved pastes
- π§Ύ Cryptographic Destruction Receipts β JWT-signed proof of paste deletion
- β Comprehensive Test Suite β 85/85 unit tests + 7/7 E2E tests passing
| Layer | Tech |
|---|---|
| π Framework | Next.js 16, React 19, Tailwind v4 |
| π Crypto | Web Crypto API β AES-256-GCM, PBKDF2, RSA-OAEP, custom GF(2βΈ) Shamir SSS |
| π» CLI | Node.js (ESM), Commander, Chalk, Ora, Tar, TSX |
| ποΈ Storage | PostgreSQL (Neon) via Prisma |
| β‘ Real-time | Pusher WebSockets + BroadcastChannel |
| π¦ Rate limiting | Upstash Redis, HMAC-SHA256 IP hashing |
cd obsidian
npm install.env.local:
DATABASE_URL="postgresql://USER:PASSWORD@HOST/DATABASE?sslmode=require"
IP_HMAC_SECRET=<32_byte_secret> # openssl rand -hex 32
# optional β enables remote real-time collaboration
PUSHER_APP_ID=
PUSHER_KEY=
PUSHER_SECRET=
PUSHER_CLUSTER=
NEXT_PUBLIC_PUSHER_KEY=
NEXT_PUBLIC_PUSHER_CLUSTER=npm run db:generate && npm run db:push
npm run dev # http://localhost:3000| Check | Command |
|---|---|
| Lint | npm run lint |
| Unit tests | npm test |
| Production build | npm run build && npm start |
Obsidian includes a full-featured terminal CLI for scripting, CI/CD pipelines, and terminal-first workflows. Encrypt, decrypt, manage RSA identity keys, split secrets with Shamir quorum, or share entire codebases directly from your shell.
cd obsidian/cli
npm install
# Link globally to use the `obsidian` command anywhere
npm link
# Or run directly via tsx:
npm run dev -- <command>Configure target server (defaults to http://localhost:3000):
obsidian config set-url https://your-obsidian-instance.com| Command | Description | Example |
|---|---|---|
obsidian send |
Encrypt & upload text or a file | obsidian send "my secret API key" --burn |
obsidian read |
Decrypt & read a paste from a URL | obsidian read "https://...#key" |
obsidian key |
Manage RSA-2048 identity keypair | obsidian key generate && obsidian key show --public |
obsidian repo send |
Tar, encrypt & upload entire folder | obsidian repo send ./my-project --exclude dist |
obsidian repo get |
Download, decrypt & extract repo | obsidian repo get "<url>#key" --output ./restored |
obsidian shamir split |
Offline mathematical secret splitting | obsidian shamir split "root-token" -n 5 -k 3 |
obsidian shamir combine |
Offline secret reconstruction | obsidian shamir combine "<shard1>" "<shard2>" |
obsidian config |
Inspect or update CLI settings | obsidian config set-url https://app.example.com |
# Encrypt text with automatic self-destruction upon reading (default)
obsidian send "sk_live_998822334455"
# Encrypt a file (.env, config, certificate) without burning
obsidian send --file .env.production --no-burn
# Pipe raw decrypted content in CI/CD scripts
obsidian read "https://obsidian.app/pasteId#key" --raw > .env# 1. Recipient generates and shares their public key
obsidian key generate
obsidian key show --public
# 2. Sender encrypts with recipient's public key (link is useless without recipient's private key)
obsidian send "confidential deployment keys" --recipient "<RECIPIENT_PUBKEY_BASE64>"
# 3. Recipient decrypts automatically using their local keystore (~/.obsidian/identity.json)
obsidian read "https://obsidian.app/pasteId#asym"# Create a 2-of-3 threshold paste (outputs 3 individual shard links)
obsidian send "Production Root Access" --shares 3 --threshold 2
# Combine any 2 shard links to reconstruct the key and decrypt
obsidian read "<shard1_url>" --shards "<shard2_url>"# Compresses (tar.gz), encrypts, and uploads directory (supports --recipient for 1-to-1 secure delivery)
obsidian repo send ./backend-service --exclude node_modules dist .git
# Download, decrypt, and unpack directly to an output directory
obsidian repo get "https://obsidian.app/pasteId#key" --output ./restored-backendKey in URL fragment: encrypt locally, share link with embedded key β one-click decrypt for recipient, server learns nothing.
sequenceDiagram
autonumber
actor Creator
participant Worker as Web Worker
participant API
actor Recipient
Creator->>Worker: Plaintext + options
Worker->>Worker: Compress β derive key (PBKDF2) β AES-256-GCM encrypt
Worker-->>Creator: ciphertext, adata, key
Creator->>API: POST /api/v1/paste
API-->>Creator: pasteId β URL#keyBase58
Creator->>Recipient: Share URL
Recipient->>API: GET /api/v1/paste/:id
Recipient->>Recipient: Decrypt using #fragment key
Recipient's public key wraps the AES key: link is useless without their private key β safe for untrusted channels (Slack, email, logs).
sequenceDiagram
autonumber
actor Recipient
actor Creator
participant API
participant IDB as IndexedDB
Recipient->>IDB: Generate & store RSA-2048 keypair
Recipient->>Creator: Public key (SPKI base64)
Creator->>Creator: Encrypt with random AES key
Creator->>Creator: Wrap AES key with recipient's public key
Creator->>API: POST { ct, adata[4] = wrapped key }
API-->>Creator: pasteId β URL#asym
Recipient->>API: GET /api/v1/paste/:id
Recipient->>IDB: Load private key
Recipient->>Recipient: Unwrap AES key β decrypt
Split the AES key into N shards, require K to unlock: multi-party threshold control via Lagrange interpolation over GF(2βΈ).
sequenceDiagram
autonumber
actor Creator
participant API
actor Holder1 as Keyholder 1
actor Holder2 as Keyholder 2
Creator->>Creator: Encrypt with AES key
Creator->>Creator: Split key β 3 shards, threshold 2
Creator->>API: POST { ct, adata, shardTotal: 3 }
API-->>Creator: pasteId
Creator->>Holder1: URL#shard-2-1-3-...
Creator->>Holder2: URL#shard-2-2-3-...
Holder1->>API: GET /api/v1/paste/:id
Holder2->>Holder1: Shard #2
Holder1->>Holder1: Combine shards β Lagrange interpolation β key
Holder1->>Holder1: Decrypt
Real-time collaborative editing: encrypted deltas streamed via Pusher as a blind relayβserver never holds keys or plaintext.
sequenceDiagram
autonumber
actor PeerA
participant Pusher as Pusher (blind relay)
actor PeerB
PeerA->>Pusher: Subscribe presence-collab-:id
PeerB->>Pusher: Subscribe presence-collab-:id
PeerA->>PeerA: Encrypt keystroke delta
PeerA->>Pusher: trigger('client-delta', ct)
Pusher-->>PeerB: Relay ct only
PeerB->>PeerB: Decrypt β render live update
obsidian/
βββ app/ API routes Β· pages Β· vault Β· interactive docs
β βββ api/v1/paste/ create Β· read Β· delete Β· comment
β βββ api/v1/collab/ presence-channel auth
β βββ api/docs/ interactive API & CLI portal
β βββ pad/ paste editor UI
β βββ vault/ user vault
βββ cli/ Developer CLI tool (`obsidian-cli`)
β βββ bin/ CLI executable wrapper (`obsidian.js`)
β βββ src/commands/ send Β· read Β· key Β· repo Β· shamir Β· config
β βββ src/lib/ crypto Β· shamir Β· keystore Β· API clients
β βββ src/utils/ archive tar/gzip Β· display formatters
βββ components/ UI components
β βββ editor/ paste creation UI
β βββ viewer/ decryption Β· quorum panel Β· comments
β βββ crypto/ crypto helpers
β βββ collab/ real-time collaboration
β βββ sharing/ share UI
β βββ qr/ QR code generator
β βββ ui/ generic UI primitives
β βββ header/ Β· layout/ layout components & CLI modal
βββ lib/ core libraries
β βββ crypto/ cipher Β· kdf Β· asymmetric Β· shamir Β· compress
β βββ api/ API clients
β βββ db database helpers
βββ workers/ off-main-thread PBKDF2 worker
βββ hooks/ custom React hooks
β βββ usePasteEncryption Β· usePasteDecryption Β· useCollab
βββ prisma/ Prisma schema β Paste Β· Comment Β· AccessLog
βββ tests/ unit Β· e2e tests
βββ public/ static assets