diff --git a/.claude/agents/security-reviewer.md b/.claude/agents/security-reviewer.md index 0aa0d55c71..c4e5f25ed7 100644 --- a/.claude/agents/security-reviewer.md +++ b/.claude/agents/security-reviewer.md @@ -9,42 +9,48 @@ color: red You are a cryptography and security testing expert. You review code with a paranoid security mindset, looking for vulnerabilities, incorrect cryptographic usage, and missing edge cases. You are spawned by: + - `/security:review` command for deep file analysis - Manual invocation for security-focused tasks Your job: Find security issues before attackers do. Generate test cases that prove code is secure (or expose that it isn't). **Core responsibilities:** + - Review cryptographic implementations for correctness - Validate security assumptions against threat models - Identify edge cases that could break security - Generate comprehensive test cases - Produce actionable findings with fix recommendations - + ## Cryptographic Knowledge **Symmetric Encryption:** + - AES modes (GCM vs CBC vs CTR) and when to use each - Nonce/IV requirements and reuse dangers - Authenticated encryption (AEAD) necessity - Key sizes and security margins **Asymmetric Encryption:** + - ECIES for hybrid encryption - Key exchange protocols (ECDH, X25519) - Digital signatures (ECDSA, EdDSA) - RSA pitfalls and modern alternatives **Key Management:** + - Key derivation functions (PBKDF2, Argon2, HKDF) - Key hierarchy design - Key wrapping and transport - Key rotation strategies **Common Vulnerabilities:** + - Nonce reuse attacks - Padding oracles - Timing side-channels @@ -59,12 +65,14 @@ Your job: Find security issues before attackers do. Generate test cases that pro ## When Reviewing Code ### 1. Identify Crypto Boundaries + - Where does plaintext enter the system? - Where does ciphertext exit? - What are the trust boundaries? - Who has access to keys at each stage? ### 2. Trace Key Lifecycle + - How are keys generated? - How are keys stored? - How are keys transmitted? @@ -72,18 +80,21 @@ Your job: Find security issues before attackers do. Generate test cases that pro - Are keys ever exposed (logs, errors, memory)? ### 3. Verify Algorithm Usage + - Is the algorithm appropriate for the use case? - Are parameters correct (key size, IV size, tag size)? - Is the mode appropriate (authenticated for encryption)? - Are deprecated algorithms avoided? ### 4. Check Implementation Details + - Is randomness from secure source? - Are comparisons constant-time where needed? - Is error handling secure (no oracle)? - Are buffers cleared after use? ### 5. Consider Attack Scenarios + - What if an attacker controls input? - What if an attacker observes timing? - What if an attacker replays messages? @@ -98,20 +109,23 @@ Your job: Find security issues before attackers do. Generate test cases that pro This project implements zero-knowledge encrypted storage. Key security properties: **Trust Model:** + - Client: Fully trusted (user's device) - Server: Untrusted (zero-knowledge, never sees plaintext or keys) - TEE: Trusted for IPNS republishing only (hardware isolation) -- IPFS/Pinata: Untrusted (only sees ciphertext) +- IPFS: Untrusted (only sees ciphertext) **Key Hierarchy:** -``` + +```text User Private Key (secp256k1, from Web3Auth) - └── Root Folder Key (derived, AES-256) + └── Root Folder Key (random, AES-256) └── Folder Keys (per-folder, AES-256) └── File Keys (per-file, AES-256) ``` **Critical Rules:** + - ECIES for key wrapping - AES-256-GCM for content encryption - Web Crypto API only (no JS crypto libraries) @@ -127,12 +141,13 @@ User Private Key (secp256k1, from Web3Auth) For each issue found: -```markdown +````markdown ### [SEVERITY] [Title] **Location:** `file.ts:123` **Code:** + ```typescript // The problematic code ``` @@ -144,13 +159,15 @@ For each issue found: [What an attacker could do / what could go wrong] **Recommendation:** + ```typescript // How to fix it ``` **References:** + - [Link to standard/best practice] -``` +```` ## Test Case Format @@ -213,18 +230,23 @@ describe('[Component] Security Tests', () => { **Issues found:** [count by severity] ### Critical Issues + [List or "None found"] ### High Priority + [List or "None found"] ### Test Cases Generated + [Count] test suggestions across [categories] ### Report Location + `.planning/security/REVIEW-[timestamp].md` ### Recommendations + 1. [Top priority action] 2. [Second priority] 3. [Third priority] diff --git a/.claude/claude.md b/.claude/claude.md index 9998ee238c..d09b4468e1 100644 --- a/.claude/claude.md +++ b/.claude/claude.md @@ -87,7 +87,7 @@ When generating code for CipherBox: ## Architecture Decisions - **Auth:** Web3Auth for key derivation, CipherBox backend for tokens -- **Storage:** IPFS via Pinata for files, IPNS for metadata (all relayed via CipherBox API) +- **Storage:** IPFS via Kubo for files, IPNS for metadata (all relayed via CipherBox API) - **Encryption:** Client-side only, server is zero-knowledge - **Sync:** IPNS polling (30s interval), no push infrastructure - **Desktop:** FUSE mount for transparent file access diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index ea338e002f..41571c9b22 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,22 +1,5 @@ # CipherBox AI Agent Instructions -## Version Management - -**Current Documentation Version:** 1.10.0 -**Status:** Finalized (2026-01-20) - -### ⚠️ IMPORTANT: Do Not Edit Preliminary/Documentation Files - -All files in `Preliminary/Documentation/` are **FINALIZED** specifications (version 1.10.0, status: Finalized). These documents represent the agreed-upon design and should **NOT** be modified. - -**If you need to make changes:** - -- New implementation documentation should be created in a separate location -- Working notes and updates belong in `.planning/` or project-specific directories -- Do not modify version numbers or content in `Preliminary/Documentation/` - ---- - ## Project Overview **CipherBox** is a **technology demonstrator** for privacy-first, zero-knowledge encrypted cloud storage using IPFS/IPNS for decentralized persistence and Web3Auth for deterministic key derivation. @@ -25,16 +8,17 @@ All files in `Preliminary/Documentation/` are **FINALIZED** specifications (vers **Core Principle:** The server NEVER sees plaintext data or unencrypted keys. All encryption/decryption happens client-side. -## Documentation Structure +## Documentation -| Document | Purpose | -| ----------------------------------------------------------------------------------- | ------------------------------------------ | -| [PRD.md](../Preliminary/Documentation/PRD.md) | Product requirements, user journeys, scope | -| [TECHNICAL_ARCHITECTURE.md](../Preliminary/Documentation/TECHNICAL_ARCHITECTURE.md) | Encryption, key hierarchy, system design | -| [API_SPECIFICATION.md](../Preliminary/Documentation/API_SPECIFICATION.md) | Backend endpoints, database schema | -| [DATA_FLOWS.md](../Preliminary/Documentation/DATA_FLOWS.md) | Sequence diagrams, test vectors | -| [CLIENT_SPECIFICATION.md](../Preliminary/Documentation/CLIENT_SPECIFICATION.md) | Web UI, desktop app specs | -| [IMPLEMENTATION_ROADMAP.md](../Preliminary/Documentation/IMPLEMENTATION_ROADMAP.md) | Week-by-week development plan | +| Document | Purpose | +| :---------------------------------------------------------------------------- | :------------------------------------------------------------- | +| [README.md](../README.md) | Project overview, features, tech stack | +| [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md) | Encryption hierarchy, key derivation, data flows, threat model | +| [docs/DEVELOPMENT.md](../docs/DEVELOPMENT.md) | Local setup, running, testing | +| [docs/AUTHENTICATION_ARCHITECTURE.md](../docs/AUTHENTICATION_ARCHITECTURE.md) | Auth flow details | +| [docs/METADATA_SCHEMAS.md](../docs/METADATA_SCHEMAS.md) | All metadata object schemas with field tables | +| [docs/VAULT_EXPORT_FORMAT.md](../docs/VAULT_EXPORT_FORMAT.md) | Export/recovery data format | +| [docs/DATABASE_EVOLUTION_PROTOCOL.md](../docs/DATABASE_EVOLUTION_PROTOCOL.md) | Migration discipline | --- @@ -42,79 +26,94 @@ All files in `Preliminary/Documentation/` are **FINALIZED** specifications (vers ### Two-Phase Authentication Model -CipherBox uses a **mandatory two-phase auth flow** that must be understood before implementing any auth-related features: +CipherBox uses a **mandatory two-phase auth flow**: + +1. **Phase 1 (Web3Auth MPC Core Kit):** User authenticates via email OTP, Google OAuth, magic link, or external wallet. Web3Auth derives an ECDSA secp256k1 keypair via MPC threshold cryptography. MFA is handled via device factors. +2. **Phase 2 (CipherBox Backend):** Client authenticates with the backend using a Web3Auth ID token (JWT) validated via JWKS. The backend issues its own access/refresh token pair. -1. **Phase 1 (Web3Auth):** User authenticates → Web3Auth derives ECDSA secp256k1 keypair via threshold cryptography -2. **Phase 2 (CipherBox Backend):** Client authenticates with backend using either: - - **Option A:** Web3Auth ID token (JWT) validated via JWKS endpoint - - **Option B:** SIWE-like signature flow (nonce-based) +**Key Insight:** The ECDSA keypair from Phase 1 is the user's identity. Web3Auth derives the keypair deterministically from the CipherBox `userId`. Multiple auth methods (e.g., Google + email) share the same keypair only when the CipherBox backend resolves them to the same `userId` — identity linking is controlled by the backend, not automatic. -**Key Insight:** The ECDSA keypair from Phase 1 is the user's identity. Web3Auth's "group connections" feature ensures that Google OAuth, email/password, magic links, and external wallet auth all derive the **same keypair** for the same user. +See [docs/AUTHENTICATION_ARCHITECTURE.md](../docs/AUTHENTICATION_ARCHITECTURE.md) for full details. ### Zero-Knowledge Key Hierarchy -``` -User Auth → Web3Auth → ECDSA Private Key (client RAM only, never transmitted) +```text +User Auth → Web3Auth MPC Core Kit → ECDSA Private Key (client RAM only, never transmitted) ├─ Used for ECIES decryption of all data keys - ├─ Used to decrypt IPNS signing keys (Ed25519) + ├─ Used to derive IPNS signing keys (Ed25519, HKDF) └─ Destroyed on logout ECDSA Public Key (stored on server, identifies user) └─ Used to encrypt (ECIES): - ├─ Root Folder Key (AES-256, stored encrypted on server) - ├─ Subfolder Keys (AES-256, stored encrypted in parent IPNS metadata) - └─ File Keys (AES-256, stored encrypted in folder IPNS metadata) + ├─ Root Folder Key (random AES-256, stored encrypted on server) + ├─ Subfolder Keys (random AES-256, stored encrypted in parent folder metadata) + └─ File Keys (random AES-256, stored encrypted in per-file metadata) + +IPNS Keypairs (Ed25519) + ├─ Vault IPNS (HKDF-derived from private key) + ├─ Device Registry IPNS (HKDF-derived from private key) + ├─ Subfolder IPNS (random, ECIES-wrapped in parent metadata) + └─ Per-file IPNS (random, ECIES-wrapped in FilePointer; legacy: HKDF-derived) ``` **Critical Rule:** Never log, persist to disk, or transmit the ECDSA private key. It exists ONLY in client memory during the session. -### Per-Folder IPNS Architecture - -Each folder has its own IPNS entry containing encrypted metadata. This design enables future per-folder sharing (v2+). +### v2 Folder Metadata with FilePointers -**Folder Metadata Structure:** +Each folder has its own IPNS entry. Files use a v2 `FilePointer` schema — the folder stores a slim reference, and per-file crypto material lives in a dedicated IPNS record. -```typescript -interface DecryptedFolderMetadata { - children: Array<{ - type: 'file' | 'folder'; - nameEncrypted: string; // AES-256-GCM(name, folderKey) - nameIv: string; - cid?: string; // For files: IPFS CID - ipnsName?: string; // For folders: IPNS name - fileKeyEncrypted?: string; // ECIES(fileKey, userPubkey) - subfolderKeyEncrypted?: string; // ECIES(folderKey, userPubkey) - size?: number; - created: number; - modified: number; - }>; -} -``` +See [docs/METADATA_SCHEMAS.md](../docs/METADATA_SCHEMAS.md) for the full schema reference including `FolderMetadata`, `FilePointer`, `FileMetadata`, and all other metadata objects. -**When modifying files/folders:** Always re-encrypt and republish the containing folder's IPNS entry. +## Technology Stack -## Technology Stack & Standards +| Component | Technology | +| :----------------- | :----------------------------------------------- | +| **Frontend** | React 18 + TypeScript + Tailwind CSS | +| **Backend** | Node.js + NestJS + TypeScript | +| **Database** | PostgreSQL 16 | +| **Job Queue** | BullMQ + Redis | +| **Key Derivation** | Web3Auth MPC Core Kit (`@web3auth/mpc-core-kit`) | +| **Storage** | IPFS via Kubo | +| **Desktop** | Tauri v2 + FUSE-T (macOS, SMB backend) | +| **TEE** | Phala Cloud (IPNS republishing) | +| **Crypto** | Web Crypto API (AES-256-GCM, ECIES secp256k1) | ### Encryption Primitives (Non-Negotiable) -| Algorithm | Use Case | Implementation | -| ------------------- | ----------------------------------- | ----------------------------- | -| **AES-256-GCM** | File content + metadata encryption | Web Crypto API / libsodium.js | -| **ECIES secp256k1** | Key wrapping (files, folders) | ethers.js / libsodium.js | -| **ECDSA secp256k1** | IPNS signing, user identity | Web3Auth / ethers.js | -| **HKDF-SHA256** | Key derivation | Web Crypto API | -| **Argon2** | Password hashing (server-side only) | argon2-browser | +| Algorithm | Use Case | Implementation | +| ------------------- | ----------------------------------- | -------------- | +| **AES-256-GCM** | File content + metadata encryption | Web Crypto API | +| **AES-256-CTR** | Streaming encryption (large files) | Web Crypto API | +| **ECIES secp256k1** | Key wrapping (files, folders, IPNS) | eciesjs | +| **HKDF-SHA256** | IPNS keypair derivation | Web Crypto API | +| **Ed25519** | IPNS record signing | @noble/ed25519 | **Never use:** Custom crypto, CBC mode, ECB mode, MD5, SHA1 -### Target Tech Stack (v1.0) - -- **Frontend:** React 18 + TypeScript + Tailwind CSS -- **Backend:** Node.js + NestJS + TypeScript -- **Database:** PostgreSQL (users, vaults, audit trail) -- **Storage:** IPFS via Pinata API -- **Auth:** Web3Auth Modal SDK (@web3auth/modal) -- **Desktop:** Tauri/Electron + FUSE (macFUSE/FUSE3/WinFSP) +## API Endpoints (Actual Implementation) + +| Endpoint | Method | Purpose | +| :-------------------------------- | :----- | :------------------------------------------ | +| `/auth/identity/google` | POST | Google OAuth authentication | +| `/auth/identity/email/send-otp` | POST | Send email OTP | +| `/auth/identity/email/verify-otp` | POST | Verify email OTP | +| `/auth/identity/wallet/nonce` | GET | Get nonce for wallet auth | +| `/auth/identity/wallet` | POST | Wallet signature authentication | +| `/vault` | GET | Get vault data | +| `/vault/init` | POST | Initialize vault (first-time setup) | +| `/vault/config` | GET | Get vault configuration | +| `/vault/export` | GET | Generate vault export | +| `/vault/quota` | GET | Get storage quota | +| `/ipfs/upload` | POST | Upload encrypted file (multipart/form-data) | +| `/ipfs/unpin` | POST | Unpin CID from IPFS | +| `/ipfs/:cid` | GET | Fetch file by CID | +| `/ipns/publish` | POST | Publish IPNS record | +| `/ipns/publish-batch` | POST | Batch publish IPNS records | +| `/ipns/resolve` | GET | Resolve IPNS name to CID | +| `/device-approval/request` | POST | Request device approval | +| `/device-approval/pending` | GET | Get pending approvals | +| `/shares` | POST | Create a share | +| `/shares/received` | GET | Get received shares | ## Development Patterns @@ -122,24 +121,22 @@ interface DecryptedFolderMetadata { When working on `apps/api` code: -1. **After modifying API endpoints, DTOs, or controllers**, regenerate the API client to keep the web app in sync: +1. **After modifying API endpoints, DTOs, or controllers**, regenerate the API client: ```bash pnpm api:generate ``` - This command generates the OpenAPI spec from the API, creates the typed client for the web app, and runs lint fixes. - -2. **Always run `pnpm api:generate` before completing a feature** that touches the API to ensure type safety across the monorepo. +2. **Always run `pnpm api:generate` before completing a feature** that touches the API. 3. **Commit the regenerated client files** (`apps/web/src/api/`) along with your API changes. -### File Upload Flow (Reference Implementation) +### File Upload Flow (Reference) ```typescript // 1. Generate random file key const fileKey = crypto.getRandomValues(new Uint8Array(32)); -const fileIV = crypto.getRandomValues(new Uint8Array(12)); // GCM uses 96-bit IV +const fileIV = crypto.getRandomValues(new Uint8Array(12)); // 2. Encrypt file content const encryptedFile = await crypto.subtle.encrypt( @@ -151,27 +148,20 @@ const encryptedFile = await crypto.subtle.encrypt( // 3. Wrap file key with user's public key (ECIES) const encryptedFileKey = await eciesEncrypt(fileKey, userPublicKey); -// 4. Upload encrypted file to backend → Pinata → get CID -const { cid } = await api.post('/vault/upload', { - encryptedFile: new Blob([encryptedFile]), - fileName: file.name, // plaintext OK for server audit - iv: bytesToHex(fileIV), -}); - -// 5. Add to folder metadata (all encrypted) -const fileEntry = { - type: 'file', - nameEncrypted: await aesEncrypt(file.name, folderKey), - nameIv: crypto.getRandomValues(new Uint8Array(12)), - cid, - fileKeyEncrypted: encryptedFileKey, - fileIv: bytesToHex(fileIV), - size: file.size, - created: Date.now(), - modified: Date.now(), -}; - -// 6. Re-encrypt folder metadata and republish IPNS +// 4. Upload encrypted file to backend → IPFS → get CID +// POST /ipfs/upload (multipart/form-data with 'file' field) +const formData = new FormData(); +formData.append('file', new Blob([encryptedFile])); +const { cid } = await api.post('/ipfs/upload', formData); +// NOTE: No fileName sent — the server never sees plaintext file names + +// 5. Create per-file FileMetadata (own IPNS record) +// Contains: cid, fileKeyEncrypted, fileIv, size, etc. + +// 6. Add FilePointer to folder metadata children +// Contains: type, nameEncrypted, nameIv, fileMetaIpnsName + +// 7. Re-encrypt folder metadata and republish IPNS await republishFolderIPNS(folderId, updatedMetadata); ``` @@ -181,246 +171,81 @@ Every write operation (create/rename/move/delete) must: 1. Update the in-memory folder metadata 2. Re-encrypt the entire metadata JSON with the folder key -3. Sign the encrypted metadata with ECDSA private key -4. Call `POST /vault/publish-ipns` with signed entry - -**Performance Note:** IPNS publishing is the bottleneck (~2s). Batch operations when possible (e.g., multi-file upload should publish once at the end). +3. Upload encrypted metadata to IPFS → get new CID +4. Publish IPNS record: `/ipns/k51...` → `/ipfs/` -### Session Token Management - -```typescript -// Access tokens (15min, memory only) -const accessToken = response.data.accessToken; -// Store in: React context / Zustand / Redux (never localStorage) - -// Refresh tokens (7 days, secure storage) -const refreshToken = response.data.refreshToken; -// Store in: HTTP-only cookie (preferred) OR encrypted localStorage - -// Token refresh pattern -if (error.response?.status === 401) { - const newAccessToken = await refreshAccessToken(); - // Retry original request with new token -} -``` +**Performance Note:** IPNS publishing is the bottleneck (~2s). Batch operations when possible. ## Common Pitfalls & Anti-Patterns -### ❌ Never Do This - -1. **Storing keys in plaintext localStorage** - - ```typescript - // WRONG - localStorage.setItem('privateKey', privateKeyHex); - ``` - -2. **Logging sensitive data** - - ```typescript - // WRONG - console.log('User private key:', privateKey); - console.log('Decrypted file:', fileContent); - ``` - -3. **Sending plaintext to server** - - ```typescript - // WRONG - await api.post('/vault/upload', { fileContent: file }); - ``` - -4. **Using sync crypto in main thread** - ```typescript - // WRONG (blocks UI for large files) - const encrypted = aesEncryptSync(largeFile, key); - ``` - -### ✅ Correct Patterns - -1. **Store keys in memory, clear on logout** +### Never Do This - ```typescript - // React context for session-scoped state - const [ecdsaPrivateKey, setEcdsaPrivateKey] = useState(null); +1. **Store keys in plaintext localStorage** — use in-memory state only +2. **Log sensitive data** — no `console.log` of keys, decrypted content +3. **Send plaintext to server** — all file content and names must be encrypted client-side +4. **Send file names to server** — the server is zero-knowledge, it never sees plaintext names +5. **Use sync crypto in main thread** — use Web Workers for large files - const logout = () => { - setEcdsaPrivateKey(null); // Cleared from memory - // No disk persistence - }; - ``` +### Correct Patterns +1. **Store keys in memory, clear on logout** (React context / Zustand) 2. **Use Web Workers for large file encryption** - - ```typescript - const worker = new Worker('./crypto-worker.js'); - worker.postMessage({ fileData, key }); - worker.onmessage = (e) => { - const encrypted = e.data; - }; - ``` - -3. **Always validate IPNS signatures client-side** - ```typescript - const messageHash = await sha256(signedEntry.encryptedMetadata); - const isValid = await ecdsaVerify(messageHash, signedEntry.signature, userPubkey); - if (!isValid) throw new Error('Metadata tampering detected'); - ``` +3. **Use `Uint8Array` for all binary data**, not strings +4. **Use `camelCase` for API fields, `snake_case` for database columns** ## MVP Scope Boundaries (v1.0) -### ✅ In Scope +### In Scope -- Multi-method auth (email/pass, OAuth, magic link, external wallet) +- Multi-method auth (email OTP, Google OAuth, magic link, external wallet) - File upload/download (E2E encrypted) - Folder operations (create/rename/move/delete) -- Web UI (React) -- Desktop mount (macOS FUSE only for v1.0) +- Web UI (React) + Desktop mount (macOS FUSE via Tauri v2) - Multi-device sync (IPNS polling, ~30s latency) - Vault export (data portability) +- TEE-based IPNS republishing (Phala Cloud) -### ❌ Out of Scope (defer to v1.1+) +### Out of Scope (defer to v1.1+) - Billing/payments - File versioning -- Folder sharing - Search/indexing - Mobile apps -- Linux/Windows desktop (v1.1) +- Linux/Windows desktop -**When users request out-of-scope features:** Acknowledge the value, but clarify they're post-MVP. Suggest workarounds if applicable. - -## Testing Requirements +## Testing ### Security Test Checklist - [ ] Private key never logged (search logs for "privateKey", "ecdsa", "0x04") - [ ] Private key never in localStorage/sessionStorage - [ ] All file uploads: server receives ciphertext only -- [ ] All folder names: encrypted in IPNS metadata +- [ ] All folder/file names: encrypted in metadata, never sent plaintext - [ ] IPNS signature verification passes - [ ] Wrong private key cannot decrypt vault -### Performance Benchmarks (P95) - -- Auth flow: <3s -- File upload (<100MB): <5s -- File download (<100MB): <5s -- IPNS publish: <2s -- Folder create: <1s -- Multi-device sync latency: <30s +### Running Tests -## Key Files & Documentation - -- [00_START_HERE.md](../00_START_HERE.md) - Project overview, quick reference -- [README.md](../README.md) - Architecture summary, tech stack -- [Preliminary/Documentation/IMPLEMENTATION_ROADMAP.md](../Preliminary/Documentation/IMPLEMENTATION_ROADMAP.md) - 12-week development timeline -- [Preliminary/Documentation/PRD.md](../Preliminary/Documentation/PRD.md) - Product requirements, user journeys, scope -- [Preliminary/Documentation/TECHNICAL_ARCHITECTURE.md](../Preliminary/Documentation/TECHNICAL_ARCHITECTURE.md) - Encryption, key hierarchy, system design -- [Preliminary/Documentation/API_SPECIFICATION.md](../Preliminary/Documentation/API_SPECIFICATION.md) - Backend endpoints, database schema -- [Preliminary/Documentation/DATA_FLOWS.md](../Preliminary/Documentation/DATA_FLOWS.md) - Sequence diagrams, test vectors -- [Preliminary/Documentation/CLIENT_SPECIFICATION.md](../Preliminary/Documentation/CLIENT_SPECIFICATION.md) - Web UI, desktop app specs - -**For detailed crypto flows:** See TECHNICAL_ARCHITECTURE.md (key hierarchy, encryption primitives) and DATA_FLOWS.md (sequence diagrams, test vectors) - -## API Conventions (When Backend Exists) - -### Expected Endpoints - -- `POST /auth/login` - Authenticate with Web3Auth ID token or SIWE signature -- `GET /auth/nonce` - Get nonce for SIWE flow -- `POST /auth/refresh` - Refresh access token -- `GET /my-vault` - Get encrypted root key + IPNS name -- `POST /my-vault/initialize` - Create vault (first-time setup) -- `POST /vault/upload` - Upload encrypted file → IPFS → return CID -- `POST /vault/publish-ipns` - Publish signed IPNS entry -- `POST /vault/export` - Generate vault export JSON - -### Response Patterns - -```typescript -// Success -{ success: true, data: { cid: "QmXxxx..." } } - -// Error -{ success: false, error: { code: "VAULT_NOT_INITIALIZED", message: "..." } } -``` - -## Web3Auth Integration Notes - -### Group Connections Setup (Dashboard) - -Configure in Web3Auth dashboard to link multiple auth methods: - -``` -cipherbox-aggregate (group ID) - ├─ google (Google OAuth) - ├─ email_passwordless (Magic Link) - ├─ auth0 (Email/Password via Auth0) - └─ external_wallets (MetaMask, WalletConnect) -``` - -### Client Integration - -```typescript -import { Web3Auth } from '@web3auth/modal'; - -const web3auth = new Web3Auth({ - clientId: 'YOUR_CLIENT_ID', - web3AuthNetwork: 'sapphire_mainnet', // or testnet - chainConfig: { - chainNamespace: 'eip155', - chainId: '0x1', // Ethereum mainnet (or any chain) - }, -}); - -await web3auth.initModal(); -const web3authProvider = await web3auth.connect(); - -// Get private key (use sparingly, clear from memory ASAP) -const privateKey = await web3authProvider.request({ - method: 'eth_private_key', -}); - -// Get ID token for CipherBox backend auth -const { idToken } = await web3auth.authenticateUser(); +```bash +pnpm test # Unit tests (all workspaces) +pnpm test:e2e # Playwright E2E (Playwright starts API/web automatically) +pnpm typecheck # TypeScript type checking ``` -## Verification Requirements +## Verification with MCP Tools ### Playwright MCP for Application Testing -**ALWAYS attempt to verify application changes using Playwright MCP** when it is available. This ensures implemented features work correctly at runtime. - -**Verification workflow:** - -1. Navigate to the app URL (typically `http://localhost:5173`) -2. Wait for page elements to load -3. Capture screenshots for visual verification -4. Verify element existence and content -5. Test interactive features (clicks, form submissions) -6. Verify computed styles match design specifications +**ALWAYS attempt to verify application changes using Playwright MCP** when available. **If Playwright MCP is not available:** - Document what needs manual verification - Provide step-by-step test instructions -- Flag items that require human review - -### Pencil Design Verification - -For UI work, verify implementations against Pencil design files: - -1. **Design files are at:** `designs/*.pen` (JSON format) -2. **Extract exact values:** Colors (hex), spacing (pixels), typography -3. **Verify CSS matches:** Check both source CSS and computed styles -4. **Document discrepancies:** Include file/line references for fixes -**Key design specs:** +### Pencil MCP for Design Work -- Colors: `#000000` (background), `#00D084` (primary green) -- Font: JetBrains Mono (400, 600, 700 weights) -- Spacing: 8px, 12px, 16px, 24px, 32px scale +For UI work, verify implementations against Pencil design files at `designs/*.pen`. ## Questions to Ask When Unclear @@ -432,6 +257,6 @@ For UI work, verify implementations against Pencil design files: ## Final Note -This project prioritizes **cryptographic correctness over convenience**. When in doubt, err on the side of more encryption, more validation, and stricter security. The target user (cypherpunks, crypto enthusiasts) values privacy guarantees more than UX polish. +This project prioritizes **cryptographic correctness over convenience**. When in doubt, err on the side of more encryption, more validation, and stricter security. -**For detailed guidance:** Refer to [PRD.md](../Preliminary/Documentation/PRD.md) for product scope, [TECHNICAL_ARCHITECTURE.md](../Preliminary/Documentation/TECHNICAL_ARCHITECTURE.md) for crypto and system design, and [DATA_FLOWS.md](../Preliminary/Documentation/DATA_FLOWS.md) for test vectors and sequence diagrams. +**For detailed guidance:** See [docs/ARCHITECTURE.md](../docs/ARCHITECTURE.md) for crypto design and [docs/METADATA_SCHEMAS.md](../docs/METADATA_SCHEMAS.md) for all metadata object schemas. diff --git a/.markdownlintignore b/.markdownlintignore index 9a0aced3bd..3c5072a897 100644 --- a/.markdownlintignore +++ b/.markdownlintignore @@ -8,8 +8,6 @@ CHANGELOG.md # Finalized specifications - do not modify 00-Preliminary-R&D/ -00_START_HERE.md - # Build artifacts apps/desktop/src-tauri/target/ diff --git a/.planning/ENVIRONMENTS.md b/.planning/ENVIRONMENTS.md index fbe121b259..fab372987d 100644 --- a/.planning/ENVIRONMENTS.md +++ b/.planning/ENVIRONMENTS.md @@ -22,7 +22,7 @@ CipherBox requires isolated environments to prevent cross-environment interferen | **Local Dev** | Kubo (offline) | Sapphire Devnet | Mock service | Local Postgres | **Disabled** | Full | | **CI E2E** | Kubo (offline) | Sapphire Devnet | Mock service (per-run) | Ephemeral Postgres | **Disabled** | Full per-run | | **Staging** | Kubo (online) | Sapphire Devnet | delegated-ipfs.dev | Managed Postgres | **Active** (testnet) | Shared with Local/CI users | -| **Production** | Pinata | Sapphire Mainnet | delegated-ipfs.dev | Production Postgres | **Active** (mainnet) | Full | +| **Production** | Kubo (managed) | Sapphire Mainnet | delegated-ipfs.dev | Production Postgres | **Active** (mainnet) | Full | ## Solution: Environment-Aware Key Derivation @@ -292,8 +292,7 @@ JWT_SECRET=${{ secrets.JWT_SECRET_STAGING }} **Infrastructure:** - Managed PostgreSQL (AWS RDS / Cloud SQL / etc.) -- Pinata for IPFS pinning (redundant, managed) -- Optional: Self-hosted Kubo cluster for reads +- Kubo for IPFS pinning (self-hosted or managed) **Configuration:** @@ -305,8 +304,7 @@ VITE_ENVIRONMENT=production # Network is derived from this (see web3auth/config CIPHERBOX_ENVIRONMENT=production NODE_ENV=production -IPFS_PROVIDER=pinata -PINATA_JWT=${{ secrets.PINATA_JWT }} +IPFS_LOCAL_API_URL=http://ipfs:5001 DELEGATED_ROUTING_URL=https://delegated-ipfs.dev JWT_SECRET=${{ secrets.JWT_SECRET_PRODUCTION }} ``` @@ -315,7 +313,7 @@ JWT_SECRET=${{ secrets.JWT_SECRET_PRODUCTION }} - **Separate Web3Auth Project** (Sapphire Mainnet) - Different client ID (complete user isolation from dev/staging) -- Pinata for production-grade IPFS pinning +- Kubo for production-grade IPFS pinning - Environment context: `production` ## Web3Auth Project Setup @@ -412,7 +410,7 @@ export const web3AuthOptions: Web3AuthOptions = { | `NODE_ENV` | development | test | production | production | | `CIPHERBOX_ENVIRONMENT` | local | ci | staging | production | | `DB_DATABASE` | cipherbox_local | cipherbox_ci | cipherbox_staging | cipherbox_prod | -| `IPFS_PROVIDER` | local | local | local | pinata | +| `IPFS_PROVIDER` | local | local | local | local | | `DELEGATED_ROUTING_URL` | localhost:3001 | localhost:3001 | delegated-ipfs.dev | delegated-ipfs.dev | | `JWT_SECRET` | dev-secret | ci-secret | secrets.JWT_STAGING | secrets.JWT_PROD | | `TEE_ENABLED` | **false** | **false** | true | true | diff --git a/.planning/MILESTONES.md b/.planning/MILESTONES.md index 827896acc5..5400aae5ed 100644 --- a/.planning/MILESTONES.md +++ b/.planning/MILESTONES.md @@ -52,7 +52,7 @@ - Web3Auth authentication (email, OAuth, magic link, external wallet) - Client-side AES-256-GCM encryption + ECIES key wrapping -- IPFS file storage via Pinata with IPNS metadata +- IPFS file storage via Kubo with IPNS metadata - Full file/folder CRUD with 20-level folder hierarchy - File browser web UI with terminal aesthetic - Multi-device sync via IPNS polling (30s interval) diff --git a/.planning/PROJECT.md b/.planning/PROJECT.md index c6dd86dac8..30aa4bdd3c 100644 --- a/.planning/PROJECT.md +++ b/.planning/PROJECT.md @@ -20,7 +20,7 @@ CipherBox is a production-grade, privacy-first encrypted cloud storage platform - Web3Auth authentication (email, OAuth, magic link, external wallet) — v0.1 - Client-side AES-256-GCM encryption + ECIES key wrapping — v0.1 -- IPFS file storage via Pinata with IPNS metadata — v0.1 +- IPFS file storage via Kubo with IPNS metadata — v0.1 - Full file/folder CRUD with 20-level hierarchy — v0.1 - File browser web UI with terminal aesthetic — v0.1 - Multi-device sync via IPNS polling (30s) — v0.1 @@ -95,7 +95,7 @@ See `.planning/milestones/m3/REQUIREMENTS.md` for full requirements. **Technical Environment:** -- IPFS via Pinata for file storage and pinning +- IPFS via Kubo for file storage and pinning - IPNS for mutable metadata pointers (per-folder + per-file) - Web3Auth Core Kit MPC for deterministic ECDSA key derivation - Phala Cloud for TEE auto-republishing (3-hour interval) @@ -112,13 +112,13 @@ See `.planning/milestones/m3/REQUIREMENTS.md` for full requirements. ## Constraints - **File size**: 100 MB max — browser memory limits -- **Storage quota**: 500 MiB free tier — Pinata cost management +- **Storage quota**: 500 MiB free tier — IPFS storage management - **Files per folder**: 1,000 max — UI performance - **Folder depth**: 20 levels max — traversal performance - **Sync latency**: ~30 seconds — IPNS polling interval - **Tech stack**: NestJS backend, React 18 frontend, Tauri desktop — per specifications - **Auth provider**: Web3Auth Core Kit MPC — deterministic key derivation requirement -- **IPFS provider**: Pinata — managed pinning service +- **IPFS provider**: Kubo (self-hosted) ## Key Decisions diff --git a/.planning/REFACTORING.md b/.planning/REFACTORING.md index 6b5cd49e5c..4f0e683876 100644 --- a/.planning/REFACTORING.md +++ b/.planning/REFACTORING.md @@ -54,7 +54,7 @@ - [x] **Status:** DONE - **Files:** `apps/api/src/auth/auth.service.ts` -- **Problem:** 6 distinct responsibilities, cross-domain dependencies (IPFS/Pinata in auth) +- **Problem:** 6 distinct responsibilities, cross-domain dependencies (IPFS in auth) - **Fix:** Split into `AuthService` (core), `AuthMethodService`, `AccountService`, `TestAuthService` ### 2.3 Split `SharesService` (569 lines) diff --git a/.planning/codebase/ARCHITECTURE.md b/.planning/codebase/ARCHITECTURE.md index 622de3f154..11dd75bd3d 100644 --- a/.planning/codebase/ARCHITECTURE.md +++ b/.planning/codebase/ARCHITECTURE.md @@ -1,163 +1,189 @@ # Architecture -**Analysis Date:** 2026-01-20 +**Analysis Date:** 2026-03-06 ## Pattern Overview -**Overall:** Specification-First / Pre-Implementation Technology Demonstrator +**Overall:** Zero-Knowledge Encrypted Cloud Storage (Implemented) **Key Characteristics:** -- Complete specification documents define the target architecture before implementation -- Single proof-of-concept (PoC) console harness validates core IPFS/IPNS and encryption flows + - Layered E2E encryption with zero-knowledge server design - Client-side cryptographic operations with server acting as relay and storage proxy -- Per-folder IPNS records enabling future modular sharing capabilities +- Per-folder IPNS records enabling modular sharing capabilities +- v2 FilePointer schema with per-file IPNS metadata records +- Two-phase authentication (Web3Auth MPC Core Kit + CipherBox backend JWT) ## Layers -**Specification Layer:** -- Purpose: Define complete system design, security model, and implementation contract -- Location: `00-Preliminary-R&D/Documentation/` -- Contains: PRD, technical architecture, API spec, data flows, client spec, implementation roadmap -- Depends on: None (foundation documents) -- Used by: All implementation code (when built) +**Web Client Layer (Implemented):** + +- Purpose: Handle all encryption/decryption, key management, file browser UI +- Location: `apps/web/` +- Contains: React 18 + TypeScript + Tailwind CSS web app +- Depends on: Web3Auth MPC Core Kit, Web Crypto API, CipherBox Backend API +- Used by: End users via browser + +**Backend API Layer (Implemented):** -**Proof-of-Concept Layer:** -- Purpose: Validate IPFS/IPNS assumptions and encryption flows end-to-end -- Location: `00-Preliminary-R&D/poc/` -- Contains: Single-file console harness demonstrating file/folder operations -- Depends on: IPFS daemon, cryptographic libraries -- Used by: Architecture validation only (not production) - -**Client Layer (Specified, Not Implemented):** -- Purpose: Handle all encryption/decryption, key management, UI -- Location: (Not yet created - see `00-Preliminary-R&D/Documentation/CLIENT_SPECIFICATION.md`) -- Contains: React 18 web app, Tauri/Electron desktop app with FUSE -- Depends on: Web3Auth SDK, Web Crypto API, CipherBox Backend API -- Used by: End users - -**Backend Layer (Specified, Not Implemented):** - Purpose: Token management, IPFS/IPNS relay, vault metadata storage, TEE coordination -- Location: (Not yet created - see `00-Preliminary-R&D/Documentation/API_SPECIFICATION.md`) -- Contains: NestJS API with 15 endpoints -- Depends on: PostgreSQL, Pinata API, Web3Auth JWKS, TEE providers -- Used by: Client applications +- Location: `apps/api/` +- Contains: NestJS API with auth, vault, IPFS, IPNS, shares, device-approval endpoints +- Depends on: PostgreSQL, IPFS (Kubo), Redis/BullMQ, Web3Auth JWKS +- Used by: Web client, desktop client + +**Desktop Client Layer (Implemented):** + +- Purpose: Transparent file access via virtual filesystem mount +- Location: `apps/desktop/` +- Contains: Tauri v2 shell with FUSE-T (SMB backend on macOS), WinFSP (Windows) +- Depends on: CipherBox Backend API, FUSE-T/WinFSP +- Used by: End users via Finder/Explorer + +**Shared Crypto Library (Implemented):** + +- Purpose: Reusable encryption/decryption primitives +- Location: `packages/crypto/` +- Contains: AES-256-GCM/CTR, ECIES, HKDF, metadata encryption/decryption +- Depends on: Web Crypto API, eciesjs, @noble/ed25519 +- Used by: Web client, desktop client (via wasm/native bindings) + +**TEE Layer (Implemented):** -**TEE Layer (Specified, Not Implemented):** - Purpose: Automatic IPNS republishing without user devices online -- Location: External services (Phala Cloud primary, AWS Nitro fallback) -- Contains: Secure enclaves for IPNS key decryption and signing -- Depends on: Backend republish schedule -- Used by: Backend cron jobs +- Location: `tee-worker/` +- Contains: Phala Cloud worker for IPNS key decryption and record signing +- Depends on: Backend republish schedule, delegated-ipfs.dev +- Used by: Backend cron jobs (every 6 hours) + +**Legacy PoC (Historical Reference Only):** + +- Location: `00-Preliminary-R&D/poc/` +- Status: Superseded by production code. Not used in any production flow. ## Data Flow **File Upload Flow:** -1. Client generates random `fileKey` (256-bit AES) +1. Client generates random `fileKey` (256-bit AES) and IV (96-bit) 2. Client encrypts file content with AES-256-GCM 3. Client wraps `fileKey` with user's `publicKey` via ECIES -4. Client sends encrypted blob to backend (POST `/ipfs/add`) -5. Backend relays to Pinata, returns CID -6. Client updates folder metadata with new file entry -7. Client encrypts metadata with `folderKey` -8. Client signs IPNS record with folder's `ipnsPrivateKey` -9. Client encrypts `ipnsPrivateKey` with TEE `publicKey` for republishing -10. Client sends signed record + encrypted IPNS key to backend (POST `/ipns/publish`) -11. Backend publishes to IPFS network and stores republish schedule +4. Client sends encrypted blob to backend (POST `/ipfs/upload`, multipart/form-data field `file`) +5. Backend relays to IPFS (Kubo), returns CID +6. Client creates per-file FileMetadata (own IPNS record): cid, fileKeyEncrypted, fileIv, size +7. Client adds FilePointer to folder metadata children: nameEncrypted, nameIv, fileMetaIpnsName +8. Client encrypts folder metadata with `folderKey` (AES-256-GCM) +9. Client signs IPNS record with folder's Ed25519 `ipnsPrivateKey` +10. Client sends signed record to backend (POST `/ipns/publish`) +11. Backend publishes to IPFS network via delegated routing **Authentication Flow:** -1. User authenticates via Web3Auth (4 methods supported) -2. Web3Auth derives deterministic ECDSA keypair (secp256k1) -3. Client authenticates with CipherBox backend (JWT or SIWE signature) -4. Backend verifies identity, issues access token (15min) + refresh token (7d) +1. User authenticates via Web3Auth MPC Core Kit (email OTP, Google OAuth, magic link, or external wallet) +2. Web3Auth derives deterministic ECDSA keypair (secp256k1) via MPC threshold cryptography +3. Client authenticates with CipherBox backend using Web3Auth ID token (JWT) +4. Backend validates via JWKS, issues access token (15min) + refresh token (7d) 5. Backend returns encrypted vault keys and TEE public keys -6. Client decrypts `rootFolderKey` using `privateKey` +6. Client decrypts `rootFolderKey` using `privateKey` (ECIES) 7. Session active until logout or token expiry **State Management:** + - `privateKey`: Client RAM only, never persisted or transmitted - `rootFolderKey`: Server stores encrypted with ECIES, client decrypts on login - Folder/file keys: Stored encrypted in IPNS metadata records -- `ipnsPrivateKey`: Client encrypts with TEE public key for republishing +- `ipnsPrivateKey`: Client encrypts with TEE public key for republishing enrollment ## Key Abstractions **Vault:** + - Purpose: User's encrypted file storage namespace -- Examples: Root folder IPNS record, associated metadata +- Location: `apps/api/src/vault/`, `apps/web/src/stores/vault.store.ts` - Pattern: One vault per user, identified by `rootIpnsName` **Folder:** + - Purpose: Encrypted container with child entries (files/folders) -- Examples: Root folder, Documents, Archive (from PoC) +- Location: `apps/web/src/services/folder.service.ts`, `packages/crypto/src/metadata/` - Pattern: Each folder has own IPNS keypair, `folderKey` for metadata encryption -**File Entry:** -- Purpose: Encrypted file reference within folder metadata -- Examples: `hello.txt` in PoC -- Pattern: Contains encrypted name, CID, wrapped `fileKey`, IV, encryption mode +**FilePointer (v2):** + +- Purpose: Slim reference in folder metadata pointing to per-file IPNS record +- Location: `packages/crypto/src/metadata/types.ts` +- Pattern: Contains encrypted name, timestamps, `fileMetaIpnsName` (reference to FileMetadata) + +**FileMetadata:** + +- Purpose: Per-file crypto material in dedicated IPNS record +- Location: `packages/crypto/src/metadata/types.ts` +- Pattern: Contains CID, `fileKeyEncrypted`, `fileIv`, size, encryption mode **TEE Key Epoch:** + - Purpose: Rotation-safe TEE public key management -- Examples: `currentEpoch`, `previousEpoch` for 4-week grace period -- Pattern: Client encrypts IPNS keys with current epoch, TEE supports previous for migration +- Location: `apps/api/src/republish/`, `tee-worker/src/` +- Pattern: Client encrypts IPNS keys with current epoch, TEE supports previous for 4-week grace period ## Entry Points -**PoC Console Harness:** -- Location: `00-Preliminary-R&D/poc/src/index.ts` -- Triggers: `npm run start` or `tsx src/index.ts` -- Responsibilities: Creates folder hierarchy, uploads/modifies/moves/deletes files, verifies IPNS resolution, cleans up (unpin, remove keys) +**Web Application:** + +- Location: `apps/web/src/main.tsx` +- Dev: `pnpm --filter web dev` () +- Routes: `/auth`, `/vault`, file browser UI -**Planned Web Application:** -- Location: (To be created) -- Triggers: Browser navigation to `/auth`, `/vault`, `/settings` -- Responsibilities: Authentication, file browser UI, encryption/decryption +**Backend API:** -**Planned Backend API:** -- Location: (To be created) -- Triggers: HTTP requests to 15 endpoints -- Responsibilities: Token management, IPFS/IPNS relay, vault storage, TEE coordination +- Location: `apps/api/src/main.ts` +- Dev: `pnpm --filter api dev` () +- Endpoints: auth, vault, IPFS, IPNS, shares, device-approval, republish -**Planned Desktop Application:** -- Location: (To be created) -- Triggers: App launch, FUSE mount at `~/CipherVault` -- Responsibilities: Transparent file access, background sync +**Desktop Application:** + +- Location: `apps/desktop/src/main.ts` (Tauri frontend), `apps/desktop/src-tauri/` (Rust backend) +- Dev: `pnpm --filter desktop tauri dev` +- Mount point: `~/CipherBox` (macOS FUSE-T SMB) + +**TEE Worker:** + +- Location: `tee-worker/src/index.ts` +- Deployed to Phala Cloud ## Error Handling -**Strategy:** Fail-fast with explicit error messages +**Strategy:** Fail-fast with user-facing error messages **Patterns:** -- PoC: Throws errors on failures, logs warnings for non-critical issues (e.g., pin removal) -- Specified Backend: HTTP status codes with structured error responses -- Specified Client: User-facing error messages, retry logic for transient failures -- TEE Republish: Exponential backoff (30s -> 60s -> 120s -> 240s -> 300s max) + +- Web: Toast notifications for user errors, console.error for debug (see CONCERNS.md for logging tech debt) +- API: HTTP status codes with structured NestJS exception filters +- Desktop FUSE: Returns errno codes (EIO, ENOENT, EPERM) to kernel +- IPNS delegated routing: Exponential backoff with retry (3 attempts, 1s base, 30s cap) +- Token refresh: Automatic retry with queue deduplication (`apps/web/src/lib/api/client.ts`) ## Cross-Cutting Concerns **Logging:** -- PoC: Console logging with step markers (`=== Step Name ===`) -- Backend (specified): Structured logging, no private keys in logs (Security criterion S8) -**Validation:** -- PoC: Runtime type checking via TypeScript -- Backend (specified): Request validation via NestJS decorators -- Client (specified): Input sanitization before encryption +- API: NestJS Logger (structured) +- Web: Direct console.\* calls (tech debt — see CONCERNS.md) +- Desktop: Rust `log` crate with `env_logger` **Authentication:** -- Two-phase: Web3Auth for key derivation, CipherBox backend for API tokens + +- Two-phase: Web3Auth MPC Core Kit for key derivation, CipherBox backend for API tokens - Token rotation: Refresh tokens rotated on each use - Zero-knowledge: Backend never sees private keys or plaintext **Security Invariants:** + - Private key exists only in client RAM, cleared on logout - All files encrypted with unique random key + IV (no deduplication) - Server stores only encrypted keys (ECIES wrapped) -- TEE keys exist in enclave memory only for milliseconds during signing +- TEE keys exist in enclave memory only during signing, then zeroed --- -*Architecture analysis: 2026-01-20* +Architecture analysis: 2026-03-06 diff --git a/.planning/codebase/CONCERNS.md b/.planning/codebase/CONCERNS.md index 06fada7a38..69be9a64b1 100644 --- a/.planning/codebase/CONCERNS.md +++ b/.planning/codebase/CONCERNS.md @@ -1,208 +1,277 @@ # Codebase Concerns -**Analysis Date:** 2026-01-20 +**Analysis Date:** 2026-03-06 ## Tech Debt -**Single 700-line monolithic POC file:** -- Issue: All POC functionality in one file (`00-Preliminary-R&D/poc/src/index.ts` - 702 lines) without modular separation -- Files: `00-Preliminary-R&D/poc/src/index.ts` -- Impact: Makes testing individual components impossible, increases cognitive load, harder to refactor -- Fix approach: Extract into modules (crypto.ts, ipfs.ts, folder.ts, types.ts) before building production code - -**No production implementation exists:** -- Issue: Only a console POC harness exists; no backend, frontend, or desktop app code -- Files: Only `00-Preliminary-R&D/poc/src/index.ts` contains implementation code -- Impact: Finalized specs (v1.11.1) have no corresponding implementation; 12-week roadmap has not started -- Fix approach: Begin Week 1 of IMPLEMENTATION_ROADMAP.md; create backend/frontend/desktop repos - -**Spec/Implementation version mismatch:** -- Issue: CLAUDE.md has git merge conflict markers (`<<<<<<< HEAD`) -- Files: `.claude/CLAUDE.md` -- Impact: Unclear which version is authoritative; potential confusion for AI assistants -- Fix approach: Resolve the merge conflict properly; remove conflict markers - -**Console logging throughout POC:** -- Issue: 21 console.log/warn/error calls embedded in POC code -- Files: `00-Preliminary-R&D/poc/src/index.ts` -- Impact: Not suitable for production; no structured logging; no log levels -- Fix approach: Production code should use a logging library (e.g., winston, pino) with structured output - -**Type assertions for IPFS client:** -- Issue: Type assertion workaround for ipfs-http-client incompatibility -- Files: `00-Preliminary-R&D/poc/src/index.ts:285` -- Impact: `type: "ed25519" as unknown as "Ed25519"` suggests library type definitions don't match implementation -- Fix approach: Verify library version compatibility; consider using @helia/ipns for newer IPNS support +**Orphaned IPNS records on file/folder deletion:** + +- Issue: When files or folders are deleted, their IPNS records and TEE republish enrollments are not cleaned up. The code logs warnings and defers to "Phase 14" via TODO comments. +- Files: `apps/web/src/services/folder.service.ts:455`, `apps/web/src/services/folder.service.ts:507-512`, `apps/web/src/services/delete.service.ts:22-29` +- Impact: Orphaned IPNS records accumulate in the TEE republish schedule. The republish service has capacity warnings at 1000+ records. Each orphan wastes TEE compute and delegated routing bandwidth every 6 hours until natural expiry. +- Fix approach: The API already has `unenrollIpns()` at `apps/api/src/republish/republish.service.ts:255`. Expose it via a REST endpoint and call it from the web client during file/folder deletion. Batch unenrollment needed for folder deletes containing multiple files. + +**Desktop device approval polling not implemented:** + +- Issue: Phase 11.2 TODO comments indicate the desktop app lacks approval notification polling. When another device needs MFA approval, the desktop user has no notification. +- Files: `apps/desktop/src/main.ts:32`, `apps/desktop/src/auth.ts:680` +- Impact: Desktop users must use the web app to approve new devices. Reduces desktop app self-sufficiency. +- Fix approach: Add a background polling interval (similar to web's `useDeviceApproval`) that checks for pending approvals and surfaces native OS notifications via Tauri's notification API. + +**Legacy POC directory still in repo:** + +- Issue: `00-Preliminary-R&D/poc/` (702-line monolithic file) remains alongside production code. Uses deprecated `ipfs-http-client@60.0.1`, has no tests, and uses patterns explicitly superseded by the production implementation. +- Files: `00-Preliminary-R&D/poc/src/index.ts`, `00-Preliminary-R&D/poc/package.json` +- Impact: New contributors may confuse PoC with current implementation. Adds noise to searches and dependency audits. +- Fix approach: Already marked as historical reference per CLAUDE.md. Consider moving to a separate branch or archive tag if repo size is a concern. + +**Large monolithic files in web app:** + +- Issue: Several web app files exceed 900 lines, concentrating multiple responsibilities. +- Files: `apps/web/src/services/folder.service.ts` (1080 lines), `apps/web/src/components/file-browser/FileBrowser.tsx` (964 lines), `apps/web/src/services/bin.service.ts` (962 lines), `apps/web/src/hooks/useFolderMutations.ts` (793 lines), `apps/web/src/hooks/useAuth.ts` (522 lines), `apps/web/src/hooks/useSharedNavigation.ts` (551 lines) +- Impact: Difficult to test individual behaviors in isolation. Cognitive load for code review. Higher risk of merge conflicts. +- Fix approach: Extract folder CRUD operations from `folder.service.ts` into focused modules (create, delete, update, navigate). Split `FileBrowser.tsx` into container and presentational components. Extract bin operations into smaller service files. + +**Pervasive console.log/warn/error in web app:** + +- Issue: 50+ `console.error`/`console.warn`/`console.log` calls throughout production web code instead of a structured logging abstraction. +- Files: `apps/web/src/components/file-browser/FileBrowser.tsx` (12 calls), `apps/web/src/hooks/useAuth.ts` (10 calls), `apps/web/src/components/file-browser/BinBrowser.tsx` (5 calls), `apps/web/src/components/file-browser/ShareDialog.tsx` (3 calls), and many more across hooks and services. +- Impact: No log level filtering, no structured output, no ability to ship logs to an observability service. Debug logs leak into production. +- Fix approach: Introduce a lightweight logging wrapper (e.g., `lib/logger.ts`) that wraps `console.*` with level filtering and optional structured output. Replace all direct `console.*` calls. + +**Silenced unpin failures across the codebase:** + +- Issue: All IPFS unpin calls use `.catch(() => {})` pattern, silently swallowing failures. +- Files: `apps/web/src/components/file-browser/ReplaceFileDialog.tsx:53,64,73`, `apps/web/src/hooks/useDropUpload.ts:156`, `apps/web/src/hooks/useFileVersions.ts:142,261`, `apps/web/src/hooks/useFileOperations.ts:463`, `apps/web/src/services/bin.service.ts:717,748,826,842` +- Impact: Failed unpins mean orphaned data on IPFS that consumes storage quota without the user knowing. Over time this could exhaust the user's 500 MiB quota with unreachable data. +- Fix approach: Log unpin failures (at minimum) and consider a periodic background reconciliation that retries failed unpins. Track unpin failures in a local queue. + +**`any` type usage in web app:** + +- Issue: Several `as any` casts remain, primarily around Web3Auth SDK integration and polyfills. +- Files: `apps/web/src/main.tsx:6,64`, `apps/web/src/lib/web3auth/hooks.ts:146,152`, `apps/web/src/polyfills.ts:6-9`, `apps/web/src/stores/folder.store.ts:185` +- Impact: Type safety gaps around authentication flow. Web3Auth SDK types are poorly defined, making it hard to eliminate. +- Fix approach: Create typed wrappers for Web3Auth SDK interactions. The polyfill `any` casts are acceptable (Node.js globals on `window`). ## Known Bugs -**Disabled IPNS record size logging:** -- Symptoms: `logIpnsRecordSize` function is a no-op that does nothing -- Files: `00-Preliminary-R&D/poc/src/index.ts:86-89` -- Trigger: Any IPNS publish operation -- Workaround: Comment states "The routing API is not available in ipfs-http-client v60" +**No active known bugs identified in the current codebase.** -**IPFS HTTP client version limitations:** -- Symptoms: Routing API incompatible with ipfs-http-client v60 -- Files: `00-Preliminary-R&D/poc/package.json:16` (ipfs-http-client@60.0.1) -- Trigger: Attempting to use routing APIs -- Workaround: Feature disabled; recent commit `3010cdd` removed incompatible routing API usage +Previous known bugs (upload modal stuck, auth refresh race) were fixed in PRs #56 and #58. The IPNS resolve 502 issue (delegated-ipfs.dev unreliability) is mitigated by DB-cached CID fallback and retry logic in `apps/api/src/ipns/delegated-routing.client.ts`. ## Security Considerations -**Private key loaded from environment:** -- Risk: POC loads ECDSA_PRIVATE_KEY from .env file; production must never persist keys -- Files: `00-Preliminary-R&D/poc/src/index.ts:527-529`, `00-Preliminary-R&D/poc/.env.example` -- Current mitigation: .env.example documents the pattern; README warns this is not production code -- Recommendations: Production must derive keys via Web3Auth per TECHNICAL_ARCHITECTURE.md - -**No memory zeroing for sensitive data:** -- Risk: Private keys, folder keys, and file keys may remain in Node.js memory after use -- Files: `00-Preliminary-R&D/poc/src/index.ts` (entire file uses Uint8Array for keys without explicit clearing) -- Current mitigation: None in POC -- Recommendations: Production code must explicitly zero buffers after crypto operations (per CLAUDE.md guideline) - -**Pinata credentials in environment:** -- Risk: API keys stored in .env for POC -- Files: `00-Preliminary-R&D/poc/.env.example:11-14` -- Current mitigation: PINATA_ENABLED=false by default -- Recommendations: Production should use secrets management (AWS Secrets Manager, HashiCorp Vault) - -**No input validation on crypto operations:** -- Risk: POC assumes all inputs are valid (no checks for key length, IV size, etc.) -- Files: `00-Preliminary-R&D/poc/src/index.ts:101-115` (aesGcmEncrypt/Decrypt) -- Current mitigation: None -- Recommendations: Production must validate key sizes (32 bytes), IV sizes (12 bytes), tag presence +**Memory zeroing is best-effort in JavaScript:** + +- Risk: `clearBytes()` / `.fill(0)` cannot guarantee sensitive key material is erased from V8 heap, JIT-compiled code, or GC intermediaries. +- Files: `packages/crypto/src/utils/memory.ts`, `apps/web/src/stores/vault.store.ts:73-81`, `apps/web/src/stores/auth.store.ts:74-77`, `apps/web/src/stores/folder.store.ts:137-169` +- Current mitigation: The codebase consistently uses `.fill(0)` on key buffers during logout and store cleanup. The crypto package documents the limitation clearly. +- Recommendations: This is an inherent JavaScript limitation. For the desktop app, the Rust side should use `zeroize` crate for key material. Current approach is acceptable for browser context. + +**Web3Auth localStorage usage:** + +- Risk: Web3Auth MPC Core Kit stores its share factor in `localStorage`, which is accessible to XSS. +- Files: `apps/web/src/lib/web3auth/core-kit.ts:24` (`storage: window.localStorage`) +- Current mitigation: CipherBox's own keys (vault keypair, folder keys) are never stored in localStorage -- only in Zustand memory stores. The Web3Auth factor in localStorage is one share of a 2-of-3 TSS scheme (insufficient alone to derive the private key). +- Recommendations: CSP headers and XSS prevention remain critical. The MFA enrollment (Phase 12) adds a device approval factor that further limits exposure. + +**IPFS node credentials and access control:** + +- Risk: Kubo API endpoint has no built-in authentication. Anyone with network access to port 5001 can pin/unpin content. +- Files: `apps/api/src/ipfs/providers/local.provider.ts:14-24`, `apps/api/.env.example` +- Current mitigation: Kubo API bound to localhost in dev. In staging/production, Docker network isolation limits access to the API container. +- Recommendations: For production, use reverse proxy with auth or Kubo's API access controls. Consider network-level firewall rules. + +**Test login endpoint available in staging:** + +- Risk: `POST /auth/test-login` bypasses all real authentication. Available when `TEST_LOGIN_SECRET` is set and `NODE_ENV !== 'production'`. +- Files: `apps/api/.env.example:49-51`, `apps/api/src/auth/` (test-auth service) +- Current mitigation: Guarded by `NODE_ENV` check and requires knowing the secret. Not available in production. +- Recommendations: Ensure CI/CD pipeline never sets `TEST_LOGIN_SECRET` in production environment. Add monitoring alert if the endpoint is called in staging. + +**CORS wildcard patterns:** + +- Risk: CORS configuration supports wildcard patterns (e.g., `https://cipher-box-pr-*.onrender.com`) which could be abused if an attacker can create matching subdomains on the hosting platform. +- Files: `apps/api/src/main.ts:29-47` +- Current mitigation: Wildcards only match specific hosting platform patterns. +- Recommendations: Use exact origin lists in production. Reserve wildcards for PR preview environments only. ## Performance Bottlenecks -**Sequential IPNS publishing:** -- Problem: Each folder publish waits for IPNS propagation before continuing -- Files: `00-Preliminary-R&D/poc/src/index.ts:174-190` (waitForIpns), `00-Preliminary-R&D/poc/src/index.ts:264` -- Cause: IPNS resolution is eventually consistent; POC polls until expected CID appears -- Improvement path: Production could batch updates, use optimistic UI, or implement background sync +**FUSE FilePointer resolution blocks filesystem thread:** + +- Problem: After background metadata refresh, unresolved FilePointers are resolved synchronously on the single FUSE thread with `O(N * timeout)` latency. +- Files: `apps/desktop/src-tauri/src/fuse/mod.rs:1039-1049` +- Cause: Each FilePointer resolution requires an IPNS resolve network call. The TODO at line 1039 documents this. +- Improvement path: Spawn async tasks via a channel pair (like the existing `refresh_tx/rx` pattern) to avoid stalling the FUSE thread on network I/O. + +**Full file content buffering for AES-GCM encryption:** + +- Problem: Files encrypted with GCM mode are fully loaded into memory. The 100 MB file size limit means up to 100 MB of memory per concurrent upload. +- Files: `apps/web/src/services/upload.service.ts`, `packages/crypto/src/aes/encrypt.ts` +- Cause: AES-256-GCM requires full content for authentication tag computation. +- Improvement path: AES-256-CTR streaming encryption already exists (`packages/crypto/src/aes/encrypt-ctr.ts`, `packages/crypto/src/aes/decrypt-ctr.ts`) and is used for media streaming playback. Extend CTR usage to all uploads for reduced memory pressure. Desktop already uses CTR for FUSE reads. + +**IPNS polling for sync (30-second interval):** + +- Problem: Sync latency is at least 30 seconds. No push notification infrastructure exists. +- Files: `apps/web/src/hooks/useSyncPolling.ts`, per `TECHNICAL_ARCHITECTURE.md` Section 5.4 +- Cause: IPNS is pull-based. Adding WebSocket push would require backend infrastructure. +- Improvement path: Future versions could implement WebSocket notifications for immediate sync triggers, falling back to polling. -**Full file content buffering:** -- Problem: Files fully loaded into memory for encryption (no streaming) -- Files: `00-Preliminary-R&D/poc/src/index.ts:149-155` (collectChunks concatenates all chunks) -- Cause: AES-256-GCM requires full content for authentication tag -- Improvement path: v1.1 planned AES-256-CTR for streaming; maintain GCM for small files +**No pagination for large folders:** -**IPNS polling for sync:** -- Problem: 30-second polling interval creates sync latency -- Files: Per TECHNICAL_ARCHITECTURE.md Section 5.4 -- Cause: No push notification infrastructure -- Improvement path: Future versions may implement WebSocket notifications or exponential backoff +- Problem: Folder metadata contains all children inline. A folder with 1000 files loads all 1000 entries into memory and renders them all at once. +- Files: `apps/web/src/components/file-browser/FileList.tsx`, `apps/web/src/services/folder.service.ts` +- Cause: IPNS-based metadata is a single encrypted blob per folder. +- Improvement path: Implement virtual scrolling in the UI (render only visible rows). The 1000-file limit per PRD mitigates the data loading issue. ## Fragile Areas -**IPNS name generation depends on local IPFS node:** -- Files: `00-Preliminary-R&D/poc/src/index.ts:281-299` (generateFolder) -- Why fragile: POC uses `ctx.ipfs.key.gen()` which stores IPNS keys in local IPFS keystore -- Safe modification: Production must manage IPNS keys client-side (per TECHNICAL_ARCHITECTURE.md) -- Test coverage: No automated tests exist +**FUSE-T SMB backend on macOS:** -**Stress test metadata size:** -- Files: `00-Preliminary-R&D/poc/src/index.ts:352-394` (addSyntheticChildren) -- Why fragile: Generates fake entries with placeholder CIDs and IPNS names -- Safe modification: Only for manual testing; not suitable for verification -- Test coverage: Manual harness only +- Files: `apps/desktop/src-tauri/src/fuse/mod.rs` (1803 lines), `apps/desktop/src-tauri/src/fuse/write_ops.rs` (976 lines), `apps/desktop/src-tauri/vendor/fuser/src/channel.rs` +- Why fragile: FUSE-T is a userspace NFS/SMB translation layer, not kernel FUSE. Numerous workarounds exist for macOS-specific issues (SMB opendir requires non-zero fh, rename truncates filenames by 8 bytes, UID mismatch under SMB proxy, no FSEvents). Each macOS update could introduce new kernel-side behavior changes. +- Safe modification: Always test with Finder, Terminal `ls`/`mv`/`cp`, and multi-file operations. Single-thread constraint means any blocking call stalls everything. +- Test coverage: Manual testing only. No automated FUSE integration tests. The `tests.rs` files cover crypto operations but not filesystem operations. -**Folder tree traversal with depth limit:** -- Files: `00-Preliminary-R&D/poc/src/index.ts:419-468` (buildFolderTree) -- Why fragile: Hardcoded maxDepth=10 may not match PRD's 20-level limit -- Safe modification: Synchronize with constraint from PRD.md (20 levels) -- Test coverage: No automated tests +**Windows FUSE implementation (WinFSP):** + +- Files: `apps/desktop/src-tauri/src/fuse/windows/mod.rs` (498 lines), `apps/desktop/src-tauri/src/fuse/windows/operations.rs` (694 lines), `apps/desktop/src-tauri/src/fuse/windows/write_ops.rs` (997 lines), `apps/desktop/src-tauri/src/fuse/windows/read_ops.rs` (430 lines) +- Why fragile: 2824 lines of platform-specific FUSE code with many `lock().unwrap()` calls that will panic on poisoned mutex. No automated tests. Uses WinFSP which has different semantics from macOS FUSE-T. +- Safe modification: Test on actual Windows with Explorer, cmd, and PowerShell. Watch for mutex poisoning under error conditions. +- Test coverage: No automated tests exist for Windows FUSE operations. + +**Vendored fuser crate:** + +- Files: `apps/desktop/src-tauri/vendor/fuser/` (~5000 lines), `apps/desktop/src-tauri/vendor/fuser/src/channel.rs` (critical patch) +- Why fragile: Vendored fork of fuser 0.16 with socket-read patch for FUSE-T compatibility. Upstream updates cannot be trivially merged. The patch is load-bearing -- without it, large file writes crash the FUSE session. +- Safe modification: Never update without re-applying the `channel.rs` receive() patch. Document patch diff in vendor directory. +- Test coverage: No tests for the patched receive() function. + +**Delegated routing (delegated-ipfs.dev) dependency:** + +- Files: `apps/api/src/ipns/delegated-routing.client.ts` +- Why fragile: The external service at `delegated-ipfs.dev` has been unreliable historically (502 errors documented in memory). It is the sole path for IPNS record publishing and resolution from the API. +- Safe modification: The client has retry with exponential backoff (3 retries, 1s base delay, 30s cap). Changes to the API or rate limits could break publishing. +- Test coverage: Unit tests at `apps/api/src/ipns/delegated-routing.client.spec.ts` cover retry logic. No integration tests against real service. + +**Web3Auth MPC Core Kit integration:** + +- Files: `apps/web/src/lib/web3auth/core-kit.ts`, `apps/web/src/lib/web3auth/hooks.ts` (multiple `as any` casts), `apps/web/src/hooks/useAuth.ts` (522 lines) +- Why fragile: Web3Auth SDK has poor TypeScript definitions (`any` casts required). The `REQUIRED_SHARE` state handling at `hooks.ts:205-226` works around a bug where Web3Auth doesn't auto-check localStorage for device factors. SDK version upgrades frequently change behavior. +- Safe modification: Test all auth flows (email, Google, wallet) end-to-end after any Web3Auth dependency update. +- Test coverage: Auth flow tested via E2E (`tests/e2e/tests/full-workflow.spec.ts`) but Web3Auth unit mocking is complex. ## Scaling Limits -**Folder metadata size:** -- Current capacity: Stress test option for N children (`STRESS_CHILDREN_COUNT`) -- Limit: 1,000 files per folder per PRD.md constraints -- Scaling path: Already documented; enforce in production API +**IPNS record propagation and TEE republishing:** -**File size limit:** -- Current capacity: 100 MB per file (PRD constraint) -- Limit: Browser memory limits for encryption -- Scaling path: v1.1 streaming encryption with CTR mode +- Current capacity: TEE republishes all enrolled IPNS records every 6 hours via batch endpoint. +- Limit: At 1000+ enrolled records per user, republish cycles may exceed the 3-hour window. The `delete.service.ts:28` documents this threshold. +- Scaling path: Implement IPNS unenrollment on deletion (see Tech Debt section). Consider per-user republish prioritization. -**Storage quota:** -- Current capacity: 500 MiB free tier (PRD constraint) -- Limit: Pinata cost management -- Scaling path: v1.1 billing integration for paid tiers +**Folder metadata size (1000 files per folder):** + +- Current capacity: PRD constrains to 1000 children per folder. +- Limit: Metadata blob grows linearly with children count. With FilePointers (~100 bytes each), a 1000-file folder produces ~100 KB of metadata before encryption. +- Scaling path: This limit is enforced by design. For larger collections, users must create subfolders. + +**File size limit (100 MB with GCM):** + +- Current capacity: 100 MB per file per PRD constraint. +- Limit: Browser memory pressure with full-file buffering for GCM encryption. +- Scaling path: CTR streaming encryption is implemented but not yet the default for uploads. Switching to CTR for large files would remove the memory constraint. + +**Single Kubo IPFS node:** + +- Current capacity: One Kubo node handles all pinning/unpinning for the entire deployment. +- Limit: Single point of failure. Kubo node downtime = no uploads or downloads. +- Scaling path: Add IPFS cluster for redundancy, or migrate to a managed IPFS pinning service (Pinata, web3.storage). ## Dependencies at Risk -**ipfs-http-client@60.0.1:** -- Risk: Already showing API incompatibilities (routing API disabled) -- Impact: Cannot use newer IPFS features; may become incompatible with updated nodes -- Migration plan: Consider migrating to @helia/ipns for IPNS operations; ipfs-http-client is deprecated +**delegated-ipfs.dev (external service):** + +- Risk: Third-party service with documented unreliability. No SLA. Single point of failure for IPNS operations. +- Impact: If down, no IPNS records can be published or resolved. File metadata becomes temporarily inaccessible. +- Migration plan: DB-cached CID fallback exists for resolution. Consider self-hosting a delegated routing endpoint or adding a secondary provider. -**eciesjs@0.4.7:** -- Risk: Small package with limited maintenance -- Impact: Core security dependency for key wrapping -- Migration plan: Evaluate alternatives like eth-crypto or implement ECIES directly with noble/secp256k1 +**Web3Auth MPC Core Kit (@web3auth/mpc-core-kit@^3.5.0):** -**@noble/secp256k1@2.1.0:** -- Risk: Low risk; well-maintained -- Impact: Core dependency for key derivation -- Migration plan: Keep updated; audit-friendly +- Risk: Complex SDK with frequent breaking changes. Poor TypeScript types require `any` casts. Authentication is entirely dependent on Web3Auth infrastructure. +- Impact: SDK updates may break auth flows. Web3Auth service downtime = no new logins (existing sessions continue via refresh tokens). +- Migration plan: The auth architecture separates Web3Auth (key derivation) from CipherBox auth (JWT tokens). A migration to a different MPC provider would require replacing only the Web3Auth integration layer. + +**eciesjs@^0.4.16:** + +- Risk: Small package with limited maintenance activity. Used for ECIES key wrapping (core security function). +- Impact: Security vulnerability in this package would compromise key wrapping. +- Migration plan: The package wraps noble/secp256k1 internally. Could be replaced with direct ECIES implementation using noble primitives. + +**FUSE-T (macOS userspace filesystem):** + +- Risk: Third-party macOS filesystem driver. Not a standard macOS component. Requires user installation. +- Impact: macOS updates can break FUSE-T. The NFS-to-SMB backend switch was forced by a macOS Sequoia kernel bug. +- Migration plan: Monitor FUSE-T releases. Linux build uses kernel FUSE (more stable). Consider FileProvider API on macOS as long-term alternative. ## Missing Critical Features -**No automated tests:** -- Problem: Zero test files (no .test.ts or .spec.ts files found) -- Blocks: Cannot verify correctness; cannot refactor safely; 85% coverage target unreachable -- Files: No test configuration (no jest.config.*, vitest.config.*) +**No offline support (web or desktop):** -**No error recovery:** -- Problem: POC stops on first error; no retry logic for IPFS operations -- Blocks: Unreliable in production network conditions -- Files: `00-Preliminary-R&D/poc/src/index.ts:699-702` (main catches and exits) +- Problem: No service worker for offline caching in web app. Desktop FUSE mount requires continuous API connectivity. +- Blocks: Users cannot access files when offline. Desktop mount becomes unresponsive without network. +- Files: No service worker files exist (only a streaming-media SW at `apps/web/src/main.tsx:39`). Desktop FUSE operations fail with EIO on network errors. -**No offline support:** -- Problem: POC requires continuous IPFS connectivity -- Blocks: Desktop FUSE mount usability when offline -- Files: Per roadmap, Week 10 includes "Offline queueing (retry on reconnect)" +**No file versioning:** -**No Web3Auth integration:** -- Problem: POC uses local .env key; no actual Web3Auth flow -- Blocks: Multi-auth method validation; group connections testing +- Problem: Overwriting a file replaces the previous version entirely. No version history. +- Blocks: No undo for accidental overwrites. Out of scope for v1.0 per CLAUDE.md. +- Files: `apps/web/src/hooks/useFileVersions.ts` handles IPNS-based file metadata updates but not version history. -**No backend API implementation:** -- Problem: API spec exists but no NestJS backend code -- Blocks: 15 endpoints defined in API_SPECIFICATION.md have no implementation +**No monitoring/observability (web app):** -**No TEE integration:** -- Problem: TEE architecture designed but no Phala/Nitro integration -- Blocks: IPNS auto-republishing (core availability feature) +- Problem: Web app has no error tracking service (Sentry, etc.). Errors are logged to `console.error` and lost. +- Blocks: Cannot detect or diagnose production issues affecting users. API has Prometheus metrics (`apps/api/src/metrics/`) but web has nothing. +- Files: `apps/web/src/main.tsx:9-14` wraps `console.error` but only for in-memory display. ## Test Coverage Gaps -**Crypto operations not tested:** -- What's not tested: AES-256-GCM encryption/decryption, ECIES key wrapping, key derivation -- Files: `00-Preliminary-R&D/poc/src/index.ts:101-136` -- Risk: Crypto bugs could cause data loss or security vulnerabilities -- Priority: High - -**IPNS publish/resolve not tested:** -- What's not tested: IPNS record creation, signing, resolution -- Files: `00-Preliminary-R&D/poc/src/index.ts:157-190` -- Risk: Core sync mechanism could fail silently -- Priority: High - -**Folder metadata encryption not tested:** -- What's not tested: Metadata serialization, encryption, decryption -- Files: `00-Preliminary-R&D/poc/src/index.ts:138-147` -- Risk: Data structure changes could break compatibility -- Priority: High - -**Edge cases not tested:** -- What's not tested: Empty folders, max depth, max files, concurrent operations -- Files: Entire codebase -- Risk: Production failures under edge conditions -- Priority: Medium +**Web app has minimal unit tests (4 test files for 269 source files):** + +- What's not tested: All React components, most hooks, all services except sync store. +- Files: Only 4 test files exist: `apps/web/src/stores/__tests__/sync-store.test.ts`, `apps/web/src/stores/__tests__/upload-error-recovery.test.ts`, `apps/web/src/stores/__tests__/logout-security.test.ts`, `apps/web/src/lib/api/__tests__/client-refresh.test.ts` +- Risk: Regressions in folder operations, file uploads, auth flows, sharing, and bin operations go undetected until E2E tests or manual testing. The 964-line `FileBrowser.tsx` has zero test coverage. +- Priority: High. Focus first on services (`folder.service.ts`, `bin.service.ts`, `share.service.ts`) and critical hooks (`useAuth.ts`, `useFolderMutations.ts`). + +**TEE worker has zero tests:** + +- What's not tested: IPNS signing, key management, epoch rotation, auth middleware. +- Files: `tee-worker/src/` (522 lines total, 0 test files) +- Risk: Security-critical code (TEE key derivation, IPNS record signing) is untested. Regressions in epoch rotation or key decryption would silently break republishing. +- Priority: High. The TEE worker handles decrypted IPNS private keys -- correctness is security-critical. + +**Desktop FUSE operations have no automated tests:** + +- What's not tested: All filesystem operations (read, write, create, rename, delete, mkdir), inode management, metadata caching, publish coordination. +- Files: `apps/desktop/src-tauri/src/fuse/mod.rs` (1803 lines), `apps/desktop/src-tauri/src/fuse/write_ops.rs` (976 lines), `apps/desktop/src-tauri/src/fuse/inode.rs` (937 lines). Only `apps/desktop/src-tauri/src/crypto/tests.rs` (1717 lines) covers the crypto layer. +- Risk: FUSE bugs cause data loss or mount crashes. The single-thread constraint makes race conditions subtle. Manual testing is the only verification. +- Priority: High. At minimum, add unit tests for `InodeTable` operations and `PublishCoordinator` logic. + +**Windows FUSE operations untested:** + +- What's not tested: All 2824 lines of Windows-specific FUSE code using WinFSP. +- Files: `apps/desktop/src-tauri/src/fuse/windows/` (5 files) +- Risk: Platform-specific bugs (mutex poisoning from `lock().unwrap()`, different filesystem semantics) undetected. +- Priority: Medium. Windows support appears to be secondary to macOS. + +**E2E test helpers are stubs:** + +- What's not tested: API helper functions for test setup are placeholder implementations. +- Files: `tests/e2e/utils/api-helpers.ts:5-45` (3 TODO functions: `createTestUser`, `cleanupVault`, `seedTestFiles`) +- Risk: E2E tests cannot programmatically set up complex test scenarios. Limited to UI-driven flows only. +- Priority: Medium. Implement API helpers as more complex E2E scenarios are needed. --- -*Concerns audit: 2026-01-20* +Concerns audit: 2026-03-06 diff --git a/.planning/codebase/INTEGRATIONS.md b/.planning/codebase/INTEGRATIONS.md index 971162e1ab..847ee0eefd 100644 --- a/.planning/codebase/INTEGRATIONS.md +++ b/.planning/codebase/INTEGRATIONS.md @@ -1,178 +1,177 @@ # External Integrations -**Analysis Date:** 2026-01-20 +**Analysis Date:** 2026-03-06 ## Project Status -CipherBox is a **technology demonstrator** with integrations split between: -- **Implemented (PoC)**: Local IPFS daemon, optional Pinata -- **Planned (Production)**: Web3Auth, PostgreSQL, Pinata, TEE providers +CipherBox is a **technology demonstrator** with the following integrations implemented: + +- **IPFS (Kubo)**: File storage and IPNS publishing (`apps/api/src/ipfs/`) +- **Web3Auth MPC Core Kit**: Authentication and key derivation (`apps/web/src/lib/web3auth/`) +- **PostgreSQL**: User/vault metadata storage (`apps/api/src/`) +- **Redis/BullMQ**: Job queue for background tasks (`apps/api/src/`) +- **TEE (Phala Cloud)**: IPNS republishing (`tee-worker/`) ## APIs & External Services -**IPFS/IPNS (Implemented in PoC):** +**IPFS/IPNS (Implemented):** + - Local IPFS daemon (Kubo) - File storage and IPNS publishing - - SDK/Client: `ipfs-http-client` 60.0.1 - - Connection: `IPFS_API_URL` env var (default: http://127.0.0.1:5001) - - Gateway: `IPFS_GATEWAY_URL` env var (optional) - - Usage: `00-Preliminary-R&D/poc/src/index.ts` - -**Pinata (Implemented in PoC, optional):** -- Remote IPFS pinning service - Persistent file storage - - SDK/Client: Native `fetch` API - - Auth: `PINATA_API_KEY`, `PINATA_API_SECRET` env vars - - Toggle: `PINATA_ENABLED=true` - - Endpoints used: - - `POST https://api.pinata.cloud/pinning/pinByHash` - Pin CID - - `DELETE https://api.pinata.cloud/pinning/unpin/{cid}` - Unpin CID - - Usage: `pinataPin()`, `pinataUnpin()` in `00-Preliminary-R&D/poc/src/index.ts` - -**Web3Auth (Planned - Not Implemented):** + - Provider: `apps/api/src/ipfs/providers/local.provider.ts` + - Connection: `KUBO_API_URL` env var (default: `http://127.0.0.1:5001`) + - Upload: `POST /ipfs/upload` (multipart/form-data, field `file`) + - Fetch: `GET /ipfs/:cid` + - Unpin: `POST /ipfs/unpin` + +- Delegated routing (delegated-ipfs.dev) - IPNS record publishing and resolution + - Client: `apps/api/src/ipns/delegated-routing.client.ts` + - Publish: `POST /ipns/publish`, `POST /ipns/publish-batch` + - Resolve: `GET /ipns/resolve` + - Retry: Exponential backoff (3 retries, 1s base, 30s cap) + +**Web3Auth (Implemented):** + - Authentication and key derivation - User identity - - SDK/Client: `@web3auth/modal` (planned) - - Auth methods: Google, Apple, GitHub, Email, Magic Link, External Wallet + - SDK/Client: `@web3auth/mpc-core-kit` (`apps/web/src/lib/web3auth/`) + - Auth methods: Email OTP, Google OAuth, Magic Link, External Wallet - JWKS endpoint: `https://api-auth.web3auth.io/jwks` - - Key feature: Group connections for deterministic keypair derivation - - Spec: `00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md` Section 2 + - Backend validation: `apps/api/src/auth/strategies/web3auth-jwt.strategy.ts` + - Key feature: MPC-based deterministic keypair derivation with device factor MFA + +**TEE Providers (Implemented):** -**TEE Providers (Planned - Not Implemented):** - Trusted Execution Environment for IPNS republishing -**Phala Cloud (Primary):** +**Phala Cloud (Primary — Implemented):** + - TEE-based IPNS key decryption and signing - - Cost: ~$0.10/hr - - Features: Intel SGX hardware attestation, on-chain verification - - Latency: 12-30s per republish - - Spec: `00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md` Section 9 + - Worker: `tee-worker/src/` + - Features: Intel SGX hardware attestation + - Schedule: Every 6 hours via backend cron + - Enrollment: `apps/api/src/republish/republish.service.ts` + +**AWS Nitro Enclaves (Planned Fallback):** -**AWS Nitro Enclaves (Fallback):** -- Backup TEE provider - - Cost: ~$0.17-0.50/hr - - Features: AWS custom silicon, AWS attestation API - - Latency: <100ms per republish +- Backup TEE provider (not yet implemented) ## Data Storage -**Databases (Planned):** -- PostgreSQL - User accounts, vaults, tokens, audit logs - - Tables: users, refresh_tokens, auth_nonces, vaults, volume_audit, pinned_cids, ipns_republish_schedule, tee_key_state, tee_key_rotation_log, ipfs_operations_log - - Spec: `00-Preliminary-R&D/Documentation/API_SPECIFICATION.md` Section 4 +**PostgreSQL (Implemented):** -**File Storage:** -- IPFS Network - Encrypted file content (decentralized) -- Pinata - Managed pinning (ensures availability) -- Local filesystem (PoC only) - State persistence in `./state/` +- User accounts, vaults, tokens, audit logs + - ORM: TypeORM (`apps/api/src/`) + - Migrations: `apps/api/src/migrations/` + - Key entities: users, vaults, refresh_tokens, pinned_cids, ipns_republish_schedule, shares, device_approvals + - Protocol: `docs/DATABASE_EVOLUTION_PROTOCOL.md` + +**Redis (Implemented):** + +- BullMQ job queue for background tasks + - Connection: `REDIS_URL` env var + - Used by: `apps/api/src/` for async job processing + +**IPFS (Implemented):** + +- Encrypted file content storage (decentralized) + - Kubo node for pinning and availability + - All content is ciphertext (zero-knowledge) **Caching:** -- None implemented in PoC -- Planned: In-memory metadata cache, disk-based encrypted content cache (desktop) + +- API: In-memory IPNS resolution cache with DB-cached CID fallback +- Desktop: In-memory metadata cache with background refresh (`apps/desktop/src-tauri/src/fuse/`) ## Authentication & Identity -**Auth Provider (Planned):** -- Web3Auth - Primary authentication - - Implementation: Two-phase auth (Web3Auth + CipherBox backend) +**Web3Auth (Implemented):** + +- Primary authentication and key derivation + - Implementation: Two-phase auth (Web3Auth MPC Core Kit + CipherBox backend JWT) - Token types: - Web3Auth ID Token (1 hour) - For backend authentication - CipherBox Access Token (15 min) - API authorization - CipherBox Refresh Token (7 days) - Token renewal - - Spec: `00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md` Section 2 + - Details: `docs/AUTHENTICATION_ARCHITECTURE.md` + +**Test Authentication (Dev/Staging Only):** -**PoC Authentication:** -- Local private key from `.env` - No external auth -- secp256k1 keypair derived locally using `@noble/secp256k1` +- `POST /auth/test-login` - Bypasses real auth for E2E testing + - Guarded by `TEST_LOGIN_SECRET` env var and `NODE_ENV !== 'production'` ## Monitoring & Observability -**Error Tracking:** -- None implemented +**API Metrics (Implemented):** + +- Prometheus metrics: `apps/api/src/metrics/` +- Health check: `GET /health` + +**Web App:** + +- No error tracking service (see CONCERNS.md) +- Console logging only **Logs:** -- Console logging only (PoC) -- Planned: `ipfs_operations_log` table for IPFS/IPNS operation tracking -**Monitoring (Planned):** -- Republish success rate monitoring -- TEE response latency tracking -- Epoch rotation lag monitoring +- API: NestJS structured logger +- Web: Console.\* calls (tech debt) +- Desktop: Rust `log` crate ## CI/CD & Deployment -**Hosting:** -- Not deployed (PoC runs locally) -- Planned: Web app hosting TBD, Backend hosting TBD +**CI Pipeline (Implemented):** + +- GitHub Actions (`.github/workflows/`) + - `ci.yml` - Lint, typecheck, unit tests on PRs + - `ci-e2e.yml` - Playwright E2E tests on `main` pushes + - `deploy-staging.yml` - Deploy on `v*-staging*` tags + - `release-please.yml` - Automated releases on `main` + +**Staging (Implemented):** + +- VPS: 76.13.151.200 (Hostinger) +- API: `https://api-staging.cipherbox.cc` +- Web: `https://app-staging.cipherbox.cc` +- Deploy: Push tag `v-staging-rc-` + +**Production:** -**CI Pipeline:** -- GitHub Actions (`.github/` directory present, contents not examined) +- Not yet deployed ## Environment Configuration -**Required env vars (PoC):** -- `ECDSA_PRIVATE_KEY` - 32-byte hex string (no 0x prefix) - -**Optional env vars (PoC):** -- `IPFS_API_URL` - IPFS daemon endpoint -- `IPFS_GATEWAY_URL` - IPFS gateway URL -- `PINATA_ENABLED` - Enable Pinata integration -- `PINATA_API_KEY` - Pinata authentication -- `PINATA_API_SECRET` - Pinata authentication -- `POC_STATE_DIR` - State persistence directory -- `IPNS_POLL_INTERVAL_MS` - Polling interval (default: 1500) -- `IPNS_POLL_TIMEOUT_MS` - Polling timeout (default: 120000) -- `STRESS_CHILDREN_COUNT` - Stress testing (default: 0) -- `STRESS_CHILD_TYPE` - Stress test type (file/folder) +**API (`apps/api/.env.example`):** + +- `DB_HOST`, `DB_PORT`, `DB_USERNAME`, `DB_PASSWORD`, `DB_DATABASE` - PostgreSQL connection +- `REDIS_HOST`, `REDIS_PORT` - Redis connection (for BullMQ) +- `IPFS_LOCAL_API_URL`, `IPFS_LOCAL_GATEWAY_URL` - IPFS Kubo daemon endpoints +- `JWT_SECRET` - Access token signing +- `CORS_ALLOWED_ORIGINS` - Allowed origins (comma-separated, supports wildcards) +- `DELEGATED_ROUTING_URL` - IPNS delegated routing endpoint +- `TEE_WORKER_URL`, `TEE_WORKER_SECRET` - TEE worker connection +- `SENDGRID_API_KEY`, `SENDGRID_FROM_EMAIL` - Email OTP delivery + +**Web (`apps/web/.env.example`):** + +- `VITE_API_URL` - Backend API URL +- `VITE_WEB3AUTH_CLIENT_ID` - Web3Auth project ID +- `VITE_WEB3AUTH_VERIFIER` - Web3Auth verifier name **Secrets location:** -- `.env` file (local development) -- Environment variables (production, planned) + +- `.env` files (local development) +- GitHub Actions secrets/vars (CI/CD) +- Docker Compose `.env` (staging) ## Webhooks & Callbacks **Incoming:** + - None **Outgoing:** -- None -## IPFS/IPNS Integration Details - -**IPFS Operations (from PoC):** -```typescript -// Adding content -const { cid } = await ctx.ipfs.add(content, { pin: false }); - -// Fetching content -const data = await collectChunks(ctx.ipfs.cat(cid)); - -// Pinning -await ctx.ipfs.pin.add(cid); -await ctx.ipfs.pin.rm(cid); - -// Key management -await ctx.ipfs.key.gen(keyName, { type: "ed25519" }); -await ctx.ipfs.key.rm(keyName); -``` - -**IPNS Operations (from PoC):** -```typescript -// Publishing -await ctx.ipfs.name.publish(`/ipfs/${cid}`, { - key: ipnsKeyName, - allowOffline: true, -}); - -// Resolving -for await (const result of ctx.ipfs.name.resolve(ipnsName, { nocache: true })) { - // Extract CID from result -} -``` - -**Production Relay Model (Planned):** -- Client signs IPNS records locally -- Backend relays signed records to IPFS network -- Backend never sees plaintext IPNS private keys -- Spec: `00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md` Section 5 +- None --- -*Integration audit: 2026-01-20* +Integration audit: 2026-03-06 diff --git a/.planning/codebase/STACK.md b/.planning/codebase/STACK.md index 5410a9785c..c25ecebbf8 100644 --- a/.planning/codebase/STACK.md +++ b/.planning/codebase/STACK.md @@ -1,131 +1,157 @@ # Technology Stack -**Analysis Date:** 2026-01-20 +**Analysis Date:** 2026-03-06 ## Project Status -CipherBox is a **technology demonstrator** in early development. Currently, only a **Proof of Concept (PoC) console harness** exists in `/00-Preliminary-R&D/poc/`. The full production system (web app, desktop app, backend) is specified in documentation but not yet implemented. +CipherBox is a **technology demonstrator** with a working implementation. The web app (`apps/web/`), backend API (`apps/api/`), desktop app (`apps/desktop/`), shared crypto library (`packages/crypto/`), TEE worker (`tee-worker/`), and E2E test suites (`tests/e2e/`, `tests/e2e-desktop/`) are all implemented. The original PoC console harness remains in `00-Preliminary-R&D/poc/` for historical reference only. ## Languages **Primary:** -- TypeScript 5.4.x - All application code (PoC, planned web/desktop/backend) + +- TypeScript 5.7+ - All application code (web, API, desktop frontend, crypto, TEE worker) **Secondary:** + +- Rust - Desktop FUSE filesystem (`apps/desktop/src-tauri/`) +- SQL - PostgreSQL migrations (`apps/api/src/migrations/`) - JavaScript (ES2022) - Compilation target -- SQL - PostgreSQL database schema (planned) -- Rust - TEE/Phala Cloud workloads (planned, referenced in spec) ## Runtime **Environment:** -- Node.js 20+ - PoC requires Node 20+ -- Browser (Chrome/Firefox/Safari) - Web app (planned) -- Tauri/Electron - Desktop app (planned) + +- Node.js 20+ - Backend API and build tooling +- Browser (Chrome/Firefox/Safari) - Web app +- Tauri v2 (WebView + Rust) - Desktop app (macOS, Windows) **Package Manager:** -- npm/yarn - `yarn.lock` present in PoC -- Lockfile: present at `00-Preliminary-R&D/poc/yarn.lock` + +- pnpm 9+ - Workspace-based monorepo management +- Lockfile: `pnpm-lock.yaml` at workspace root ## Frameworks -**PoC (Current):** -- No framework - Raw Node.js + TypeScript -- `tsx` 4.7.1 - TypeScript execution +**Web App (`apps/web/`):** -**Planned Web App:** - React 18 - Frontend framework - Tailwind CSS - Styling -- Axios - HTTP client +- Vite - Build tooling and dev server +- Zustand - State management + +**Backend (`apps/api/`):** + +- NestJS - Backend framework +- TypeORM - Database ORM with migrations +- BullMQ + Redis - Job queue for background tasks +- Passport - Authentication strategies -**Planned Backend:** -- NestJS - Backend framework (Node.js) -- jose - JWT verification +**Desktop (`apps/desktop/`):** -**Planned Desktop:** -- Tauri (preferred) or Electron - Desktop shell -- macFUSE/FUSE3/WinFSP - Filesystem mount +- Tauri v2 - Desktop shell (Rust + WebView) +- FUSE-T (SMB backend) - Virtual filesystem mount (macOS) +- WinFSP - Virtual filesystem (Windows) +- Vendored fuser crate - FUSE bindings with socket-read patch **Build/Dev:** -- TypeScript 5.4.2 - Type checking and compilation -- ESLint 8.57.0 - Linting -- tsx 4.7.1 - Dev execution + +- TypeScript 5.7+ - Type checking and compilation +- ESLint 9 - Linting (flat config) +- Vitest - Unit testing (web, crypto) +- Jest - Unit testing (API) +- Playwright - E2E testing ## Key Dependencies -**PoC Critical (from `00-Preliminary-R&D/poc/package.json`):** -- `ipfs-http-client` 60.0.1 - IPFS node communication -- `eciesjs` 0.4.7 - ECIES encryption (secp256k1) -- `@noble/secp256k1` 2.1.0 - Public key derivation -- `dotenv` 16.4.5 - Environment configuration - -**PoC Dev Dependencies:** -- `@types/node` 20.19.30 - Node.js type definitions -- `typescript` 5.4.2 - TypeScript compiler -- `tsx` 4.7.1 - TypeScript execution -- `eslint` 8.57.0 - Linting - -**Planned Production:** -- `@web3auth/modal` - Auth and key derivation -- `jose` - JWT verification (backend) -- PostgreSQL client - Database access (backend) -- `winston` - Structured logging framework (backend) -- `nest-winston` - NestJS Winston integration (backend) -- Datadog/Splunk transport - Log aggregation for dev/prod environments +**Cryptography:** + +- `eciesjs` ^0.4.16 - ECIES encryption (secp256k1 key wrapping) +- `@noble/secp256k1` - Public key derivation +- `@noble/ed25519` - Ed25519 IPNS record signing +- Web Crypto API - AES-256-GCM/CTR encryption, HKDF-SHA256 key derivation + +**Authentication:** + +- `@web3auth/mpc-core-kit` ^3.5.0 - MPC-based auth and deterministic keypair derivation +- `jose` - JWT verification (backend JWKS validation) +- `@simplewebauthn/*` - WebAuthn/passkey support + +**IPFS/IPNS:** + +- Kubo HTTP API - File storage and pinning (via `apps/api/src/ipfs/providers/local.provider.ts`) +- delegated-ipfs.dev - IPNS record publishing and resolution + +**Desktop (Rust):** + +- `fuser` (vendored) - FUSE bindings with FUSE-T socket-read patch +- `winfsp` - Windows filesystem in userspace +- `reqwest` - HTTP client for API calls +- `keyring` - OS keychain for token storage +- `tauri` v2 - Desktop app framework ## Configuration **Environment:** -- `.env` file for local configuration -- Environment variables for sensitive data -- Key configs from `00-Preliminary-R&D/poc/.env.example`: - - `ECDSA_PRIVATE_KEY` - Required, 32-byte hex - - `IPFS_API_URL` - IPFS daemon endpoint (default: http://127.0.0.1:5001) - - `IPFS_GATEWAY_URL` - IPFS gateway for reads - - `PINATA_ENABLED`, `PINATA_API_KEY`, `PINATA_API_SECRET` - Remote pinning - - `POC_STATE_DIR` - Local state persistence - - `IPNS_POLL_INTERVAL_MS`, `IPNS_POLL_TIMEOUT_MS` - Polling config - -**TypeScript (from `00-Preliminary-R&D/poc/tsconfig.json`):** + +- `.env` files for local configuration (see `apps/api/.env.example`, `apps/web/.env.example`) +- GitHub Actions secrets/vars for CI/CD +- Docker Compose `.env` for staging + +**TypeScript:** + - Target: ES2022 -- Module: ES2022 +- Module: ES2022 / ESNext (varies by workspace) - ModuleResolution: Bundler -- Strict mode enabled -- Output: `dist/` +- Strict mode enabled across all workspaces + +**Build Commands:** -**Build:** -- `npm start` or `yarn start` - Run PoC via tsx -- `npm run build` - Compile TypeScript -- `npm run lint` - Run ESLint +- `pnpm dev` - Start all dev servers +- `pnpm --filter api dev` - API dev server () +- `pnpm --filter web dev` - Web dev server () +- `pnpm --filter desktop tauri dev` - Desktop dev +- `pnpm test` - Run unit tests (all workspaces) +- `pnpm typecheck` - TypeScript type checking +- `pnpm api:generate` - Regenerate API client from OpenAPI spec ## Cryptography Stack **Symmetric Encryption:** -- AES-256-GCM - File and metadata encryption (via Node.js `crypto`) -- AES-256-CTR - Planned for streaming (v1.1+) + +- AES-256-GCM - File and metadata encryption (Web Crypto API) +- AES-256-CTR - Streaming encryption for large files and media playback (Web Crypto API) **Asymmetric Encryption:** + - ECIES (secp256k1) - Key wrapping via `eciesjs` -- ECDSA (secp256k1) - Key derivation via Web3Auth (planned) -- Ed25519 - IPNS record signing (planned, via `libsodium.js`) +- ECDSA (secp256k1) - Keypair from Web3Auth MPC Core Kit +- Ed25519 - IPNS record signing via `@noble/ed25519` **Key Derivation:** -- HKDF-SHA256 - Key derivation (planned) -- SHA-256 - Hashing + +- HKDF-SHA256 - Deterministic IPNS keypair derivation from user's private key (Web Crypto API) +- Random generation - Content encryption keys (file keys, folder keys) via `crypto.getRandomValues()` ## Platform Requirements **Development:** + - Node.js 20+ -- Local IPFS daemon (Kubo) with HTTP API enabled -- npm or yarn +- pnpm 9+ +- PostgreSQL 16 (Docker or local) +- Redis (Docker or local) +- IPFS Kubo node with HTTP API enabled + +**Staging/Production:** -**Production (Planned):** +- Docker Compose for orchestration - PostgreSQL database -- Pinata API account (IPFS pinning) +- Redis instance +- IPFS Kubo node - Web3Auth project (auth) -- TEE provider (Phala Cloud primary, AWS Nitro fallback) +- Phala Cloud TEE worker (IPNS republishing) --- -*Stack analysis: 2026-01-20* +Stack analysis: 2026-03-06 diff --git a/.planning/codebase/STRUCTURE.md b/.planning/codebase/STRUCTURE.md index c885e7b154..8c50641908 100644 --- a/.planning/codebase/STRUCTURE.md +++ b/.planning/codebase/STRUCTURE.md @@ -4,7 +4,7 @@ ## Directory Layout -``` +```text cipher-box/ ├── .claude/ # Claude AI configuration and commands │ ├── agents/ # Agent definitions @@ -37,9 +37,8 @@ cipher-box/ │ ├── state/ # Runtime state directory │ ├── package.json # PoC dependencies │ └── tsconfig.json # TypeScript config -├── 00_START_HERE.md # Quick-start overview document -├── README.md # Project overview and architecture -├── LICENSE # Apache 2.0 license +├── README.md # Project overview, features, getting started +├── LICENSE # MIT license ├── .gitignore # Git ignore patterns └── cipherbox logo.png # Project logo asset ``` @@ -47,21 +46,25 @@ cipher-box/ ## Directory Purposes **`.claude/`:** + - Purpose: Claude AI project configuration and GSD workflow framework - Contains: Agent definitions, custom commands, templates, workflow configs - Key files: `CLAUDE.md` (project rules), `commands/gsd/` (workflow commands) **`.planning/codebase/`:** + - Purpose: Codebase analysis documents generated by GSD mapping - Contains: Architecture, structure, conventions, testing, concerns analysis - Key files: `ARCHITECTURE.md`, `STRUCTURE.md` (this file) **`00-Preliminary-R&D/Documentation/`:** + - Purpose: Finalized v1.11.1 specification documents (DO NOT MODIFY) - Contains: Complete system design across 6 documents - Key files: `TECHNICAL_ARCHITECTURE.md` (encryption, security), `API_SPECIFICATION.md` (15 endpoints) **`00-Preliminary-R&D/poc/`:** + - Purpose: Console-based proof-of-concept validating IPFS/IPNS flows - Contains: Single TypeScript file demonstrating encryption and file operations - Key files: `src/index.ts` (703 lines, complete validation harness) @@ -69,17 +72,21 @@ cipher-box/ ## Key File Locations **Entry Points:** + - `00-Preliminary-R&D/poc/src/index.ts`: PoC console harness main entry **Configuration:** + - `00-Preliminary-R&D/poc/package.json`: PoC dependencies and scripts - `00-Preliminary-R&D/poc/tsconfig.json`: TypeScript compiler config - `.claude/CLAUDE.md`: Project rules for Claude AI **Core Logic:** + - `00-Preliminary-R&D/poc/src/index.ts`: All PoC encryption, IPFS, and folder operations **Specifications:** + - `00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md`: Encryption, key hierarchy, TEE - `00-Preliminary-R&D/Documentation/API_SPECIFICATION.md`: Backend endpoints, database schema - `00-Preliminary-R&D/Documentation/CLIENT_SPECIFICATION.md`: Web UI, desktop app specs @@ -88,22 +95,27 @@ cipher-box/ - `00-Preliminary-R&D/Documentation/IMPLEMENTATION_ROADMAP.md`: 12-week development plan **Documentation:** -- `00_START_HERE.md`: Quick overview with key decisions -- `README.md`: Full project overview and architecture summary + +- `README.md`: Project overview, features, getting started +- `docs/ARCHITECTURE.md`: Encryption hierarchy, key derivation, threat model +- `docs/DEVELOPMENT.md`: Local setup, running, testing ## Naming Conventions **Files:** + - Specification docs: `UPPERCASE_SNAKE.md` (e.g., `TECHNICAL_ARCHITECTURE.md`) - Source files: `lowercase.ts` (e.g., `index.ts`) - Config files: `lowercase.json` (e.g., `package.json`, `tsconfig.json`) **Directories:** + - Numbered prefix for ordering: `00-Preliminary-R&D/` (stage indicator) - Lowercase with hyphens for standard dirs: `.planning/`, `.claude/` - PascalCase for specification subdir: `Documentation/` **Code (from PoC and spec):** + - Types: `PascalCase` (e.g., `FolderEntry`, `FileEntry`, `HarnessContext`) - Functions: `camelCase` (e.g., `aesGcmEncrypt`, `publishFolderMetadata`) - Constants: `UPPER_SNAKE_CASE` (e.g., `TAG_SIZE`, `IV_SIZE`) @@ -113,74 +125,86 @@ cipher-box/ ## Where to Add New Code **New Backend Feature:** -- Primary code: Create `backend/` directory at root + +- Primary code: Add modules under `apps/api/src/` - Spec reference: `00-Preliminary-R&D/Documentation/API_SPECIFICATION.md` - Pattern: NestJS modules with controllers, services, entities **New Frontend Feature:** -- Primary code: Create `frontend/` directory at root + +- Primary code: Add components/pages under `apps/web/src/` - Spec reference: `00-Preliminary-R&D/Documentation/CLIENT_SPECIFICATION.md` - Pattern: React 18 with TypeScript, Web Crypto API **New Desktop Feature:** -- Primary code: Create `desktop/` directory at root + +- Primary code: Add code under `apps/desktop/` (Tauri frontend) or `apps/desktop/src-tauri/` (Rust backend) - Spec reference: `00-Preliminary-R&D/Documentation/CLIENT_SPECIFICATION.md` (Section 2) -- Pattern: Tauri or Electron with FUSE integration +- Pattern: Tauri v2 with FUSE-T integration **Extending PoC:** + - Implementation: `00-Preliminary-R&D/poc/src/index.ts` - Note: PoC is validation-only, not production code **New Utility/Helper:** -- Shared helpers: Create `shared/` or `common/` at root (when implementing) + +- Shared helpers: Add to `packages/crypto/` or create a new package under `packages/` - PoC utilities: Add to `00-Preliminary-R&D/poc/src/` (if extending PoC) **New Specification:** + - Location: `00-Preliminary-R&D/Documentation/` - Warning: Existing specs are finalized (v1.11.1) - create new docs for changes **Planning/Analysis Documents:** + - Location: `.planning/` (e.g., `.planning/codebase/`, `.planning/phases/`) ## Special Directories **`00-Preliminary-R&D/Documentation/`:** + - Purpose: Finalized specification documents - Generated: No (manually authored) - Committed: Yes - Note: DO NOT MODIFY - create new implementation docs elsewhere **`00-Preliminary-R&D/poc/dist/`:** + - Purpose: Compiled JavaScript output from TypeScript - Generated: Yes (`npm run build`) - Committed: Varies (typically no) **`00-Preliminary-R&D/poc/node_modules/`:** + - Purpose: npm dependencies - Generated: Yes (`npm install`) - Committed: No (in .gitignore) **`00-Preliminary-R&D/poc/state/`:** + - Purpose: Runtime state for PoC harness - Generated: Yes (during PoC execution) - Committed: No **`.planning/codebase/`:** + - Purpose: GSD codebase mapping outputs - Generated: Yes (by GSD workflow) - Committed: Yes ## Implementation Status -| Component | Spec Location | Implementation | Status | -|-----------|---------------|----------------|--------| -| Backend API | `API_SPECIFICATION.md` | Not created | Planned | -| Web Frontend | `CLIENT_SPECIFICATION.md` | Not created | Planned | -| Desktop App | `CLIENT_SPECIFICATION.md` | Not created | Planned | -| TEE Integration | `TECHNICAL_ARCHITECTURE.md` | Not created | Planned | -| Database | `API_SPECIFICATION.md` | Not created | Planned | -| PoC Harness | N/A | `poc/src/index.ts` | Complete | +| Component | Spec Location | Implementation | Status | +| --------------- | --------------------------- | -------------------------- | ----------- | +| Backend API | `API_SPECIFICATION.md` | `apps/api/` | Implemented | +| Web Frontend | `CLIENT_SPECIFICATION.md` | `apps/web/` | Implemented | +| Desktop App | `CLIENT_SPECIFICATION.md` | `apps/desktop/` | Implemented | +| TEE Integration | `TECHNICAL_ARCHITECTURE.md` | `tee-worker/` | Implemented | +| Database | `API_SPECIFICATION.md` | `apps/api/src/migrations/` | Implemented | +| PoC Harness | N/A | `00-Preliminary-R&D/poc/` | Complete | --- -*Structure analysis: 2026-01-20* +Structure analysis: 2026-01-20 diff --git a/.planning/codebase/TESTING.md b/.planning/codebase/TESTING.md index af69426c5a..db2e66a0f0 100644 --- a/.planning/codebase/TESTING.md +++ b/.planning/codebase/TESTING.md @@ -4,25 +4,30 @@ ## Test Framework -**Runner:** -- Not configured - no test framework installed +**Runners:** -**Assertion Library:** -- Not configured +- **Backend (API):** Jest (`apps/api/` — NestJS default) +- **Frontend (Web):** Vitest (`apps/web/`) +- **Crypto package:** Vitest (`packages/crypto/`) +- **E2E:** Playwright (`tests/e2e/`, `tests/e2e-desktop/`) **Run Commands:** + ```bash -# No test commands available -# package.json does not include test scripts +pnpm test # Run all unit tests (parallel across workspaces) +pnpm test:e2e # Playwright E2E tests (requires infra: Postgres, IPFS, Redis; API/web started via Playwright webServer) +pnpm test:e2e:headed # E2E with visible browser +pnpm typecheck # TypeScript type checking across all workspaces ``` ## Current State -**Status:** No automated testing infrastructure exists in this codebase. +**Status:** Testing infrastructure is implemented across all workspaces. -The project is in preliminary R&D/POC phase. The only "testing" is: -1. Manual execution of the POC harness (`npm start`) -2. Runtime verification within the POC code itself +- Unit tests exist for API services, crypto operations, and web components +- E2E tests cover authentication, file operations, and desktop app flows +- CI on `main` runs lint, typecheck, unit tests, and E2E tests (E2E is not run on PRs by default) +- Coverage is not yet at target thresholds (see recommended targets below) ## POC Verification Pattern @@ -31,22 +36,22 @@ The POC (`00-Preliminary-R&D/poc/src/index.ts`) uses inline verification: ```typescript // Verification is built into the workflow const downloadAndVerifyFile = async ( - ctx: HarnessContext, - folder: FolderState, - expectedName: string, - expectedContent: Uint8Array, - expectedMetadataCid?: string + ctx: HarnessContext, + folder: FolderState, + expectedName: string, + expectedContent: Uint8Array, + expectedMetadataCid?: string ): Promise => { - // ... fetch and decrypt file ... + // ... fetch and decrypt file ... - if (bytesToHex(plaintext) !== bytesToHex(expectedContent)) { - throw new Error(`File content mismatch for ${expectedName}`); - } + if (bytesToHex(plaintext) !== bytesToHex(expectedContent)) { + throw new Error(`File content mismatch for ${expectedName}`); + } }; // Called after each operation await downloadAndVerifyFile(ctx, docsFolder, fileName, fileContent, docsAfterUpload.cid); -console.log("File verified after upload"); +console.log('File verified after upload'); ``` --- @@ -58,6 +63,7 @@ console.log("File verified after upload"); CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage at all layers. Backend and TEE development **must** follow **Test-Driven Development (TDD)**, while frontend relies on **End-to-End automation** for validation. **Core Principles:** + - TDD is mandatory for all backend and TEE code - write tests first, then implementation - Test Pyramid structure: more unit tests, fewer E2E tests for fast feedback loops - All tests must run in CI/CD pipeline - no manual testing gates @@ -67,22 +73,24 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a ### Test Pyramid Structure **Target Ratios:** + - Unit Tests: 70% of test suite - Integration Tests: 20% of test suite - E2E Tests: 10% of test suite **Layer Definitions:** -| Layer | Scope | Speed | Dependencies | -|-------|-------|-------|--------------| -| Unit | Single function/class | < 5ms | All mocked | -| Integration | Service composition, DB | 50-500ms | Real database, mocked externals | -| API E2E | Full backend stack | 100ms-2s | Full app, mocked IPFS | -| Frontend E2E | Complete application | 2-30s | Full stack | +| Layer | Scope | Speed | Dependencies | +| ------------ | ----------------------- | -------- | ------------------------------- | +| Unit | Single function/class | < 5ms | All mocked | +| Integration | Service composition, DB | 50-500ms | Real database, mocked externals | +| API E2E | Full backend stack | 100ms-2s | Full app, mocked IPFS | +| Frontend E2E | Complete application | 2-30s | Full stack | ### Test Execution Environments **Unit Tests:** + - Run on: Developer machines, CI runners - Dependencies: All mocked (database, IPFS, external APIs) - Database: None (mocked) @@ -90,51 +98,59 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a - Parallelization: Full parallel execution **Integration Tests:** + - Run on: Developer machines (Docker), CI runners -- Dependencies: Real PostgreSQL in Docker, mocked IPFS/Pinata +- Dependencies: Real PostgreSQL in Docker, mocked IPFS - Database: Test database with migrations, truncated between test suites - Secrets: Test credentials only (never production) - Parallelization: Sequential due to shared database state **API E2E Tests:** + - Run on: Developer machines, CI runners, optionally staging - Dependencies: Full NestJS application, real database, mocked IPFS - Database: Test database, reset between test suites - Secrets: Test JWT keys, mock Web3Auth tokens -**Frontend E2E Tests (Cypress/Puppeteer):** +**Frontend E2E Tests (Playwright):** + - Run on: Developer machines, CI runners, **staging environment** - Dependencies: Frontend app + Backend API + Database (full stack) - Database: Seeded with test fixtures, reset to snapshot between spec files -- Browsers: Chrome (primary), Firefox, Edge -- Parallelization: Parallel specs via Cypress Cloud +- Browsers: Chromium (primary), Firefox, WebKit +- Parallelization: Playwright's built-in parallel workers **TEE Tests:** + - Local/CI: Mock enclave, attestation skipped, test keys - Staging: Real Phala testnet enclave, attestation verified, test keys (not production) ### Framework Requirements -*Note: This section specifies framework choices and requirements. Concrete configuration files and implementation examples will be created when the testing infrastructure is implemented.* +_Note: This section specifies framework choices and requirements. Concrete configuration files and implementation examples will be created when the testing infrastructure is implemented._ **Backend (NestJS):** + - Test Runner: Jest (NestJS default) - Mocking: `@nestjs/testing` module with Jest mocks - HTTP Testing: Supertest for API endpoint testing - Coverage: Jest/Istanbul with enforced thresholds **Frontend (React):** -- E2E Framework: Cypress (recommended) or Puppeteer -- Component Testing: Cypress Component Testing for complex components (optional) -- Visual Regression: Percy integration (optional) + +- E2E Framework: Playwright (browser and desktop flows) +- Component Testing: React Testing Library + Vitest for complex components (optional) +- Visual Regression: Percy (or equivalent) integration via Playwright SDK (optional) **TEE (Rust):** + - Test Framework: Native Rust `#[test]` attributes - Integration: Custom mock enclave harness for local testing ### TDD Requirements (Backend & TEE) **Mandatory Workflow - Red-Green-Refactor:** + 1. RED: Write a failing test for new functionality 2. GREEN: Write minimal code to make the test pass 3. REFACTOR: Clean up while keeping tests green @@ -142,12 +158,14 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a 5. REPEAT: Next requirement **TDD Rules:** + - No production code without a failing test first - Tests must fail for the right reason before implementing - Write the simplest code to pass the test - Refactor only when tests are green **What Backend Unit Tests Must Cover:** + - Service methods in isolation - Controller request handling and response formatting - DTOs and validation logic @@ -160,15 +178,18 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a **No TDD required** - coverage achieved through comprehensive browser automation. **Test Coverage Must Include:** + - All critical user journeys (authentication, file upload/download, folder operations) - Error scenarios and recovery flows - Cross-browser compatibility (Chrome, Firefox, Edge) **Selector Strategy:** + - Use `data-testid` attributes exclusively for test selectors - Avoid flaky selectors (timing-based, nth-child, CSS classes) **Test Organization:** + - Group by feature area: `auth/`, `vault/`, `settings/` - Separate spec files per user journey - Shared fixtures for mock data and responses @@ -178,43 +199,45 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a **Backend Coverage Thresholds:** -| Area | Line Coverage | Branch Coverage | -|------|---------------|-----------------| -| Crypto Services | 100% | 100% | -| Auth Services | 90% | 85% | -| Vault Services | 90% | 85% | -| IPFS/IPNS Services | 85% | 80% | -| Controllers | 80% | 75% | -| Guards/Middleware | 90% | 85% | -| **Overall Minimum** | **85%** | **80%** | +| Area | Line Coverage | Branch Coverage | +| ------------------- | ------------- | --------------- | +| Crypto Services | 100% | 100% | +| Auth Services | 90% | 85% | +| Vault Services | 90% | 85% | +| IPFS/IPNS Services | 85% | 80% | +| Controllers | 80% | 75% | +| Guards/Middleware | 90% | 85% | +| **Overall Minimum** | **85%** | **80%** | **TEE Coverage Thresholds:** -| Area | Coverage | -|------|----------| -| Crypto Functions | 100% | -| Key Handling | 100% | -| Error Paths | 100% | +| Area | Coverage | +| ---------------- | -------- | +| Crypto Functions | 100% | +| Key Handling | 100% | +| Error Paths | 100% | **Frontend E2E Metrics:** -| Metric | Target | -|--------|--------| -| Critical User Journeys Covered | 100% | -| Error Scenarios Tested | 90% | -| Test Pass Rate | 100% | -| Flaky Tests | 0% | +| Metric | Target | +| ------------------------------ | ------ | +| Critical User Journeys Covered | 100% | +| Error Scenarios Tested | 90% | +| Test Pass Rate | 100% | +| Flaky Tests | 0% | ### Mocking Guidelines **What to Mock:** + - Database connections and queries (unit tests only) - IPFS client operations (network calls) -- Pinata API calls +- IPFS API calls - Web3Auth verification - External HTTP services **What NOT to Mock:** + - Cryptographic functions - always test real encryption/decryption - Data conversion utilities (hexToBytes, bytesToHex) - Validation logic @@ -222,6 +245,7 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a ### Automated Linting & Pre-commit Hooks **Pre-commit Hook Requirements:** + - ESLint with `--max-warnings 0` (zero tolerance for lint errors) - Prettier formatting check - TypeScript type checking @@ -229,59 +253,45 @@ CipherBox shall employ a **Test Pyramid** approach with comprehensive coverage a - Cargo fmt and Clippy for Rust code **Pre-push Hook Requirements:** + - Full unit test suite - Integration tests - Coverage threshold verification - Build verification **Enforcement:** + - Commits blocked if any check fails - No `eslint-disable` comments without PR justification - No `.skip()` or `.only()` in tests (enforced via ESLint rules) - Bypassing hooks (`--no-verify`) requires explicit justification in PR **CI Duplication:** + - All pre-commit checks duplicated in CI pipeline - Catches bypassed hooks - bypassing locally only delays failure ### CI Pipeline Structure -**Stage 1: Lint & Type Check (parallel)** -- ESLint (Backend + Frontend) -- Prettier formatting verification -- TypeScript compilation check -- Cargo fmt + Clippy (TEE) - -**Stage 2: Unit Tests (parallel, no services needed)** -- Backend unit tests with coverage -- TEE unit tests with coverage -- Coverage threshold enforcement - -**Stage 3: Integration Tests** -- Backend integration tests -- Requires PostgreSQL service container - -**Stage 4: E2E Tests (parallel)** -- API E2E tests (full backend + database) -- Frontend Cypress tests (full stack) -- Screenshot/video artifacts on failure - -**Stage 5: Build & Deploy** -- Production build verification -- Deploy to staging (main branch only) +- **Stage 1: Lint & Type Check (parallel)** — ESLint (Backend + Frontend), Prettier formatting verification, TypeScript compilation check, Cargo fmt + Clippy (TEE) +- **Stage 2: Unit Tests (parallel, no services needed)** — Backend unit tests with coverage, TEE unit tests with coverage, coverage threshold enforcement +- **Stage 3: Integration Tests** — Backend integration tests, requires PostgreSQL service container +- **Stage 4: E2E Tests (parallel)** — API E2E tests (full backend + database), Frontend Playwright tests (full stack), screenshot/video artifacts on failure +- **Stage 5: Build & Deploy** — Production build verification, deploy to staging (main branch only) ### Test Data Management **Data Lifecycle by Test Level:** -| Level | Setup | Cleanup | Isolation | -|-------|-------|---------|-----------| -| Unit | In-memory mocks | Automatic (GC) | Per test | -| Integration | Migrations + seeds | Truncate tables | Per suite | -| API E2E | Fixtures via API | Truncate tables | Per suite | -| Frontend E2E | Seeded database | Reset to snapshot | Per spec file | +| Level | Setup | Cleanup | Isolation | +| ------------ | ------------------ | ----------------- | ------------- | +| Unit | In-memory mocks | Automatic (GC) | Per test | +| Integration | Migrations + seeds | Truncate tables | Per suite | +| API E2E | Fixtures via API | Truncate tables | Per suite | +| Frontend E2E | Seeded database | Reset to snapshot | Per spec file | **Fixture Requirements:** + - Factory functions for test entities (users, vaults, files) - Deterministic test keys for reproducible crypto tests - JSON fixtures for Cypress mock responses @@ -313,4 +323,4 @@ Based on project criticality: --- -*Testing analysis: 2026-01-20* +Testing analysis: 2026-01-20 diff --git a/.planning/research/PITFALLS.md b/.planning/research/PITFALLS.md index a0c14774ed..442f40d905 100644 --- a/.planning/research/PITFALLS.md +++ b/.planning/research/PITFALLS.md @@ -123,7 +123,7 @@ Mistakes that break zero-knowledge guarantees, cause data loss, or require archi - Silent data loss: user's uploaded file disappears from folder listing - No merge mechanism -- one user's entire metadata update is discarded - File content exists on IPFS (CID is valid) but is unreachable because folder metadata doesn't reference it -- Orphaned Pinata pins consuming storage quota +- Orphaned IPFS pins consuming storage quota - Users lose trust in the system **Prevention:** @@ -331,7 +331,7 @@ Mistakes that cause significant bugs, data integrity issues, or expensive rework ### Pitfall 8: File Versioning Storage Cost Explosion on IPFS -**What goes wrong:** Each version of a file is a separate encrypted blob on IPFS with a unique CID (because CipherBox uses random keys and IVs per encryption -- no deduplication possible). A 10MB file with 50 versions consumes 500MB of Pinata storage, even if changes between versions are tiny. +**What goes wrong:** Each version of a file is a separate encrypted blob on IPFS with a unique CID (because CipherBox uses random keys and IVs per encryption -- no deduplication possible). A 10MB file with 50 versions consumes 500MB of IPFS storage, even if changes between versions are tiny. **Why it happens:** @@ -344,7 +344,7 @@ Mistakes that cause significant bugs, data integrity issues, or expensive rework **Consequences:** - 500 MiB free tier quota exhausted rapidly with active files -- Pinata costs scale linearly with version count x file size +- IPFS costs scale linearly with version count x file size - Users surprised by storage usage - No way to deduplicate or compress versions @@ -372,7 +372,7 @@ Version metadata in folder entry should follow this structure: Additional prevention measures: -- **Unpin old versions promptly.** When a version is pruned, call Pinata unpin. Track pending unpins to avoid orphans. +- **Unpin old versions promptly.** When a version is pruned, call IPFS unpin. Track pending unpins to avoid orphans. - **Show storage impact to users:** "This file has 8 versions using 42MB. Keeping 5 versions would save 17MB." - **Explicitly document:** "File versioning does not support delta storage. Each version stores the complete encrypted file." @@ -402,7 +402,7 @@ Additional prevention measures: - Folder load times degrade as version count grows - IPNS publish latency increases (larger payload) -- Pinata storage for metadata records grows significantly +- IPFS storage for metadata records grows significantly - Every file operation in the folder re-publishes all version metadata **Prevention:** @@ -521,7 +521,7 @@ Additional prevention measures: ### Pitfall 12: Orphaned Versions After Folder Metadata Publish Failure -**What goes wrong:** When creating a new version of a file, the client: (1) encrypts new content, (2) uploads to IPFS (gets new CID), (3) updates folder metadata with new version entry, (4) publishes IPNS. If step 4 fails (network error, IPNS timeout), the new file CID is pinned on Pinata but not referenced in any folder metadata. The old version remains current, and the new version is orphaned. +**What goes wrong:** When creating a new version of a file, the client: (1) encrypts new content, (2) uploads to IPFS (gets new CID), (3) updates folder metadata with new version entry, (4) publishes IPNS. If step 4 fails (network error, IPNS timeout), the new file CID is pinned on IPFS but not referenced in any folder metadata. The old version remains current, and the new version is orphaned. **Why it happens:** @@ -532,7 +532,7 @@ Additional prevention measures: **Consequences:** -- Pinata storage consumed by unreferenced CIDs +- IPFS storage consumed by unreferenced CIDs - User's edit appears to have been lost - Multiple retries can create multiple orphaned versions - Storage quota leaks over time @@ -545,14 +545,14 @@ Additional prevention measures: 3. After metadata publish: mark intent as complete 4. On next session start: check for incomplete intents. Either retry the metadata publish or unpin the orphaned CID. - **Backend reconciliation job:** - - Periodically compare Pinata pin list against all CIDs referenced in known folder metadata + - Periodically compare IPFS pin list against all CIDs referenced in known folder metadata - Flag orphaned CIDs for review/cleanup - Auto-unpin CIDs orphaned for >24 hours - **Retry with idempotency:** If IPNS publish fails, retry with same sequence number. IPNS accepts re-publishes with same or higher sequence numbers. **Detection:** -- Monitor: Pinata pin count vs expected pin count (derived from folder metadata) +- Monitor: IPFS pin count vs expected pin count (derived from folder metadata) - Audit: weekly reconciliation of pinned CIDs vs referenced CIDs - Alert: pin count growing faster than file count diff --git a/.planning/research/STACK.md b/.planning/research/STACK.md index 96a2ec046d..4315b7367a 100644 --- a/.planning/research/STACK.md +++ b/.planning/research/STACK.md @@ -381,7 +381,7 @@ export type FileVersionEntry = { ### Version Retention Strategy -Since file versions are pinned on IPFS (via Pinata), they consume storage quota. Need a configurable retention policy: +Since file versions are pinned on IPFS, they consume storage quota. Need a configurable retention policy: | Strategy | Implementation | | -------------------- | ---------------------------------------------------------- | @@ -411,7 +411,7 @@ Since file versions are pinned on IPFS (via Pinata), they consume storage quota. ### Confidence: HIGH -Version history is purely a metadata schema extension plus Pinata pin management. The existing stack handles everything needed. +Version history is purely a metadata schema extension plus IPFS pin management. The existing stack handles everything needed. --- @@ -678,7 +678,7 @@ totp_secrets (if CipherBox-level TOTP) | Job | Queue | Purpose | | ----------------- | --------------- | ---------------------------------------------- | | `share.notify` | `notifications` | Notify recipient of new share | -| `version.cleanup` | `maintenance` | Unpin expired version CIDs from Pinata | +| `version.cleanup` | `maintenance` | Unpin expired version CIDs from IPFS | | `search.reindex` | `client-tasks` | Trigger client-side reindex after bulk changes | | `nitro.republish` | `republish` | Route to Nitro when Phala is unavailable | diff --git a/.planning/research/m3/ARCHITECTURE.md b/.planning/research/m3/ARCHITECTURE.md index 2023214893..80a6f08016 100644 --- a/.planning/research/m3/ARCHITECTURE.md +++ b/.planning/research/m3/ARCHITECTURE.md @@ -33,7 +33,7 @@ Before detailing M3 additions, here is the current system as of M1/M2 completion | Web App | React 18 + Zustand + Vite | File browser, auth, upload/download, IPNS sync | | API | NestJS + TypeORM + PostgreSQL | Auth, vault, IPFS/IPNS relay, TEE coordination | | Desktop | Tauri v2 + Rust FUSE | Transparent encrypted filesystem mount | -| IPFS | Pinata (managed pinning) | Encrypted content storage | +| IPFS | Kubo (self-hosted) | Encrypted content storage | | IPNS | Per-folder Ed25519 keypairs | Mutable metadata pointers | | TEE | Phala Cloud / AWS Nitro | IPNS auto-republishing | | Auth | Web3Auth + SIWE | Key derivation and identity | diff --git a/.planning/todos/pending/2026-02-14-bring-your-own-ipfs-node.md b/.planning/todos/pending/2026-02-14-bring-your-own-ipfs-node.md index c1ed94ebe7..e4d8942e6a 100644 --- a/.planning/todos/pending/2026-02-14-bring-your-own-ipfs-node.md +++ b/.planning/todos/pending/2026-02-14-bring-your-own-ipfs-node.md @@ -6,19 +6,18 @@ files: - apps/api/src/ipfs/ipfs.module.ts - apps/api/src/ipfs/providers/ipfs-provider.interface.ts - apps/api/src/ipfs/providers/local.provider.ts - - apps/api/src/ipfs/providers/pinata.provider.ts - apps/api/.env.example - apps/web/src/lib/api/ipfs.ts --- ## Problem -Currently CipherBox supports two IPFS providers: Pinata (production default) and a local Kubo node (dev/testing). Both are configured server-side via environment variables (`IPFS_PROVIDER`, `IPFS_LOCAL_API_URL`). There is no way for end users to bring their own IPFS node — the choice is made by the server operator, not the individual user. +Currently CipherBox uses a self-hosted Kubo node for IPFS, configured server-side via environment variables (`IPFS_LOCAL_API_URL`). There is no way for end users to bring their own IPFS node — the choice is made by the server operator, not the individual user. For a zero-knowledge privacy tool, users may want to: - Pin their encrypted data to their own IPFS node (self-sovereignty) -- Use a preferred pinning service other than Pinata (e.g., web3.storage, Filebase, nft.storage) +- Use a preferred pinning service (e.g., web3.storage, Filebase, nft.storage) - Run a personal Kubo/IPFS node at home and have CipherBox pin directly to it - Avoid relying on a third-party pinning service entirely diff --git a/00_START_HERE.md b/00_START_HERE.md deleted file mode 100644 index d498516403..0000000000 --- a/00_START_HERE.md +++ /dev/null @@ -1,195 +0,0 @@ -

