vault1984/CLAUDE.md

5.3 KiB

vault1984

Zero-knowledge password manager. Infrastructure is the moat. FIPS 140-3, BoringCrypto, built for trust.

Ground Rules

Johan is the architect. You are the collaborator. Same principles as inou:

  1. Discussion first. Default is conversation. No code until asked ("do it", "implement it").
  2. Minimal diffs. Change only what's requested. No drive-by cleanups.
  3. Less code, better architecture. If something needs a lot of code, the design is probably wrong.
  4. Ask, don't assume. Ambiguous request → ask. Don't pick an interpretation and run.
  5. No unsolicited files. No new docs, tests, or helpers unless explicitly asked.
  6. Mention concerns once, then execute. Johan has reasons. Respect them.

Repository Structure

docs/              — all design documentation (shared across OSS + commercial)
oss/               — open source, published to GitHub
  app/             — vault1984 server (Go, FIPS 140-3)
  cli/             — v1984 CLI client
  crypto/          — crypto primitives (BoringCrypto)
  Makefile         — build system
commercial/        — proprietary, Zürich only, never on GitHub
  account/         — account system (billing, vault credits)
  mgmt/            — POP management sidecar
  website/         — vault1984.com (marketing + account management)
  marketing/       — marketing assets
  tailscale/       — ACL config

Build: Always use GOEXPERIMENT=boringcrypto (set in Makefile). Required for FIPS 140-3.

cd oss/
make deploy       # build + test + restart everything
make deploy-app   # app only
make deploy-web   # website only
make status       # check what's running

Environments

Environment Host Purpose
HQ / NOC noc.vault1984.com (185.218.204.47) Hans runs this — Hans' domain
Forge (local) 192.168.1.16 Development

SSH: root@185.218.204.47 (HQ/Hans), ssh johan@192.168.1.16 (forge)

Security Non-Negotiables

  • FIPS 140-3 via GOEXPERIMENT=boringcrypto — never build without it
  • Zero-knowledge — server never sees plaintext credentials
  • WebAuthn PRF — hardware key derives master secret; L2 (16 bytes) for agents, L3 (32 bytes) for humans only
  • No logging of credential content, ever
  • Registration = unlocked. Passkey registration MUST derive and store the master key. There is no distinction between "registered" and "logged in" — both mean the user authenticated with hardware. The vault is immediately usable after registration, no second tap.
  • No "simplest fix" shortcuts. This is a world-class security product. Every flow must be correct by design, not patched after the fact.

Current Status (Mar 2026)

  • Binary builds: amd64 + arm64, telemetry flag support
  • POP nodes: HQ (Zürich), Virginia (us-east-1), Singapore (ap-southeast-1)
  • Telemetry: binary supports --telemetry-* flags; HQ dashboard /telemetry handler pending
  • WebAuthn L2: in progress
  • Permanent VAULT_KEY handling: pending

Data Access Architecture

All DB operations go through named functions in oss/app/lib/dbcore.go. No direct SQL outside dbcore.go.

Choke points:

  • EntryCreate/Get/Update/Delete/List/Search — all credential entry operations
  • SessionCreate/Get/Delete — session management
  • AuditLog — every security event goes here, no exceptions

FORBIDDEN outside dbcore.go:

  • db.QueryRow(), db.Exec(), db.Query() — direct SQL is a violation (one exception: telemetry.go — isolated, non-security code)
  • New wrapper functions that bypass the named choke points
  • Any modification to dbcore.go without Johan's explicit approval

Encryption: All credential fields are encrypted with the vault key via Pack/Unpack in dbcore.go. This is the ONLY encryption path. Never encrypt/decrypt fields outside of it.

Session & Key Architecture (DO NOT VIOLATE)

One session key, one salt, one source of truth.

  • Session key: v1984_master in sessionStorage — 32-byte master secret, base64-encoded
  • HKDF salt: vault1984-master-v2 — used everywhere, no alternatives
  • L1 = bytes[0..8], L2 = bytes[0..16], L3 = bytes[0..32] — all derived from v1984_master
  • webauthn.js is the ONLY module that derives and stores the master key
  • topbar.js is the ONLY module that clears it (on lock/logout/401)
  • crypto.js is the ONLY module that encrypts/decrypts fields — shared between CLI and browser

Rules:

  • NEVER create a second session key (no v1984_l2key, no v1984_foo)
  • NEVER derive keys with a different salt
  • NEVER derive or store keys outside webauthn.js
  • NEVER encrypt/decrypt outside crypto.js
  • Registration = unlocked. One tap stores the master key. No second tap.
  • isUnlocked() checks sessionStorage — if false, user is logged out

Shared JS (crypto/ directory):

  • oss/crypto/crypto.js and oss/crypto/totp.js are the source of truth
  • Makefile copies them to oss/app/cmd/vault1984/web/ before building
  • NEVER edit the copies in web/ directly — edit oss/crypto/ and rebuild
  • CLI (QuickJS) and browser (Web Crypto) use the same code

Key Files

  • docs/L2_AGENT_ENCRYPTION.md — WebAuthn L2 encryption spec (SUPERSEDED by truncation model)
  • docs/ — architecture docs
  • oss/app/cmd/vault1984 — main entry point
  • oss/crypto/ — shared JS crypto (source of truth for CLI + browser)
  • oss/cli/ — vault1984-cli (C + QuickJS + BearSSL)