release: v0.41.1 — passkeys shipped + QA blind-spot fixes + standards unification
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
parent
88a32a983f
commit
55b2baee5f
18
HISTORY.md
18
HISTORY.md
|
|
@ -1,5 +1,23 @@
|
|||
# Bill Tracker — Changelog
|
||||
|
||||
## v0.41.1
|
||||
|
||||
### 🔐 Passkeys / security keys — WebAuthn finally reachable
|
||||
|
||||
- **[Auth] Passkey & hardware-security-key sign-in shipped end to end.** The WebAuthn backend existed since v0.36 but no UI ever called it — a ghost feature (was QA-B1-01). Now: the login page runs a security-key second step that mirrors TOTP (prompt fires right after the password; cancel/retry handled), and Profile gains a **Passkeys & Security Keys** card (enroll with a name, list keys, password-gated remove / remove-all). Deploy note: set **`WEBAUTHN_RP_ID`** (see `.env.example`) — keys bind to the hostname, and a boot warning now fires if it's unset in production. Origin verification also accepts the browser's real origin when its hostname matches the RP ID, fixing enrollment behind the Vite dev/e2e proxy. Covered end to end by `e2e/webauthn.probe.spec.js` using Playwright's virtual authenticator — no human with a YubiKey required.
|
||||
|
||||
### 🐛 QA Fixes (2026-07-10 blind-spot recon)
|
||||
|
||||
- **[Auth] Login self-lockout for WebAuthn-enabled users.** `authService.login` returned a `requires_webauthn` payload, but `POST /login` only handled `requires_totp` and crashed into a 500 on every attempt — anyone who enabled WebAuthn via the API was permanently locked out. The route now returns the two-step payload, and a stale `webauthn_enabled` flag with no usable credentials falls back to password login instead of hard-failing. Test: `tests/authLoginWebauthnRoute.test.js`. (was QA-B1-01, lockout part)
|
||||
- **[Client] Session expiry mid-use now redirects to login.** `useAuth` only checked `/auth/me` on mount, so an expired session left the app half-alive with raw 401 toasts. `api.ts` dispatches `auth:expired` on a 401 outside `/auth/*` (under `/auth/*` a 401 means wrong credential input and must not log you out); `AuthProvider` clears the user and `RequireAuth` redirects preserving the return path. Test: `client/api.sessionExpiry.test.ts`. (error-handling audit)
|
||||
- **[API] Raw `err.message` no longer leaks on 5xx.** Ten call sites returned internal error text to clients on server failures (admin bank-sync/rollback, notification test-sends, spending, bulk unmatch, import); the conversion sweep found ten more of the same class (dataSources, subscriptions, bills). All masked now — intentional user-facing messages survive only via explicit `ApiError` wraps or 4xx service statuses. (was QA-B13-02)
|
||||
- **[Auth] Dead duplicate admin routes removed from `routes/auth.cts`.** The "MOUNTED AT /api/admin" section was false — the canonical copies live in `admin.cts`; the duplicates were unreachable and additionally exposed `/api/auth/has-users` without authentication. (was QA-B17-01)
|
||||
- **[Version] `package.json` synced with the release (0.40.0 → 0.41.x drift).** `/api/version`, the release-notes badge, and the update checker all read package.json and were under-reporting. `tests/versionSync.test.js` now fails the suite if package.json and the top `HISTORY.md` heading ever drift again. (was QA-B0-03)
|
||||
|
||||
### 🧹 QA — standards unification (throw-pattern complete + enforced)
|
||||
|
||||
- **[Server] All 29 route files now emit errors through the canonical throw-pattern** (`utils/apiError.cts` factories → terminal handler), finishing the program CODE_STANDARDS tracked at 6/29. Wire shapes preserved (probe suite proves it over real HTTP); client-visible codes kept (`ALREADY_MATCHED`, `DUPLICATE_SUSPECTED`, `TRANSACTION_PAYMENT_LOCKED`, `NO_DEBTS`, `INVALID_PLAN_STATE`, …); deliberate exceptions documented inline and in CODE_STANDARDS.md. Enforced from here on by an eslint `no-restricted-imports` ratchet on `routes/**`, plus `no-console` on the server (logger-only, two sanctioned bootstrap exceptions). `client/api.ts` builds every thrown error through a single `toApiError()`.
|
||||
|
||||
## v0.41.0
|
||||
|
||||
### 🚀 Express 4 → 5 (Phase 2) — modern framework + native async error handling
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "bill-tracker",
|
||||
"version": "0.41.0",
|
||||
"version": "0.41.1",
|
||||
"description": "Monthly bill tracking system",
|
||||
"main": "server.cts",
|
||||
"engines": {
|
||||
|
|
|
|||
Loading…
Reference in New Issue