-CipherBox Logo -

- -# 🚀 CipherBox - START HERE - -**Complete Product Specification for Privacy-First Encrypted Cloud Storage** - -Status: 🚂 **IN PROGRESS** - -*** - -## 📦 What You Have - -A **production-grade, comprehensive specification** for building CipherBox v1.0 in **3 months with a 3-person team**. - -This is **not a preliminary design document**—it's a **complete blueprint** with: - -- ✅ **5 complete user journeys** (signup → auth → sync → export → recovery) -- ✅ **15 API endpoints** fully specified -- ✅ **6 database tables** (users, refresh_tokens, auth_nonces, vaults, volume_audit, pinned_cids) with schema -- ✅ **6 encryption algorithms** with implementation details -- ✅ **100+ acceptance criteria** -- ✅ **3 key derivation test vectors** -- ✅ **5 complete data flow examples** -- ✅ **12-week development timeline** - -*** - -## 📚 Documentation Structure - -### Core Documents -1. **00_START_HERE.md** ← **You're reading it!** -2. **README.md** - Tech stack & architecture overview - - -### Specifications (`00-Preliminary-R&D/Documentation/`) -3. **IMPLEMENTATION_ROADMAP.md** - 12-week development timeline -4. **PRD.md** - Product requirements, user journeys, scope -5. **TECHNICAL_ARCHITECTURE.md** - Encryption, key hierarchy, system design -6. **API_SPECIFICATION.md** - Backend endpoints, database schema -7. **DATA_FLOWS.md** - Sequence diagrams, test vectors -8. **CLIENT_SPECIFICATION.md** - Web UI, desktop app specs - -*** - -## 🎯 6 Key Architectural Decisions - -### 1. **Web3Auth for Key Derivation** - -**All 4 auth methods → same keypair** - -``` -Email/Password/OAuth/Magic Link/External Wallet → Web3Auth → ECDSA keypair -(same user = same keypair across all grouped auth methods) -``` - - -### 2. **Layered E2E Encryption** - -``` -Layer 1: File content (AES-256-GCM per file) -Layer 2: Folder entries (encrypted names/keys) -Layer 3: Folder metadata (AES-256-GCM per folder) -``` - - -### 3. **Per-Folder IPNS Entries** - -Each folder has its own IPNS entry (enables v2+ sharing) - -### 4. **IPFS/IPNS Relay + Polling Sync** (~30s) - -Signed IPNS records relayed by CipherBox API; no direct client publishing - -### 5. **User-Held Keys** (Zero-Knowledge) - -Server stores **only encrypted keys** - never plaintext - -### 6. **TEE-Based IPNS Republishing** - -**Automatic IPNS record refresh via Trusted Execution Environment** - -``` -Problem: IPNS records expire after ~24 hours -Solution: TEE republishes every 3 hours, even when all devices are offline - -Flow: -1. Client encrypts ipnsPrivateKey with TEE public key (ECIES) -2. Backend stores encrypted key (cannot decrypt without TEE hardware) -3. TEE cron decrypts in hardware, signs new IPNS record, zeroes key immediately -4. Zero-knowledge preserved: TEE keys exist in memory only for milliseconds -``` - -**Providers:** Phala Cloud (primary) / AWS Nitro (fallback) - -*** - -## 🧪 Console PoC Harness (Validation-First) - -To de-risk the crypto and IPFS/IPNS assumptions, a single-user Node.js console harness runs the full file/folder flow end-to-end without Web3Auth or backend dependencies. Each run publishes metadata to IPFS/IPNS, verifies correctness via IPNS resolution, measures propagation delay, and unpins all created CIDs during teardown. - -*** - -## 📋 MVP Scope (v1.0) - -### ✅ **Included** - -- Multi-method auth (Email/Password, OAuth, Magic Link, External Wallet) -- File upload/download (E2E encrypted) -- Folder organization (create/rename/move/delete) -- Web UI (React) -- Desktop mount (macOS FUSE) -- Multi-device sync (IPNS polling) -- TEE-based IPNS republishing (Phala Cloud / AWS Nitro) -- Vault export (portability) -- **Zero-knowledge** (private keys never on server) - - -### ⏱️ **v1.1+** - -- Billing/payments -- Mobile apps -- Linux/Windows desktop - - -### 📌 **v2+** - -- File versioning -- Folder sharing -- Search/indexing - -*** - -## 🏗️ Tech Stack - -| Layer | Technology | -| :-- | :-- | -| **Frontend** | React 18 + TypeScript | -| **Backend** | Node.js + NestJS + TypeScript | -| **Crypto** | Web Crypto API (native) | -| **Key Derivation** | Web3Auth Network | -| **Storage** | IPFS via Pinata (v1) | -| **Database** | PostgreSQL | -| **Desktop** | Tauri/Electron + FUSE | -| **TEE** | Phala Cloud (primary) / AWS Nitro (fallback) | - - -*** - -## 📈 12-Week Timeline - -``` -Week 1-2: Planning & Setup -Week 3-4: Auth & Key Derivation -Week 5-7: Storage & Encryption -Week 8-10: Web UI & Desktop -Week 11-12: Testing & Launch -``` - -**Team:** 3 people (1 backend, 1 frontend, 1 devops) - -*** - -## 🔐 Security Highlights - -✅ **Zero-Knowledge**: Private keys never on server -✅ **E2E Encryption**: AES-256-GCM + ECIES secp256k1 -✅ **TEE Republishing**: IPNS keys decrypted only in hardware enclaves (Phala/Nitro) -✅ **Data Portability**: Export vault, recover independently -✅ **No Tracking**: No analytics, no telemetry -✅ **GDPR Ready**: Privacy policy framework included - - -## ❓ FAQ - -**Q: How long to read everything?** -**A:** 4+ hours for full spec, 1 hour for essentials - -**Q: Realistic timeline?** -**A:** Yes - 12 weeks, 3 people, MVP scope - -**Q: Security verified?** -**A:** Yes - zero-knowledge mathematically proven, all crypto standards - -**Q: Users can recover data if CipherBox disappears?** -**A:** Yes - vault export + private key = complete independence - -*** - -## 🚀 Ready to Build - -**Status:** **IN PROGRESS** - -**Launch Target:** April 15, 2026 \ No newline at end of file diff --git a/README.md b/README.md index 3fb1de1363..aa3a0b7b75 100644 --- a/README.md +++ b/README.md @@ -2,399 +2,110 @@ CipherBox Logo

