2026-05-19 11:19:20 -04:00
2026-05-19 09:31:33 -04:00
2026-05-19 09:44:51 -04:00
2026-05-19 10:35:34 -04:00
2026-04-26 10:10:29 -04:00
2026-05-22 11:00:30 -04:00
2026-04-18 21:00:19 -04:00
2026-05-22 11:00:30 -04:00
2026-04-16 08:27:07 -04:00
2026-04-16 08:27:07 -04:00
2026-04-16 08:27:07 -04:00

PassKeeper 🔐

A self-hosted, zero-knowledge password manager — web app and Chrome/Firefox extension. Your master password and decrypted vault data never leave your browser.


Features

Web App

  • Zero-knowledge encryption — AES-256-GCM client-side; 600k-iteration PBKDF2 vault key
  • 7 item types — Passwords, Secure Notes, Cards, Bank Accounts, Addresses, Identities, Passkeys
  • Vault item tags — comma-separated tags stored inside the encrypted blob; sidebar tag filter; live badge preview in modal; no schema change required
  • Collapsible folder groups — click any folder header in the vault list to collapse/expand; item count badge and chevron indicator; state persists across re-renders
  • TOTP / 2FA — per-site TOTP codes stored in plain.totp_uri; live 6-digit display with countdown
  • Folder organisation — create, rename, delete; filter vault by folder
  • Item sharing — ECDH P-256 zero-knowledge re-encryption; item name encrypted with shared key — server never sees it
  • Emergency access — configurable wait-timer access grant for a trusted contact
  • Security dashboard — weak / reused / old / no 2FA saved / HaveIBeenPwned breach check (k-anonymity — passwords never transmitted)
  • Proactive health notifications — sidebar badge and dismissible banner on vault load when breached, weak, or reused passwords are detected; HIBP runs in the background without blocking the UI; results cached so opening the Security tab is instant
  • Import / Export — encrypted JSON backup; CSV export (plaintext, handle carefully); import from Chrome, Bitwarden, and 1Password CSV formats (RFC 4180 compliant parser)
  • Account MFA — TOTP-based login (Google Authenticator / Authy); single-use code enforcement prevents replay attacks
  • Passkeys / WebAuthn — register device biometrics or hardware keys (YubiKey, cross-device QR) as a sign-in method; master password still required to unlock vault (zero-knowledge preserved); manage passkeys in Account Settings; transport type shown per credential (📱 Device / 🔑 Security key)
  • Master password change — atomic zero-knowledge re-encryption of entire vault including item names and ECDH sharing private key; sharing continues to work after password change
  • Account recovery — 128-bit recovery code; server never stores it; challenge-response proof prevents forgery; vault item names re-encrypted along with vault data; recovery key uses per-user email as PBKDF2 salt
  • Audit log — server-side trail of all create/edit/delete/import/export actions; no plaintext names ever logged
  • Encrypted item namesenc_name/iv_name; server holds only the item type as a label
  • Browser history — back/forward button works for all views (history.pushState)
  • Web-app auto-lock — configurable inactivity timeout (5/10/15/30/60 min or Never); also locks immediately when tab is hidden (screen lock, minimize) for longer than the timeout
  • Clipboard auto-clear — sensitive copies cleared after 30 seconds
  • Responsive layout — phone, tablet, laptop, large desktop; collapsible sidebar

