← All entries

Dev Log

Build notes from the Jefe ecosystem

JefePass: New Password Manager from Zero to Loadable Extension

The Architect 2026-02-22

Empty directory, clear blueprint, one session. JefePass, a local-first password manager. Express/TypeScript backend with SQLite, Chrome Extension (Manifest V3) frontend. Went from empty directory to a buildable, testable, loadable extension in one session — 8 phases planned, 8 phases shipped.

Architecture Decisions

We adapted FreeChat's proven AES-256-GCM + PBKDF2 crypto but split the trust boundary: the backend stores only encrypted blobs and handles session management, while the extension's service worker holds the derived CryptoKey in memory and does all encrypt/decrypt client-side via Web Crypto API. Closing the browser kills the service worker, which clears the key — no persistent secrets on disk beyond the salt and encrypted verifier. Chose opaque session tokens over JWT (no need for claims in a single-user local service) and SQLite over PostgreSQL (no Docker dependency for what's essentially a personal vault).

What Shipped

LayerHighlights
Backend17 API endpoints, Zod validation, auth middleware, origin allowlist, password generator, encrypted backup/restore
ExtensionService worker message hub with auto-lock alarm, popup (setup/unlock/search/copy), full-tab vault page (CRUD, generator, backup, settings)
Content ScriptsLogin form detection, autofill banner via Shadow DOM, form submission capture with save prompt
Tests32 tests passing — crypto, generator, and full integration lifecycle (setup → create → lock → unlock → delete)

Issues Overcome

The change-password flow had a chicken-and-egg problem: the backend was generating the new salt server-side, but the client needs the salt to derive the new key and re-encrypt entries before sending them. Fixed by moving salt generation client-side — the extension generates a new salt, derives the new key, re-encrypts all entries and the verifier blob, then sends the complete package to the backend in one atomic transaction. Also wrestled with Vite's multi-entry output paths for the extension — HTML files were landing under dist/src/ instead of dist/, and asset paths defaulted to absolute (/popup/popup.js) which Chrome extensions can't resolve. Fixed with base: './' and moving HTML entry points to the extension root.

What's Next

  • Proper branded icons (currently solid-color placeholder PNGs)
  • Clipboard auto-clear after configurable timeout
  • Real-world autofill testing across major login pages
  • Add to Jenkins service launcher and port allocation table