diff --git a/CLAUDE.md b/CLAUDE.md index 0478fab..68012ee 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -9,12 +9,14 @@ A full-featured password manager web app and browser extension modelled after La ## Tech Stack ### Development (Windows) + - **Backend:** Python 3.12, Flask 3.x - **Database:** MySQL 8.x - **Frontend:** Vanilla JS (Web Crypto API) + Jinja2 templates - **Dev server:** `python run.py` ### Production (Ubuntu) + - **Web server:** Nginx (reverse proxy, TLS termination) - **WSGI server:** Gunicorn - **Process manager:** systemd @@ -148,12 +150,12 @@ CREATE TABLE vault_items ( ## Migration History -| Revision | Description | -|---|---| +| Revision | Description | +| -------------- | ------------------------------------------- | | `71d7158dd3b9` | Add audit_logs; fix sharing_public_key type | -| `a1b2c3d4e5f6` | Encrypt TOTP secret at rest | -| `b2c3d4e5f6a7` | Add account recovery columns | -| `c3d4e5f6a7b8` | Add enc_name + iv_name to vault_items | +| `a1b2c3d4e5f6` | Encrypt TOTP secret at rest | +| `b2c3d4e5f6a7` | Add account recovery columns | +| `c3d4e5f6a7b8` | Add enc_name + iv_name to vault_items | --- @@ -178,16 +180,18 @@ CREATE TABLE vault_items ( ## Extension Storage Architecture -| Data | Storage | Reason | -|---|---|---| -| `access_token`, `vault_key_jwk`, `vault_items`, `vault_items_cs` | `chrome.storage.session` | Memory-only, cleared on browser close | -| `refresh_token`, `enc_key_salt`, `pending_save`, `save_blocklist`, `idle_lock_seconds` | `chrome.storage.local` | Persists across restarts | -| Web-app session timeout | `localStorage` (`web_idle_minutes`) | Per-browser preference | +| Data | Storage | Reason | +| -------------------------------------------------------------------------------------- | ----------------------------------- | ------------------------------------- | +| `access_token`, `vault_key_jwk`, `vault_items`, `vault_items_cs` | `chrome.storage.session` | Memory-only, cleared on browser close | +| `refresh_token`, `enc_key_salt`, `pending_save`, `save_blocklist`, `idle_lock_seconds` | `chrome.storage.local` | Persists across restarts | +| Web-app session timeout | `localStorage` (`web_idle_minutes`) | Per-browser preference | ### Critical: `vault_items_cs` is in `session`, NOT `local` + Requires Chrome 111+. `content.js` `onChanged` listener watches `area === 'session'`. Do not revert — reverting persists decrypted passwords to disk. ### Pending-save badge + `background.js` sets a red `"!"` badge on `SAVE_CREDENTIALS`. Cleared via `CLEAR_SAVE_BADGE` when user acts on the save prompt in the popup. --- @@ -195,16 +199,19 @@ Requires Chrome 111+. `content.js` `onChanged` listener watches `area === 'sessi ## Key Implementation Details ### Vault item tags + - Stored as `plain.tags: string[]` inside `enc_data`. No schema change ever needed. - **Web app:** `_parseTags(str)` → comma-split, lowercase, dedup, sort. `_allTags()` collects across all items. `renderTagList()` builds sidebar. Tags field in modal has live badge preview. - **Extension:** `.pk-tag` badges below item subtitle. Favorites tab = items where `tags.includes('favorite')`. Favorited items show gold ★ in site label. - To favourite an item: add tag `favorite` in the web app edit modal. ### Collapsible folder groups + - **Web app:** `_collapsedGroups` Set persists state across re-renders. Header shows name + count badge + chevron (▼/▶). Click toggles and re-renders. - **Extension:** only on "All items" tab. `_folders` fetched in parallel with vault. `_collapsedFolders` Set. `folderName(id)` resolves to display name with `(none)` fallback. ### Import / Export + - **Encrypted JSON export:** `GET /api/vault` → versioned envelope → download. Zero-knowledge. - **CSV export:** decrypt client-side → `name, url, username, password, notes`. - **JSON import:** sends encrypted blobs to `POST /api/vault/import` directly. @@ -212,79 +219,95 @@ Requires Chrome 111+. `content.js` `onChanged` listener watches `area === 'sessi - Both endpoints write audit logs: `vault_item.export`, `vault_item.import`. ### Web-app session timeout + - `_startWebIdleTracking()` called at end of `init()`. Listens to `mousemove`, `mousedown`, `keydown`, `touchstart`, `scroll`. - On timeout: `VaultSession.clear()` → unlock overlay → toast. - Stored in `localStorage` as `web_idle_minutes`. Default 15 min. Options: Never/5/10/15/30/60. - Exposed in Account Settings → Auto-Lock (`