mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-14 20:21:09 +02:00
fix: 4 boot-time noise + correctness bugs surfaced by post-deploy smoke
All four were pre-existing; the audit smoke-test made them visible. Fixed
together because they share a "boot console-warn cleanup" theme.
1. streaks ensureSeeded race (DexieError2 ×2)
- Two boot-time liveQuery callers passed the `count > 0` check before
either had written, then the second's `.add()` hit a ConstraintError.
- Fix: cache the seed promise per module, run the existence check +
bulkAdd inside one Dexie RW transaction, and only insert MISSING
defs (preserves existing currentStreak/longestStreak counts).
2. encryptRecord('agents', …) "wrong table name?" warning
- The DEV-only check fired whenever a record carried none of the
registered encrypted fields, regardless of whether anything could
actually leak. `ensureDefaultAgent` writes a fresh agent row before
`systemPrompt` / `memory` exist — pure noise.
- Fix: drop the "no fields at all" branch. Keep the case-mismatch
branch (the branch that actually catches silent plaintext leaks).
3. Passkey signInWithPasskey "Cannot read properties of undefined
(reading 'allowCredentials')"
- Client destructured `{ options, challengeId }` from the server's
options response, but Better-Auth's `@better-auth/passkey` plugin
returns the raw PublicKeyCredentialRequestOptionsJSON (no
envelope) and tracks the challenge in a signed cookie. Both
`options` and `challengeId` came back undefined; SimpleWebAuthn
blew up the moment it tried to read the request shape. Verify body
`{ challengeId, credential }` was likewise wrong — Better-Auth
wants `{ response }`.
- Fix: align both register and authenticate flows with Better-Auth's
native shape on options + verify, and add `credentials: 'include'`
on every fetch so the challenge cookie actually round-trips.
Server's verify proxy now reads `parsed?.response?.id` for
credentialID rate-limiting.
4. /api/v1/me/onboarding/ → 404
- Hono's nested router (`app.route(prefix, sub)` + inner
`app.get('/')`) matches the prefix-without-slash form only. The
onboarding-status store sent the request with a trailing slash, so
every login produced a 404 + a console warn.
- Fix: client sends the path without trailing slash; mana-auth picks
up `hono/trailing-slash` middleware as defense-in-depth so a future
accidental trailing slash on any /me/* route 301-redirects instead
of 404-ing.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
44f9155ed3
commit
0c30a16eb5
6 changed files with 106 additions and 55 deletions
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { trimTrailingSlash } from 'hono/trailing-slash';
|
||||
import { loadConfig } from './config';
|
||||
import { getDb } from './db/connection';
|
||||
import { createBetterAuth } from './auth/better-auth.config';
|
||||
|
|
@ -78,6 +79,14 @@ const app = new Hono();
|
|||
|
||||
app.onError(errorHandler);
|
||||
app.use('*', requestLogger());
|
||||
// Defense-in-depth for clients that accidentally request the trailing-slash
|
||||
// form of a route (e.g. `/api/v1/me/onboarding/`). Hono's nested-router root
|
||||
// match-up doesn't include the prefix-with-slash variant, so without this
|
||||
// middleware those clients get a 404 even though the same path-without-slash
|
||||
// would work. Trims the slash and 301-redirects on GET/HEAD, only when a
|
||||
// non-trimmed lookup already produced a 404 — so the legitimate root path
|
||||
// `/` is never touched.
|
||||
app.use('*', trimTrailingSlash());
|
||||
app.use(
|
||||
'*',
|
||||
cors({
|
||||
|
|
|
|||
|
|
@ -159,14 +159,17 @@ export function createPasskeyRoutes(
|
|||
|
||||
// Clone the body before the upstream read so we can extract
|
||||
// credentialID for rate-limit bookkeeping without double-
|
||||
// consuming the stream. The client sends
|
||||
// `{ challengeId, credential: { id: '<base64url>' } }`.
|
||||
// consuming the stream. The client sends Better-Auth's shape
|
||||
// `{ response: { id: '<base64url>', ... } }` — see
|
||||
// `verifyPasskeyAuthenticationBodySchema` in the upstream
|
||||
// @better-auth/passkey plugin. Falls back to a flat `{ id }`
|
||||
// body for any direct-to-mana-auth caller (legacy harness).
|
||||
let credentialId: string | null = null;
|
||||
let bodyText: string | null = null;
|
||||
try {
|
||||
bodyText = await c.req.text();
|
||||
const parsed = JSON.parse(bodyText);
|
||||
credentialId = parsed?.credential?.id ?? parsed?.id ?? null;
|
||||
credentialId = parsed?.response?.id ?? parsed?.id ?? null;
|
||||
} catch {
|
||||
// Body malformed — let the upstream handler return a real
|
||||
// validation error. No rate-limit bump because we don't
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue