password_manager/README.md

125 lines
5.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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.
## Features
- **AES-256-GCM encryption** — All credentials encrypted with a key derived from your master password via PBKDF2 (100,000 iterations). The key exists only in memory.
- **Zero network calls** — Works from `file://` or `localhost`. 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** — Configurable length (464), character types, custom exclusions, strength indicator.
- **Copy to clipboard** — One-click copy with 15-second auto-clear.
- **JSON import/export** — Export your entire vault as encrypted JSON. Import with merge or replace mode.
- **Auto-lock** — Vault locks automatically on tab switch, visibility change, or configurable inactivity timer.
- **Dark theme** — Responsive layout that works on desktop and mobile.
## Quick Start
```bash
npm install
npm run dev # http://localhost:5173
```
## Production Build
```bash
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 (open `dist/index.html` directly)
- 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`](https://www.npmjs.com/package/vite-plugin-singlefile) for JS/CSS inlining, plus a post-build script that inlines the favicon SVG and removes leftover asset files.
## Architecture
```
src/
├── App.svelte # Root — toggles LockScreen ↔ MainLayout
├── main.js # Entry point
├── components/
│ ├── LockScreen.svelte # Vault creation & password unlock
│ ├── MainLayout.svelte # Dashboard shell (sidebar + content)
│ ├── Sidebar.svelte # Group list, search, group CRUD
│ ├── EntryList.svelte # Searchable/filterable entry table
│ ├── EntryDetail.svelte # View single entry, copy, delete
│ ├── EntryForm.svelte # Create/edit entry with validation
│ ├── PasswordGenerator.svelte # Standalone generator panel
│ └── ImportExport.svelte # JSON import/export modals
├── lib/
│ ├── crypto/crypto.js # PBKDF2 key derivation, AES-GCM, generator
│ ├── models/schema.js # Data factories, validation, ID generation
│ ├── storage/db.js # IndexedDB wrapper (idb library)
│ └── stores/
│ ├── app.svelte.js # Reactive app state (lock/unlock)
│ ├── search.svelte.js # Shared search + filter state
│ └── security.svelte.js # Auto-lock timer, visibility detection
└── styles/
└── main.css # Dark theme, CSS variables, responsive
scripts/
└── inline-assets.js # Post-build: inlines favicon, removes leftover files
```
### Encryption Flow
```
Master Password ──PBKDF2──→ 256-bit Key ──AES-GCM──→ Encrypted Credential
(100k 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`, `password` (encrypted), `url`, `notes` (encrypted), `groupId`, `createdAt`, `updatedAt` |
| `groups` | `id`, `name`, `color`, `createdAt` |
| `meta` | `salt`, `testEncrypted`, `testPlaintext` |
## Security Considerations
| Threat | Mitigation |
|---|---|
| Key persistence | Key stored only in `$state`, cleared on lock/close |
| Weak passwords | Strength indicator on generator |
| Clipboard leakage | Auto-clear after 15 seconds |
| Tab left open | Auto-lock on visibility change (tab switch) |
| Database tampering | All sensitive data encrypted at rest with AES-256-GCM |
| Brute force | PBKDF2 with 100,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** — Encrypted data is safe, but metadata (titles, usernames, URLs) may be visible if not encrypted. Currently only `password` and `notes` are encrypted; titles/usernames/URLs are stored in plaintext for searchability.
- **No automatic backups** — Use the JSON export feature to back up your vault regularly.
## Development
```bash
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