Skip to content

Repository files navigation

certwarden

Self-hosted dashboard for the Spanish digital certificates (FNMT / Cl@ve style) that agencies and firms hold for their clients. It watches certificate folders — local or on SMB/CIFS network shares — reads expiry dates, groups certificates by holder identity, and sends renewal reminders by email + calendar invite (.ics).

LAN-only by design: no outbound calls except to the SMTP server you configure and to the SMB/CIFS file servers an admin explicitly adds in the UI.

Features

  • Folder watcher — drop a certificate into the watched folder and it appears in the UI within a second (chokidar, with hot-restart when the folder changes). An unreadable directory is treated as unknown state, never as empty: the catalog is never pruned because a share blinked.
  • Modern PKCS#12 parsing.p12/.pfx files as exported by OpenSSL 3.x / current FNMT (PBES2 + AES-256) are parsed by delegating to the OpenSSL CLI with a -legacy fallback for old RC2/3DES bundles. Passwords are passed via environment, never argv. Also reads PEM, DER and .cer/.crt (detecting DER disguised as PEM).
  • Identity grouping — certificates are grouped by holder (DNI/NIE extracted from the subject, e.g. FNMT's IDCES-… serial numbers). Superseded versions of the same holder are collapsed under the newest one, and automatic alerts only fire for the current version — no false alarms for certificates you already renewed.
  • PKCS#12 password from filename — configurable regex; by default the password is read between parentheses: NAME_NIF (PASSWORD).p12. A per-certificate manual override is also available (stored AES-256-GCM encrypted, with rollback if the new password breaks a previously parsing certificate, and throttled to keep the endpoint from acting as a password oracle).
  • SMB/CIFS network shares — discover, mount and watch shares from the UI. Credentials are stored AES-256-GCM encrypted (scrypt-derived key); at mount time they are written as 0600 files on a RAM-only tmpfs and deleted in a finally. Mount options are whitelisted, child processes get a minimal environment, and every log line is scrubbed of secrets. An optional SMB_ALLOWED_CIDRS egress allowlist is available.
  • Expiry scanning + automatic digest — a daily cron flags certificates expiring within configurable warning/critical windows, and an automatic email digest (grouped by severity, deduplicated so the same alarm is not repeated every day) keeps the team informed.
  • Renewal scheduling — pick a date and the server emails an .ics invite; reminders retry with exponential backoff, distinguishing permanent SMTP failures from transient ones. Bulk .ics export for up to 200 certificates at once.
  • Realtime UI — an authenticated WebSocket pushes certificate changes to the dashboard as they happen (session-cookie auth reused in the upgrade handshake, ping/pong heartbeat, client reconnection with backoff).
  • Local users — bcrypt + session cookie. Login is protected by a three-bucket brute-force throttle designed so an attacker exhausts their own budget before they can lock out the victim, plus timing padding on failures and session regeneration after login. The server refuses to boot with a weak or default SESSION_SECRET, and the first-admin bootstrap is closed behind a token by default.
  • Safe deletion — deleting a certificate archives the file into a .trash/ folder; the server never unlinks certificate material.
  • Single Docker image — Express 5 serves both the API and the built Angular SPA on one port. Optional nginx reverse-proxy profiles (HTTP or TLS) and a systemd autostart installer are included, plus scripts to bundle the image + data for turnkey delivery to an offline client server.

Quick start (Docker)

cp .env.example .env
# Edit .env — at minimum set SESSION_SECRET (32+ chars; the server refuses weak secrets).
docker compose up -d

Open http://your-server:4000, create the first (admin) account, then configure SMTP under Settings.

Drop certificates into ./data/certificates/ on the host — they show up in the dashboard within a second.

PKCS#12 password convention

The default regex is \(([^()]+)\)(?:_\d+)?\.(?:p12|pfx)$ — the password is taken from the parentheses in the filename. Example: maria_lopez_12345678Z (MyP4ss).p12 uses password MyP4ss. Change the pattern in Settings → Certificates or via the P12_PASSWORD_REGEX env var, or set a per-certificate override from the certificate's detail view.

Local development

pnpm install
pnpm dev          # api on :4000, Angular dev server on :4200 (proxied to api)

Demo dataset

pnpm demo:start builds and starts the app with a realistic synthetic FNMT-style dataset (18 generated certificates covering multi-version holders, representation certificates and a wrong-password case) — useful for walkthroughs. All demo data is generated locally by scripts/gen-test-certs.ts; nothing real is included.

Project layout

server/   Express 5 + better-sqlite3 + chokidar + node-cron + nodemailer (ESM, TypeScript)
web/      Angular 21 standalone components + signals + Tailwind v4
scripts/  Demo dataset generator, client-delivery bundling, autostart installer
deploy/   Optional nginx reverse-proxy configs (HTTP / TLS)
data/     Bind-mounted at runtime — SQLite DB and the certificates/ folder

Security notes

  • Sessions live in SQLite; the cookie is httpOnly + sameSite=lax. Put a TLS-terminating reverse proxy in front if you serve beyond a trusted LAN (a ready-made nginx TLS profile is included).
  • PKCS#12 filename passwords are used to parse metadata. A manual per-certificate password override, when set by an admin, is persisted encrypted (AES-256-GCM under a key derived from CREDENTIAL_ENCRYPTION_KEY); the certificate-install endpoint that returns it is admin-only and audited.
  • SMB credentials are stored encrypted and never reach argv, logs or child-process environments.
  • No telemetry. Outbound traffic is limited to your configured SMTP server and explicitly added SMB/CIFS servers.

License

MIT

About

Self-hosted dashboard for Spanish FNMT/Cl@ve digital certificates: folder & SMB/CIFS watching, expiry tracking, identity grouping, email + .ics renewal reminders. Angular 21 + Express 5 + SQLite, single Docker image.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages