4.6 KiB
4.6 KiB
Password Vault
An offline-first password manager that runs entirely in your browser. No server, no cloud, no tracking — your vault lives on your machine.
NOTE: This is majority vibe-coded with pi.dev and Qwen 3.6.
Features
- AES-256-GCM encryption — All credentials encrypted with a key derived from your master password via PBKDF2 (600,000 iterations). The key exists only in memory.
- Zero network calls — Works from
file://orlocalhost. No APIs, no analytics, no telemetry. - Group management — Organize entries into color-coded groups. Create, rename, delete.
- Full-text search — Instant search across title, username, URL, and notes.
- Password generator — One-click random password generation in the entry form (🎲 button). Uses Web Crypto API for cryptographically secure randomness.
- Copy to clipboard — One-click copy with 15-second auto-clear.
- JSON import/export — Export your vault as encrypted JSON with selective group filtering. Import with merge or replace mode.
- Auto-lock — Vault locks automatically on tab switch, visibility change, or 5-minute inactivity timer.
- Dark theme — Responsive layout that works on desktop and mobile.
Development
Quick Start
npm install
npm run build # → dist/index.html (single self-contained file)
npm run preview # test the production build locally
The build produces a single dist/index.html file with all JavaScript, CSS, and assets (including favicon) inlined as data URIs. No external files, no network requests — it works from:
file://protocol (opendist/index.htmldirectly)- Any static web server (nginx, Apache, GitHub Pages, etc.)
- USB stick, email attachment, or any offline medium
The single-file output is handled by vite-plugin-singlefile for JS/CSS inlining, plus a post-build script that inlines the favicon SVG and removes leftover asset files.
Encryption Flow
Master Password ──PBKDF2──→ 256-bit Key ──AES-GCM──→ Encrypted Credential
(600k iters)
│
└── Salt stored in IndexedDB (not encrypted)
- The encryption key is never persisted — it lives only in JavaScript memory.
- A test payload (random string) is encrypted on vault creation and stored alongside the salt. On unlock, the entered password is used to derive a key and decrypt the test payload — if decryption succeeds, the password is correct.
- On tab close or auto-lock, the key is cleared from memory.
Storage Schema (IndexedDB)
| Store | Fields |
|---|---|
entries |
id, title, username, encryptedPassword (encrypted), url, notes, groupId, tags, createdAt, updatedAt |
groups |
id, name, color, createdAt |
meta |
salt, testEncrypted, testPlaintext, dbVersion |
Security Considerations
| Threat | Mitigation |
|---|---|
| Key persistence | Key stored only in $state, cleared on lock/close |
| Weak passwords | 16-character default with mixed character types |
| Clipboard leakage | Auto-clear after 15 seconds |
| Tab left open | Auto-lock on visibility change (tab switch) |
| Database tampering | Passwords encrypted at rest with AES-256-GCM |
| Brute force | PBKDF2 with 600,000 iterations slows offline attacks |
Known limitations
- No browser fingerprinting or anti-keylogger — This is a local tool, not a hardened security appliance.
- IndexedDB can be inspected — Only
encryptedPasswordis encrypted at rest. Titles, usernames, URLs, and notes are stored in plaintext for searchability and are visible if the database is inspected. - Test plaintext stored in IndexedDB — The
testPlaintextvalue used for password verification is stored unencrypted in themetastore. An attacker with access to IndexedDB could use it to verify guessed passwords alongside the salt. - No automatic backups — Use the JSON export feature to back up your vault regularly.
Development
npm run dev # Start dev server with HMR
npm run build # Production build (zero warnings target)
npm run preview # Preview production build
Stack
- Svelte 5 — Runes-based reactivity (
$state,$derived,$effect), props-based event passing - Vite 8 — Build tool and dev server
- vite-plugin-singlefile — Inlines all JS/CSS into a single HTML file
- idb — Promise-based IndexedDB wrapper
- Web Crypto API — Native browser cryptography (no external crypto libraries)
- Vanilla CSS — Dark theme with CSS custom properties, no preprocessors
License
MIT