Browser Extension (Chrome / Edge — Manifest V3 + Firefox — Manifest V2)

  • Autofill — detects login forms; injects icon into username and password fields only (scored heuristic, not all inputs)
  • Smart domain matching — matches by domain name; handles bare domains (github.com) and subdomains
  • Suggestion dropdown — filters as you type; keyboard navigation (↑↓ Enter); one-click fill
  • Collapsible folder groups — "All items" tab groups by folder with collapse/expand toggle matching the web app UX
  • Favorites tab — items tagged favorite in the web app appear in a dedicated tab; marked with ★
  • Tag display — purple badge pills on item rows; tags sourced from plain.tags[]
  • Three-dot flyout menu — contextual actions: Open URL / Copy username / Copy password; built dynamically from what the item has
  • Dedicated copy-username button — person icon alongside copy-password in every item row
  • Auto-save banner — save/update credentials on form submit; duplicate detection; "Never for this site" blocklist
  • Pending-save badge — red ! on toolbar icon when a credential is waiting to be saved
  • Inline password generator — fully CSPRNG (crypto.getRandomValues throughout, Math.random never called)
  • TOTP live display — 6-digit code + countdown per item
  • SSO bridge — log in once on the web app; extension picks up the session
  • Idle lock — configurable auto-lock (1/5/10/30 min or Never)
  • Clipboard auto-clear — passwords/usernames cleared from clipboard after 30 seconds
  • Keyboard shortcutCtrl+Shift+L / Cmd+Shift+L to open popup (customisable at chrome://extensions/shortcuts)
  • Firefox compatible — separate MV2 manifest + background script; same popup/content/bridge code

Security Architecture

Master Password
      │
      ├─ PBKDF2(email, 100k iter)  ──►  authHash  ──►  POST /api/auth/login
      │                                                  Argon2id(authHash) stored in DB
      │                                                  (transparently rehashed if params upgraded)
      │
      └─ PBKDF2(enc_key_salt, 600k iter)  ──►  vaultKey (browser memory only)
                                                    │
                                            AES-256-GCM encrypt
                                                    │
                                      enc_data + iv     (item payload + tags)
                                      enc_name + iv_name (item name)
                                            │
                                      POST /api/vault  ──►  Server stores ciphertext only

Sharing:  ECDH(Alice_priv, Bob_pub) ──► sharedKey ──► AES-256-GCM(enc_data + enc_name)
          Server stores only ciphertext — cannot read item content or item name

Security hardening highlights

  • TOTP replay prevention — each 6-digit code is single-use (120s window); recorded in totp_used_codes table
  • Recovery proofenc_key_salt not returned by server during recovery; client must decrypt the recovery blob to prove code possession
  • folder_id ownership — all create/update/import operations validate folder belongs to current user
  • Audit log privacy — item names and shared item names never appear in server-side audit logs
  • Extension fingerprintingweb_accessible_resources: [] blocks external pages from probing extension files
  • Passkey / WebAuthn — FIDO2 assertion proves identity to the server without a password; vault key still derived from master password client-side; sign_count updated on each use for clone detection
  • Password age trackingpassword_changed_at stored inside encrypted blob; security dashboard uses actual password change date, not item creation date
  • Emergency access stale snapshot detection — server flags provisioned snapshots created before the enc_name fix; UI prompts grantor to re-provision
  • Recovery key hardening — recovery key derived with PBKDF2(recoveryCode, userEmail, 200k iter); per-user email salt prevents cross-account recovery code reuse; legacy 'passkeeper-recovery' salt accepted transparently for existing codes

A database breach exposes only encrypted ciphertext. The server cannot read vault names, passwords, tags, or shared item names.


Tech Stack

Layer Technology
Backend Python 3.12, Flask 3.x
Database MySQL 8.x
Frontend Vanilla JS, Web Crypto API, Jinja2
Auth Argon2id + PBKDF2 + JWT (HS256) + WebAuthn (FIDO2)
Encryption AES-256-GCM (client-side)
Extension Chrome MV3 / Firefox MV2
Web server Nginx + Gunicorn + systemd
Rate limiting Flask-Limiter + Redis
TLS Let's Encrypt / Certbot

Getting Started

Prerequisites

  • Python 3.12+
  • MySQL 8.x
  • No Node.js or build step required

Development (Windows)

git clone https://github.com/yourname/passkeeper
cd passkeeper
python -m venv .venv
.venv\Scripts\activate
pip install -r requirements.txt
copy .env.example .env

Edit .env:

FLASK_ENV=development
SECRET_KEY=<64-char hex>
JWT_SECRET_KEY=<64-char hex>
MYSQL_HOST=localhost
MYSQL_USER=passkeeper
MYSQL_PASSWORD=yourpassword
MYSQL_DB=passkeeper
TOTP_ENCRYPTION_KEY=<64-char hex>
mysql -u root -p -e "CREATE DATABASE passkeeper CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -u root -p -e "CREATE USER 'passkeeper'@'localhost' IDENTIFIED BY 'yourpassword'; GRANT ALL ON passkeeper.* TO 'passkeeper'@'localhost'; FLUSH PRIVILEGES;"
python reset_db.py
python run.py

Generate secrets:

python -c "import secrets; print(secrets.token_hex(32))"

Load the Extension (Chrome)

  1. chrome://extensions/ → Enable Developer mode
  2. Load unpacked → select extension/ folder
  3. Reload after any JS/CSS changes

Load the Extension (Firefox)

  1. about:debuggingThis FirefoxLoad Temporary Add-on
  2. Select extension/manifest.firefox.json

Production Deployment

1. Server dependencies

sudo apt update && sudo apt install python3.12 python3.12-venv mysql-server nginx \
    certbot python3-certbot-nginx redis-server

2. Application setup

cd /var/www/passkeeper
python3.12 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .env   # set production values
flask db upgrade       # run all migrations

3. systemd service

sudo cp scripts/passkeeper.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl enable --now passkeeper

4. Nginx

sudo cp scripts/passkeeper-nginx.conf /etc/nginx/sites-available/passkeeper
sudo ln -s /etc/nginx/sites-available/passkeeper /etc/nginx/sites-enabled/
sudo certbot --nginx -d yourdomain.com
sudo nginx -t && sudo systemctl reload nginx

5. Future schema migrations

flask db upgrade && sudo systemctl reload passkeeper

Environment Variables

Variable Description
SECRET_KEY Flask session secret (64-char hex)
JWT_SECRET_KEY JWT signing secret (64-char hex)
MYSQL_HOST / MYSQL_USER / MYSQL_PASSWORD / MYSQL_DB Database
TOTP_ENCRYPTION_KEY Server-side AES key for TOTP secrets (64-char hex)
RATELIMIT_STORAGE_URI Redis URI — required in production (redis://127.0.0.1:6379/0)
CORS_ORIGINS Allowed origins (* in dev, domain in prod)
WEBAUTHN_RP_ID Passkey relying party ID — effective domain, no scheme (pwkeeper.ngodanguyen.tech)
WEBAUTHN_RP_NAME Passkey relying party display name (PassKeeper)
WEBAUTHN_ORIGINS Comma-separated allowed origins for WebAuthn (https://pwkeeper.ngodanguyen.tech)

Project Structure

passkeeper/
├── app/                  # Flask application
│   ├── models/           # SQLAlchemy models
│   ├── routes/           # API blueprints (auth, vault, folders, sharing, emergency)
│   ├── services/         # Auth (Argon2id, JWT, TOTP encryption, TOTP replay helpers)
│   ├── static/js/        # Client-side crypto + vault UI
│   └── templates/        # Jinja2 templates
├── extension/            # Browser extension
│   ├── popup/            # Popup UI
│   ├── content/          # Content script (autofill, field detection)
│   ├── shared/           # Shared crypto + Firefox polyfill
│   ├── bridge/           # SSO bridge
│   ├── background.js          # Chrome MV3 service worker
│   ├── background.firefox.js  # Firefox MV2 background page
│   ├── manifest.json          # Chrome/Edge MV3
│   └── manifest.firefox.json  # Firefox MV2
├── migrations/           # Alembic migration scripts
├── scripts/              # Nginx, systemd, backup
└── requirements.txt

API Overview

All vault/folder endpoints require Authorization: Bearer <access_token>.

Method Endpoint Description
POST /api/auth/register Create account
POST /api/auth/login Authenticate
POST /api/auth/mfa/verify Complete MFA (single-use code)
POST /api/auth/refresh Rotate tokens
POST /api/auth/logout Blacklist tokens
GET /api/vault List encrypted items
POST /api/vault Create item (enc_data, iv, enc_name, iv_name, tags in payload)
PUT /api/vault/<id> Update item
DELETE /api/vault/<id> Delete item
GET /api/vault/export Download encrypted JSON backup
POST /api/vault/import Bulk import; returns { imported, skipped }
GET/POST /api/folders List / create folders
POST /api/sharing Share item — sends enc_name/iv_name for ZK name
POST /api/emergency Create emergency access grant
POST /api/auth/change-password Atomic vault re-encryption
POST /api/auth/recover Account recovery (one-time)
POST /api/webauthn/register/begin Start passkey registration
POST /api/webauthn/register/complete Finish passkey registration
POST /api/webauthn/authenticate/begin Start passkey login
POST /api/webauthn/authenticate/complete Complete passkey login → tokens
GET /api/webauthn/credentials List registered passkeys
DELETE /api/webauthn/credentials/<id> Remove a passkey

Item Tagging

Tags are stored as plain.tags: string[] inside the encrypted vault blob — the server never sees them and no schema change is required.

Web app: Add tags in the item edit modal (comma-separated). Tags appear as purple badge pills on item rows. A Tags section in the sidebar lets you filter by any tag. Search respects the active tag filter.

Extension: Tags appear as .pk-tag badges on item rows. Items tagged favorite appear in the Favorites tab and show a ★ in the site label.


Backup

# Install cron job
sudo cp scripts/passkeeper-logrotate /etc/logrotate.d/passkeeper
crontab scripts/backup.cron

# Manual backup
bash scripts/backup_db.sh

Licence

MIT — see LICENSE.


Roadmap

# Feature Notes
1 One-time share links Single-use encrypted link for non-account recipients; key in URL fragment
2 Custom fields Arbitrary key-value pairs per item; stored in encrypted blob
3 Trusted devices Skip MFA for N days on trusted browsers
4 Email notifications Alert on login from new IP, MFA changes, password change
5 Audit log improvements Filter by type/date, CSV export, pagination
6 Vault item attachments Client-side encrypted file attachments per item
7 Collections / nested folders Group folders into top-level collections
8 iOS AutoFill Extension Native credential filling in Safari and iOS apps
9 Extension TOTP QR capture Detect and save TOTP secrets during 2FA setup
10 Admin panel User management for multi-user deployments
11 Backup verification cron Weekly automated restore test
12 Health check endpoint GET /health for uptime monitors
S
Description
Password Manager application
Readme
1.2 MiB
Languages
JavaScript 56.4%
Python 27.1%
HTML 7.7%
CSS 7.4%
Shell 1.4%