- Add Vault Encryption section documenting Argon2id + AES-256-GCM scheme - Document key derivation parameters (256MB memory, 4 threads, 8 iterations) - Add Permission System section with reckless mode and whitelist info - Update Angular version to 19, add Argon2Crypto to common library exports - Expand SignerMetaHandler description with reckless mode and whitelist Files modified: - CLAUDE.md - package.json 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
4.6 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
Plebeian Signer is a browser extension for managing multiple Nostr identities and signing events without exposing private keys to web applications. It implements NIP-07 (window.nostr interface) with support for NIP-04 and NIP-44 encryption.
Build Commands
npm ci # Install dependencies
npm run build:chrome # Build Chrome extension (outputs to dist/chrome)
npm run build:firefox # Build Firefox extension (outputs to dist/firefox)
npm run watch:chrome # Development build with watch mode for Chrome
npm run watch:firefox # Development build with watch mode for Firefox
npm test # Run unit tests with Karma
npm run lint # Run ESLint
Important: After making any code changes, rebuild both extensions before testing:
npm run build:chrome && npm run build:firefox
Architecture
Monorepo Structure
This is an Angular 19 CLI monorepo with three projects:
- projects/chrome: Chrome extension (MV3)
- projects/firefox: Firefox extension
- projects/common: Shared Angular library used by both extensions
Extension Architecture
The extension follows a three-layer communication model:
-
Content Script (
plebian-signer-content-script.ts): Injected into web pages, bridges messages between page scripts and the background service worker -
Injected Script (
plebian-signer-extension.ts): Injected into page context, exposeswindow.nostrAPI to web applications -
Background Service Worker (
background.ts): Handles NIP-07 requests, manages permissions, performs cryptographic operations
Message flow: Web App → window.nostr → Content Script → Background → Content Script → Web App
Storage Layers
- BrowserSyncHandler: Encrypted vault data synced across browser instances (or local-only based on user preference)
- BrowserSessionHandler: Session-scoped decrypted data (unlocked vault state)
- SignerMetaHandler: Extension metadata (sync flow preference, reckless mode, whitelisted hosts)
Each browser (Chrome/Firefox) has its own handler implementations in projects/{browser}/src/app/common/data/.
Vault Encryption (v2)
The vault uses Argon2id + AES-256-GCM for password-based encryption:
- Key derivation: Argon2id with 256MB memory, 4 threads, 8 iterations (~3 second derivation)
- Encryption: AES-256-GCM with random 12-byte IV per encryption
- Salt: Random 32-byte salt per vault (stored in
BrowserSyncData.salt) - The derived key is cached in session storage (
BrowserSessionData.vaultKey) to avoid re-derivation on each operation
Note: Argon2id runs on main thread via WebAssembly (hash-wasm) because Web Workers cannot load external scripts in browser extensions due to CSP restrictions. A deriving modal provides user feedback during the ~3 second operation.
Custom Webpack Build
Both extensions use @angular-builders/custom-webpack to bundle additional entry points beyond the main Angular app:
background.ts- Service workerplebian-signer-extension.ts- Page-injected scriptplebian-signer-content-script.ts- Content scriptprompt.ts- Permission prompt popupoptions.ts- Extension options page
Common Library
The @common import alias resolves to projects/common/src/public-api.ts. Key exports:
StorageService: Central data management with encryption/decryptionCryptoHelper,NostrHelper: Cryptographic utilities (nostr-tools based)Argon2Crypto: Vault encryption with Argon2id key derivation- Shared Angular components and pipes
Permission System
Permissions are stored per identity+host+method combination. The background script checks permissions before executing NIP-07 methods:
allow/denypolicies can be stored for each method- Kind-specific permissions supported for
signEvent - Reckless mode: Auto-approves all actions without prompting (global setting)
- Whitelisted hosts: Auto-approves all actions from specific hosts
Testing Extensions Locally
Chrome:
- Navigate to
chrome://extensions - Enable "Developer mode"
- Click "Load unpacked"
- Select
dist/chrome
Firefox:
- Navigate to
about:debugging - Click "This Firefox"
- Click "Load Temporary Add-on..."
- Select a file in
dist/firefox
NIP-07 Methods Implemented
getPublicKey()- Return public keysignEvent(event)- Sign Nostr eventgetRelays()- Get configured relaysnip04.encrypt/decrypt- NIP-04 encryptionnip44.encrypt/decrypt- NIP-44 encryption