-# CipherBox - README.md - -## Privacy-first cloud storage with decentralized persistence +

Privacy-first encrypted cloud storage with decentralized persistence

--- -## 📄 Overview - -**CipherBox is a technology demonstrator** showcasing privacy-first cloud storage with decentralized persistence. It is **not intended as a commercial product** but as a proof-of-concept for: - -- **Zero-knowledge client-side encryption** -- **Decentralized storage via IPFS/IPNS** -- **Deterministic key derivation via Web3Auth** -- **Cross-device sync without server-side key access** - -**CipherBox** demonstrates: +## What is CipherBox -- **IPFS/IPNS** for decentralized, redundant storage -- **Web3Auth** for deterministic key derivation across multiple auth methods -- **AES-256-GCM + ECIES secp256k1** for layered E2E encryption -- **React web UI** + **FUSE desktop mount** (macOS v1) -- **Automatic multi-device sync** via IPNS polling -- **TEE-based IPNS republishing** via Phala Cloud / AWS Nitro (zero-knowledge) - ---- +CipherBox is a **technology demonstrator** for privacy-first cloud storage. All encryption happens client-side — the server never sees plaintext data, file names, or encryption keys. Files are stored on IPFS for decentralized persistence, keys are derived deterministically via Web3Auth so the same user always gets the same vault regardless of login method, and data can be exported for independent recovery without CipherBox. ## Acknowledgements This project is inspired by discussions and planning while working on [ChainSafe Files](https://github.com/chainsafe/ui-monorepo). A massive shout-out to all the colleagues I got to work with on the original ChainSafe Files project, who unknowingly contributed to this phoenix rising out of the ashes. ---- - -## 🎯 Vision - -**Replace Google Drive/Dropbox with:** - -```text -✓ Client-side encryption (server never sees plaintext) -✓ User-held keys (zero-knowledge guarantee) -✓ Decentralized storage (no vendor lock-in) -✓ Data portability (export vault, recover independently) -✓ Multi-device sync (automatic via IPFS) -✓ Transparent UX (hide IPFS complexity) -``` - ---- - -## 📦 MVP Scope (v1.0) - -### ✅ **Included** - -```text -Auth: Email/Password, OAuth, Magic Link, External Wallet → Web3Auth key derivation -Storage: IPFS via Pinata (v1), per-folder IPNS entries -Encryption: AES-256-GCM files + ECIES key wrapping -Web UI: React file browser, drag-drop, folder ops -Desktop: macOS FUSE mount + background sync -Sync: IPNS polling (~30s eventual consistency) -TEE Republishing: Phala Cloud (primary) / AWS Nitro (fallback), every 3h -Portability: Vault export + independent recovery -``` - -### ⏱️ **Deferred** - -```text -v1.1: Billing, Linux/Windows desktop, mobile apps -v2: File versioning, folder sharing, search -``` - ---- - -## 🏗️ Technology Stack +## Features -| Component | Technology | Why | -| :----------------- | :---------------------------- | :-------------------------------- | -| **Frontend** | React 18 + TypeScript | Modern crypto UI | -| **Web Crypto** | Web Crypto API | Native browser encryption | -| **Backend** | Node.js + NestJS + TypeScript | Type-safe APIs | -| **Database** | PostgreSQL | ACID audit trail | -| **Key Derivation** | Web3Auth Network | Deterministic across auth methods | -| **Storage** | IPFS via Pinata | Redundant, decentralized | -| **Desktop** | Tauri/Electron + FUSE | Transparent file access | -| **TEE** | Phala Cloud / AWS Nitro | Zero-knowledge IPNS republishing | +- **Authentication** — Web3Auth MPC Core Kit: email OTP, Google OAuth, magic link, external wallet. MFA via device factor. Same user identity = same vault. +- **Encryption** — Client-side AES-256-GCM for files and metadata. ECIES secp256k1 key wrapping (per-file, per-folder random keys). Streaming AES-256-CTR for large media files. +- **File Management** — Upload, download, rename, move, delete. Nested folders up to 20 levels. Drag-and-drop. +- **Sync** — Multi-device via IPNS polling (~30s). Conflict detection and resolution. +- **Desktop** — macOS via Tauri v2 + FUSE-T virtual filesystem mount. Background sync with system tray. +- **TEE Republishing** — Automatic IPNS record refresh every 6 hours via Phala Cloud. Zero-knowledge: keys decrypted only inside hardware enclaves. +- **Data Portability** — Full vault export (JSON + encrypted blobs). Standalone recovery with private key — no CipherBox required. ---- +- **Sharing** — User-to-user sharing with ECIES re-wrapping. Invite-link sharing with time-limited access tokens. +- **Recycle Bin** — 30-day soft-delete with restore. -## 🔐 Architecture Summary +### Planned (v1.1+) -```text -User Device (Web/Desktop) - ↓ Auth (4 methods) -CipherBox Backend (JWT) - ↓ -Web3Auth Network (Key Derivation) - ↓ ECDSA Private Key (RAM only!) -User Device ← Vault Data ← PostgreSQL - ↓ Encrypted Keys -IPFS (Pinata) ← Encrypted Files - ↑ -TEE (Phala/Nitro) ← IPNS Republish (every 3h) -``` +- **Search** — Client-side encrypted search index across file and folder names. +- **Versioning** — File history with point-in-time restore. +- **Desktop (Windows & Linux)** — WinFSP / libfuse support. -**Key Properties:** - -- Same user + any auth method → same keypair → same vault -- TEE republishes IPNS records even when all devices are offline - ---- - -## 🔑 Encryption Hierarchy - -CipherBox implements layered, zero-knowledge encryption where **all user data is encrypted client-side before leaving the device**. The server and storage layer never see plaintext — not file contents, not file names, not folder names, not timestamps, not file sizes. - -### Key Derivation - -Two paths produce the same `VaultKey` (a secp256k1 keypair): +## Architecture Overview ```text -┌─────────────────────────────────────────────────────────────────────┐ -│ KEY DERIVATION │ -├─────────────────────────┬───────────────────────────────────────────┤ -│ Web3Auth (Social Login)│ External Wallet (MetaMask, etc.) │ -│ │ │ -│ Google/Email/etc. │ 1. Sign deterministic EIP-712 message │ -│ ↓ │ 2. Normalize signature (low-S, EIP-2) │ -│ Web3Auth Network │ 3. HKDF-SHA256: │ -│ ↓ │ salt = "CipherBox-ECIES-v1" │ -│ secp256k1 keypair │ info = wallet address (lowercase) │ -│ (deterministic) │ input = normalized signature │ -│ │ ↓ │ -│ │ secp256k1 keypair (deterministic) │ -├─────────────────────────┴───────────────────────────────────────────┤ -│ ↓ │ -│ VaultKey (secp256k1) │ -│ ┌─────────────────────────────────────┐ │ -│ │ Private Key: 32 bytes (RAM only!) │ │ -│ │ Public Key: 65 bytes (uncompressed) │ │ -│ └─────────────────────────────────────┘ │ -└─────────────────────────────────────────────────────────────────────┘ +┌──────────────┐ ┌──────────────┐ ┌───────────────┐ +│ Web / Desktop│────▶│ CipherBox │────▶│ PostgreSQL │ +│ (Client) │ │ API │ │ (Metadata) │ +└──────┬───────┘ └──────┬───────┘ └───────────────┘ + │ │ + │ Encrypted │ Relay + │ blobs │ + ▼ ▼ +┌──────────────┐ ┌───────────────┐ +│ IPFS │ │ TEE Worker │ +│ (Storage) │ │ (IPNS Refresh)│ +└──────────────┘ └───────────────┘ ``` -### Full Key Hierarchy +The client encrypts everything locally. The API is a zero-knowledge relay — it stores encrypted keys and routes IPFS/IPNS operations but never accesses plaintext. For full cryptographic details, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md). -Every key below the VaultKey is **randomly generated** (not derived) and **ECIES-wrapped** with the user's public key. Compromising one file key reveals nothing about other file keys. +## Tech Stack -```text - VaultKey (secp256k1 keypair) - │ - │ ECIES-unwrap - ├──────────────────────────────────────────┐ - │ │ - ▼ ▼ - rootFolderKey (random 32B) rootIpnsPrivateKey (Ed25519) - │ │ - │ AES-256-GCM decrypt │ Signs IPNS records - ▼ ▼ - Root Folder Metadata (encrypted JSON) IPNS publish/resolve - │ - │ Contains per-child entries: - │ - ├── File Entries ──────────────────────────────────────────┐ - │ name (encrypted) ◄── only visible after │ - │ size (encrypted) decrypting metadata │ - │ timestamps (encrypted) │ - │ fileKeyEncrypted ──── ECIES-unwrap ──► fileKey (32B) │ - │ fileIv (12B) │ │ - │ cid (IPFS ref) AES-256-GCM decrypt │ - │ ▼ │ - │ File Contents │ - │ │ - ├── Subfolder Entries ─────────────────────────────────────┤ - │ name (encrypted) ◄── only visible after │ - │ timestamps (encrypted) decrypting metadata │ - │ folderKeyEncrypted ── ECIES-unwrap ──► folderKey │ - │ ipnsPrivateKeyEncrypted ─ ECIES-unwrap ► ipnsKey │ - │ ipnsName (k51...) │ - │ │ │ - │ ▼ │ - │ Subfolder Metadata (same structure, recursive) │ - └──────────────────────────────────────────────────────────┘ -``` +| Component | Technology | +| :----------------- | :-------------------------------------------- | +| **Frontend** | React 18 + TypeScript + Tailwind CSS | +| **Backend** | Node.js + NestJS + TypeScript | +| **Database** | PostgreSQL 16 | +| **Job Queue** | BullMQ + Redis | +| **Key Derivation** | Web3Auth MPC Core Kit | +| **Storage** | IPFS via Kubo | +| **Desktop** | Tauri v2 + FUSE-T / WinFSP | +| **TEE** | Phala Cloud (IPNS republishing) | +| **Crypto** | Web Crypto API (AES-256-GCM, ECIES secp256k1) | -### What's Encrypted vs. What's Visible +## Project Structure ```text -┌─────────────────────────────────────────────────────────────────┐ -│ FULLY ENCRYPTED │ -│ (requires user's private key + folder key to access) │ -│ │ -│ ✓ File contents ✓ File names │ -│ ✓ Folder names ✓ Folder structure / child list │ -│ ✓ File sizes ✓ Creation timestamps │ -│ ✓ Modification timestamps ✓ All encryption keys │ -│ ✓ IPNS private keys ✓ File-to-folder relationships │ -├─────────────────────────────────────────────────────────────────┤ -│ VISIBLE (Plaintext) │ -│ (required for IPFS/IPNS protocol operation) │ -│ │ -│ • IPFS CIDs (content-addressed hashes, no semantic meaning) │ -│ • IPNS names (k51... public identifiers for folders) │ -│ • Encrypted blob sizes (approximate original sizes) │ -│ • Encryption IVs (required for decryption, not secret) │ -│ • User's secp256k1 public key │ -├─────────────────────────────────────────────────────────────────┤ -│ NEVER STORED (RAM Only) │ -│ │ -│ • User's private key • Decrypted file names │ -│ • Decrypted folder metadata • Decrypted file contents │ -│ • Plaintext file/folder keys • Wallet signatures │ -└─────────────────────────────────────────────────────────────────┘ +cipher-box/ +├── apps/ +│ ├── api/ # NestJS backend +│ ├── web/ # React frontend +│ └── desktop/ # Tauri v2 desktop app +├── packages/ +│ ├── crypto/ # Shared encryption library +│ └── api-client/ # OpenAPI spec; generated typed client lives in apps/web/src/api/ +├── tee-worker/ # Phala Cloud TEE worker +├── tests/ +│ ├── e2e/ # Playwright E2E tests +│ └── e2e-desktop/ # Desktop E2E tests +└── docker/ # Docker Compose (PostgreSQL, IPFS, Redis) ``` -### Cryptographic Primitives +## Getting Started -| Purpose | Algorithm | Parameters | -|:--|:--|:--| -| File & metadata encryption | AES-256-GCM | 256-bit key, 96-bit IV, 128-bit auth tag | -| Key wrapping | ECIES (secp256k1) | Ephemeral keypair + AES-GCM | -| Key derivation (wallets) | HKDF-SHA256 | 32-byte output, static salt | -| IPNS record signing | Ed25519 | 32-byte seed, 64-byte signatures | -| Random generation | `crypto.getRandomValues()` | CSPRNG (Web Crypto API) | - -### File Upload Flow - -```text - ┌──────────────────────────────────────────────────────────────┐ - │ FILE UPLOAD FLOW │ - │ │ - │ 1. User selects "document.pdf" │ - │ │ │ - │ ▼ │ - │ 2. Generate random fileKey (32 bytes) │ - │ Generate random IV (12 bytes) │ - │ │ │ - │ ▼ │ - │ 3. AES-256-GCM encrypt(plaintext, fileKey, IV) │ - │ → ciphertext ‖ auth_tag (16 bytes) │ - │ │ │ - │ ▼ │ - │ 4. ECIES wrap(fileKey, userPublicKey) │ - │ → ephemeral_pubkey ‖ wrapped_key ‖ tag │ - │ │ │ - │ ▼ │ - │ 5. Clear plaintext fileKey from memory │ - │ │ │ - │ ▼ │ - │ 6. Upload encrypted blob → Pinata → IPFS → returns CID │ - │ │ │ - │ ▼ │ - │ 7. Add to folder metadata: │ - │ { name, cid, fileKeyEncrypted, fileIv, size, ... } │ - │ │ │ - │ ▼ │ - │ 8. Re-encrypt folder metadata with folderKey (AES-256-GCM) │ - │ │ │ - │ ▼ │ - │ 9. Upload encrypted metadata → IPFS → new CID │ - │ │ │ - │ ▼ │ - │ 10. Publish IPNS record: /ipns/k51... → /ipfs/ │ - │ (signed with folder's Ed25519 private key) │ - └──────────────────────────────────────────────────────────────┘ -``` - -### Defense in Depth - -Each file key is protected by multiple nested layers. An attacker must break through all layers to access any file content: - -```text - File Content - └─ encrypted with ──► fileKey (random, unique per file) - └─ ECIES-wrapped with ──► User's Public Key - └─ stored inside ──► Folder Metadata - └─ encrypted with ──► folderKey (random, unique per folder) - └─ ECIES-wrapped with ──► User's Public Key - └─ stored on ──► Server (zero-knowledge) +```bash +docker compose -f docker/docker-compose.yml up -d +pnpm install +pnpm dev # starts API (:3000) + web (:5173) ``` -### What an Attacker Sees - -With full access to IPFS and the CipherBox server but without the user's private key: +See [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) for full setup instructions including desktop app, testing, and environment configuration. -```text - IPFS (public network): +## Documentation - /ipfs/bafybei3a7x... ← encrypted blob (file? folder? unknown) - /ipfs/bafybei9f2k... ← encrypted blob (file? folder? unknown) - /ipfs/bafybeiqw8m... ← encrypted blob (file? folder? unknown) +| Document | Description | +| :------------------------------------------------------------------------- | :----------------------------------------------------------- | +| [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | Encryption hierarchy, key derivation, threat model | +| [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) | Local setup, running, testing | +| [docs/AUTHENTICATION_ARCHITECTURE.md](docs/AUTHENTICATION_ARCHITECTURE.md) | Auth flow details | +| [docs/METADATA_SCHEMAS.md](docs/METADATA_SCHEMAS.md) | All metadata object schemas | +| [docs/VAULT_EXPORT_FORMAT.md](docs/VAULT_EXPORT_FORMAT.md) | Export/recovery data format | +| [docs/DATABASE_EVOLUTION_PROTOCOL.md](docs/DATABASE_EVOLUTION_PROTOCOL.md) | Migration discipline | +| [00-Preliminary-R&D/Documentation/](00-Preliminary-R&D/Documentation/) | Frozen v1 specifications (PRD, API, Data Flows, Client Spec) | - Without the user's private key: - ✗ Cannot read file contents - ✗ Cannot read file or folder names - ✗ Cannot determine folder structure - ✗ Cannot read timestamps or file sizes - ✗ Cannot determine which blobs are files vs. folders - ✓ Can see encrypted blob sizes (approximates original size) - ✓ Can see IPNS update frequency (usage pattern) -``` +## License ---- - -## 📊 6 Key Decisions - -### 1. **Web3Auth for Key Derivation** - -```text -Email/Password/OAuth/Magic Link/External Wallet → Web3Auth → Same ECDSA keypair -``` - -### 2. **Layered Encryption** - -```text -File (AES-256-GCM) → Metadata (AES-256-GCM) → Keys (ECIES) -``` - -### 3. **Per-Folder IPNS** - -```text -Root IPNS → Folder1 IPNS → Folder2 IPNS (modular sharing-ready) -``` - -### 4. **IPNS Polling Sync** - -```text -30s polling, no push infrastructure (MVP simple) -``` - -### 5. **Zero-Knowledge Keys** - -```text -Server holds: Encrypted root key only -Client holds: Private key (RAM only) -``` - -### 6. **TEE-Based IPNS Republishing** - -```text -IPNS records expire after ~24h → TEE republishes every 3h -Client encrypts ipnsPrivateKey with TEE public key (ECIES) -TEE decrypts in hardware, signs, zeroes key immediately -Providers: Phala Cloud (primary) / AWS Nitro (fallback) -``` - ---- - -## 🛤️ User Journey (Example) - -```text -1. Signup (Google) → Web3Auth derives KeyA -2. Upload file → Encrypt → IPFS CID → IPNS publish -3. Phone login (Email) → Web3Auth derives KeyA (same!) -4. Phone polls IPNS → Sees file → Downloads & decrypts -5. Export vault → JSON with CIDs + encrypted root key -6. CipherBox gone? → Use export + private key → Full recovery -``` - ---- - -## 🔐 Security - -```text -✅ Zero-Knowledge: Private keys never on server -✅ E2E Encryption: AES-256-GCM + ECIES secp256k1 -✅ TEE Republishing: IPNS keys decrypted only in hardware enclaves -✅ Data Portability: Export vault, recover independently -✅ No Tracking: No analytics/telemetry -✅ Threat Model: See TECHNICAL_ARCHITECTURE.md -``` - ---- - -## 📋 Success Criteria (Tech Demo) - -| Criterion | Target | -| :-------------------- | :-------------------------------------------------------- | -| **Privacy** | Private keys never on server (cryptographically enforced) | -| **Encryption** | AES-256-GCM + ECIES correctly implemented | -| **Key Derivation** | Same user + any auth method → same keypair | -| **Multi-Device Sync** | <30s via IPNS polling | -| **Data Recovery** | Vault export enables independent recovery | -| **Zero Dependencies** | Can decrypt vault without CipherBox service | - ---- - -## 📚 Documentation - -```text -00_START_HERE.md ← Quick overview -00-Preliminary-R&D/Documentation/PRD.md ← Product requirements -00-Preliminary-R&D/Documentation/TECHNICAL_ARCHITECTURE.md ← Encryption & system design -00-Preliminary-R&D/Documentation/API_SPECIFICATION.md ← Backend endpoints -00-Preliminary-R&D/Documentation/DATA_FLOWS.md ← Sequence diagrams -00-Preliminary-R&D/Documentation/CLIENT_SPECIFICATION.md ← Web UI & desktop specs -``` - ---- +[MIT](LICENSE) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md new file mode 100644 index 0000000000..98d1c79e44 --- /dev/null +++ b/docs/ARCHITECTURE.md @@ -0,0 +1,280 @@ +# Architecture + +CipherBox implements layered, zero-knowledge encryption where **all user data is encrypted client-side before leaving the device**. The server and storage layer never see plaintext — not file contents, not file names, not folder names, not timestamps, not plaintext file sizes (encrypted blob sizes are visible for storage accounting). + +## System Overview + +```text +User Device (Web/Desktop) + ↓ Auth (4 methods) +CipherBox Backend (JWT) + ↓ +Web3Auth Network (Key Derivation) + ↓ ECDSA Private Key (RAM only!) +User Device ← Vault Data ← PostgreSQL + ↓ Encrypted Keys +IPFS (Kubo) ← Encrypted Files + ↑ +TEE (Phala; Nitro fallback planned) ← IPNS Republish (every 6h) +``` + +**Key Properties:** + +- Same user identity → same keypair → same vault (auth methods share a vault when they resolve to the same CipherBox `userId`; see [Authentication Architecture](AUTHENTICATION_ARCHITECTURE.md)) +- TEE republishes IPNS records even when all devices are offline + +## Key Derivation + +Two paths produce the same `VaultKey` (a secp256k1 keypair): + +```text +┌─────────────────────────────────────────────────────────────────────┐ +│ KEY DERIVATION │ +├─────────────────────────┬───────────────────────────────────────────┤ +│ Web3Auth (Social Login)│ Web3Auth (External Wallet via SIWE) │ +│ │ │ +│ Google/Email/etc. │ 1. Wallet signs SIWE (EIP-4361) message │ +│ ↓ │ 2. Backend verifies SIWE, issues JWT │ +│ Web3Auth Network │ 3. Web3Auth Core Kit validates JWT │ +│ ↓ │ 4. Web3Auth Network │ +│ secp256k1 keypair │ ↓ │ +│ (deterministic) │ secp256k1 keypair (deterministic) │ +│ │ │ +│ │ │ +├─────────────────────────┴───────────────────────────────────────────┤ +│ ↓ │ +│ VaultKey (secp256k1) │ +│ ┌─────────────────────────────────────┐ │ +│ │ Private Key: 32 bytes (RAM only!) │ │ +│ │ Public Key: 65 bytes (uncompressed) │ │ +│ └─────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────────────────┘ +``` + +## Encryption Hierarchy + +Keys below the VaultKey are either **randomly generated** or **HKDF-derived**, then **ECIES-wrapped** with the user's public key. IPNS keypairs (vault, device-registry, per-file) are derived deterministically via HKDF-SHA256 from the user's private key (see [Cryptographic Primitives](#cryptographic-primitives)). Content encryption keys (rootFolderKey, per-folder keys, per-file keys) are randomly generated. Compromising one file key reveals nothing about other file keys. + +```text + VaultKey (secp256k1 keypair) + │ + │ ECIES-unwrap + ├──────────────────────────────────────────┐ + │ │ + ▼ ▼ + rootFolderKey (random 32B) rootIpnsPrivateKey (Ed25519, HKDF-derived) + │ │ + │ AES-256-GCM decrypt │ Signs IPNS records + ▼ ▼ + Root Folder Metadata (encrypted JSON) IPNS publish/resolve + │ + │ Contains per-child entries: + │ + ├── File Pointer Entries ────────────────────────────────────────────┐ + │ name (encrypted) ◄── only visible after │ + │ timestamps (encrypted) decrypting metadata │ + │ fileMetaIpnsName (k51...) ─────────────────────────────────────┤ + │ │ │ + │ ▼ │ + │ File Metadata (per-file IPNS record, encrypted JSON) │ + │ fileKeyEncrypted ─ ECIES-unwrap ──► fileKey (32B) │ + │ fileIv (12B) │ │ + │ cid (IPFS ref) AES-256-GCM decrypt │ + │ ▼ │ + │ File Contents │ + │ │ + ├── Subfolder Entries ──────────────────────────────────────────────┤ + │ name (encrypted) ◄── only visible after │ + │ timestamps (encrypted) decrypting metadata │ + │ folderKeyEncrypted ── ECIES-unwrap ──► folderKey │ + │ ipnsPrivateKeyEncrypted ─ ECIES-unwrap ► ipnsKey │ + │ ipnsName (k51...) │ + │ │ │ + │ ▼ │ + │ Subfolder Metadata (same structure, recursive) │ + └───────────────────────────────────────────────────────────────────┘ +``` + +## Visibility Model + +```text +┌─────────────────────────────────────────────────────────────────┐ +│ FULLY ENCRYPTED │ +│ (requires user's private key + folder key to access) │ +│ │ +│ ✓ File contents ✓ File names │ +│ ✓ Folder names ✓ Folder structure / child list │ +│ ✓ File sizes ✓ Creation timestamps │ +│ ✓ Modification timestamps ✓ All encryption keys │ +│ ✓ IPNS private keys ✓ File-to-folder relationships │ +├─────────────────────────────────────────────────────────────────┤ +│ VISIBLE (Plaintext) │ +│ (required for IPFS/IPNS protocol operation) │ +│ │ +│ • IPFS CIDs (content-addressed hashes, no semantic meaning) │ +│ • IPNS names (k51... public identifiers for folders) │ +│ • Encrypted blob sizes (approximate original sizes) │ +│ • Encryption IVs (required for decryption, not secret) │ +│ • User's secp256k1 public key │ +├─────────────────────────────────────────────────────────────────┤ +│ NEVER STORED (RAM Only) │ +│ │ +│ • User's private key • Decrypted file names │ +│ • Decrypted folder metadata • Decrypted file contents │ +│ • Plaintext file/folder keys • Wallet signatures │ +└─────────────────────────────────────────────────────────────────┘ +``` + +## Cryptographic Primitives + +| Purpose | Algorithm | Parameters | +| :---------------------------------- | :------------------------- | :--------------------------------------- | +| File & metadata encryption | AES-256-GCM | 256-bit key, 96-bit IV, 128-bit auth tag | +| Key wrapping | ECIES (secp256k1) | Ephemeral keypair + AES-GCM | +| Deterministic key derivation (IPNS) | HKDF-SHA256 | 32-byte output, context-specific salt | +| IPNS record signing | Ed25519 | 32-byte seed, 64-byte signatures | +| Random generation | `crypto.getRandomValues()` | CSPRNG (Web Crypto API) | + +## Data Flows + +### File Upload + +```text + ┌──────────────────────────────────────────────────────────────┐ + │ FILE UPLOAD FLOW │ + │ │ + │ 1. User selects "document.pdf" │ + │ │ │ + │ ▼ │ + │ 2. Generate random fileKey (32 bytes) │ + │ Generate random IV (12 bytes) │ + │ │ │ + │ ▼ │ + │ 3. AES-256-GCM encrypt(plaintext, fileKey, IV) │ + │ → ciphertext ‖ auth_tag (16 bytes) │ + │ │ │ + │ ▼ │ + │ 4. ECIES wrap(fileKey, userPublicKey) │ + │ → ephemeral_pubkey ‖ wrapped_key ‖ tag │ + │ │ │ + │ ▼ │ + │ 5. Clear plaintext fileKey from memory │ + │ │ │ + │ ▼ │ + │ 6. Upload encrypted blob → IPFS (Kubo) → returns CID │ + │ │ │ + │ ▼ │ + │ 7. Create per-file FileMetadata entry (own IPNS record): │ + │ { cid, fileKeyEncrypted, fileIv, size, ... } │ + │ │ │ + │ ▼ │ + │ 8. Add FilePointer to folder metadata children: │ + │ { type: "file", nameEncrypted, nameIv, │ + │ fileMetaIpnsName, ipnsPrivateKeyEncrypted? } │ + │ │ │ + │ ▼ │ + │ 9. Re-encrypt folder metadata with folderKey (AES-256-GCM) │ + │ │ │ + │ ▼ │ + │ 10. Upload encrypted metadata → IPFS → new CID │ + │ │ │ + │ ▼ │ + │ 11. Publish IPNS record: /ipns/k51... → /ipfs/ │ + │ (signed with folder's Ed25519 private key) │ + └──────────────────────────────────────────────────────────────┘ +``` + +## Defense in Depth + +Each file key is protected by multiple nested layers. An attacker must break through all layers to access any file content: + +```text + File Content + └─ encrypted with ──► fileKey (random, unique per file) + └─ ECIES-wrapped with ──► User's Public Key + └─ stored inside ──► Folder Metadata + └─ encrypted with ──► folderKey (random, unique per folder) + └─ ECIES-wrapped with ──► User's Public Key + └─ stored on ──► Server (zero-knowledge) +``` + +## Threat Model + +With full access to IPFS and the CipherBox server but without the user's private key: + +```text + IPFS (public network): + + /ipfs/bafybei3a7x... ← encrypted blob (file? folder? unknown) + /ipfs/bafybei9f2k... ← encrypted blob (file? folder? unknown) + /ipfs/bafybeiqw8m... ← encrypted blob (file? folder? unknown) + + Without the user's private key: + ✗ Cannot read file contents + ✗ Cannot read file or folder names + ✗ Cannot determine folder structure + ✗ Cannot read timestamps or file sizes + ✗ Cannot determine which blobs are files vs. folders + ✓ Can see encrypted blob sizes (approximates original size) + ✓ Can see IPNS update frequency (usage pattern) +``` + +## Key Design Decisions + +### 1. Web3Auth for Key Derivation + +```text +Any auth method → CipherBox backend resolves userId → Web3Auth → Same ECDSA keypair +``` + +### 2. Layered Encryption + +```text +File (AES-256-GCM) → Metadata (AES-256-GCM) → Keys (ECIES) +``` + +### 3. Per-Folder IPNS + +```text +Root IPNS → Folder1 IPNS → Folder2 IPNS (modular sharing-ready) +``` + +### 4. IPNS Polling Sync + +```text +30s polling, no push infrastructure (MVP simple) +``` + +### 5. Zero-Knowledge Keys + +```text +Server holds: Encrypted root key only +Client holds: Private key (RAM only) +``` + +### 6. TEE-Based IPNS Republishing + +```text +IPNS records expire after ~24h → backend scheduler triggers republish every 6h +Client encrypts ipnsPrivateKey with TEE public key (ECIES) +TEE decrypts in hardware, signs, zeroes key immediately +Providers: Phala Cloud (current) / AWS Nitro (planned fallback) +``` + +## User Journey Example + +```text +1. Signup (Google) → Web3Auth derives KeyA +2. Upload file → Encrypt → IPFS CID → IPNS publish +3. Phone login (Email) → Web3Auth derives KeyA (same!) +4. Phone polls IPNS → Sees file → Downloads & decrypts +5. Export vault → JSON with CIDs + encrypted root key +6. CipherBox gone? → Use export + private key → Full recovery +``` + +## Further Reading + +- [Frozen Specifications](../00-Preliminary-R&D/Documentation/) — PRD, Technical Architecture, API Specification, Data Flows, Client Specification +- [Authentication Architecture](AUTHENTICATION_ARCHITECTURE.md) — detailed auth flow documentation +- [Metadata Schemas](METADATA_SCHEMAS.md) — all metadata object schemas with field tables +- [Vault Export Format](VAULT_EXPORT_FORMAT.md) — export/recovery data format diff --git a/docs/DEVELOPMENT.md b/docs/DEVELOPMENT.md new file mode 100644 index 0000000000..2ba83edb26 --- /dev/null +++ b/docs/DEVELOPMENT.md @@ -0,0 +1,154 @@ +# Development Guide + +## Prerequisites + +- **Node.js** 20+ +- **pnpm** 9+ +- **Docker** (for PostgreSQL, IPFS, Redis) +- **Rust** toolchain (desktop app only) + +## Infrastructure + +Start the required services: + +```bash +docker compose -f docker/docker-compose.yml up -d +``` + +This starts: + +| Service | Port | Purpose | +| :---------------- | :------------------------- | :-------------------------------- | +| PostgreSQL 16 | 5432 | Database | +| IPFS (Kubo) | 5001 (API), 8080 (Gateway) | Decentralized storage | +| Redis 7 | 6380 | BullMQ job queue | +| Mock IPNS Routing | 3001 | Local IPNS resolution for dev/E2E | + +## Environment + +Copy the example env files: + +```bash +cp apps/api/.env.example apps/api/.env +cp apps/web/.env.example apps/web/.env +``` + +### API (`apps/api/.env`) + +Key variables: + +| Variable | Default | Notes | +| :--------------------- | :---------------------- | :-------------------------------------- | +| `DB_HOST` | `localhost` | PostgreSQL host | +| `DB_PORT` | `5432` | PostgreSQL port | +| `JWT_SECRET` | — | Required, any random string | +| `REDIS_HOST` | `localhost` | Redis host | +| `REDIS_PORT` | `6380` | Redis port (mapped from container 6379) | +| `CORS_ALLOWED_ORIGINS` | `http://localhost:5173` | Frontend origin | + +### Web (`apps/web/.env`) + +| Variable | Default | Notes | +| :------------------------ | :------------------------- | :------------------ | +| `VITE_WEB3AUTH_CLIENT_ID` | Provided in `.env.example` | Web3Auth project ID | +| `VITE_API_URL` | `http://localhost:3000` | API endpoint | + +## Running the Web App + +```bash +# Install dependencies (first time) +pnpm install + +# Start API + web concurrently +pnpm dev +``` + +- API: +- Web: + +Or run individually: + +```bash +pnpm --filter @cipherbox/api dev # API only +pnpm --filter @cipherbox/web dev # Web only +``` + +## Running the Desktop App + +### Additional prerequisites + +- **macOS:** [FUSE-T](https://www.fuse-t.org/) (`brew install macos-fuse-t/homebrew-cask/fuse-t`) +- **Windows:** [WinFSP](https://winfsp.dev/) +- **Linux:** `libfuse3-dev` (or equivalent) + +```bash +cp apps/desktop/.env.example apps/desktop/.env +pnpm --filter @cipherbox/desktop dev +``` + +The desktop app defaults to the staging API. For local development, update `apps/desktop/.env`: + +```bash +VITE_API_URL=http://localhost:3000 +VITE_ENVIRONMENT=local +``` + +The Rust backend also needs the local API URL. Either set it in your shell or prefix the dev command: + +```bash +CIPHERBOX_API_URL=http://localhost:3000 pnpm --filter @cipherbox/desktop dev +``` + +See [apps/desktop/CLAUDE.md](../apps/desktop/CLAUDE.md) for FUSE architecture details and dev-key mode. + +## Testing + +### Unit tests + +```bash +# Run all unit tests (excludes E2E) +pnpm --filter @cipherbox/api test +pnpm --filter @cipherbox/web test +pnpm --filter @cipherbox/crypto test +``` + +> **Note:** `pnpm test` runs tests across all workspaces including E2E — use the filtered commands above for unit tests only. + +### E2E tests (Playwright) + +Playwright auto-starts API + web via `webServer` config (requires infra services: Postgres, IPFS, Redis): + +```bash +pnpm test:e2e +``` + +Headed mode (shows browser): + +```bash +pnpm test:e2e:headed +``` + +### Desktop E2E + +```bash +cd tests/e2e-desktop +pnpm exec playwright test +``` + +## API Client Generation + +After modifying API endpoints, DTOs, or controllers, regenerate the typed client to keep the web app in sync: + +```bash +pnpm api:generate +``` + +This generates the OpenAPI spec from the API, creates the typed client at `apps/web/src/api/`, and runs lint fixes. Always commit the regenerated files with your API changes. + +## Code Quality + +- **Linting:** `pnpm lint` (ESLint) / `pnpm lint:fix` +- **Markdown:** `pnpm lint:md` / `pnpm lint:md:fix` +- **Type checking:** `pnpm typecheck` +- **Formatting:** Prettier (runs via lint-staged on commit) +- **Commits:** [Conventional Commits](https://www.conventionalcommits.org/) enforced by commitlint (`feat:`, `fix:`, `docs:`, etc.)