diff --git a/src/chat-app/app.ts b/src/chat-app/app.ts index 75db463..d4b2573 100644 --- a/src/chat-app/app.ts +++ b/src/chat-app/app.ts @@ -49,8 +49,7 @@ export async function createAppInstance() { }) // Chat has no public view — every non-login route requires auth. - // Chat is Nostr end-to-end — it cannot work without an identity. - installStrictAuthGuard(router, { requirePubkey: true }) + installStrictAuthGuard(router) const pinia = createPinia() diff --git a/src/lib/router-helpers.ts b/src/lib/router-helpers.ts index 1b7d92a..84bec63 100644 --- a/src/lib/router-helpers.ts +++ b/src/lib/router-helpers.ts @@ -14,12 +14,12 @@ import type { Router, RouteRecordRaw } from 'vue-router' * mismatch: guards register early but await this promise before reading * auth state. Phase 3 calls markAuthReady() once auth is initialized. */ -type AuthUserLike = { value: { id?: string; pubkey?: string } | null } +type AuthUserLike = { value: { pubkey?: string } | null } type AuthLike = { isAuthenticated: { value: boolean } // Populated after server-validated getCurrentUser() in auth.checkAuth(). - // Guards require BOTH isAuthenticated and a server-populated user — - // token presence alone is not enough (issue #36). + // Guards require BOTH isAuthenticated and a user with a pubkey — token + // presence alone is not enough (issue #36). currentUser: AuthUserLike } @@ -33,39 +33,20 @@ export function markAuthReady(auth: AuthLike): void { /** * Belt-and-suspenders auth check: token presence in localStorage isn't * sufficient — the server must have confirmed the token represents a real - * session, which is signalled by currentUser being populated. - * - * Keyed on `id`, never `pubkey`. Every account has an id; a Nostr pubkey - * is optional — Lightning-only accounts have none. Using pubkey as the - * "server answered" marker locked those accounts out of every - * strict-guard app: login succeeded, isAuthenticated flipped true, pubkey - * stayed empty, isFullyAuthed returned false, and the guard bounced them - * back to /login indefinitely. The #36 protection is unchanged — a bare - * token in localStorage still does not satisfy this. + * session, which is signalled by currentUser being populated with a pubkey. */ function isFullyAuthed(auth: AuthLike): boolean { - return auth.isAuthenticated.value && !!auth.currentUser?.value?.id + return auth.isAuthenticated.value && !!auth.currentUser?.value?.pubkey } /** * Strict guard — every non-/login route requires auth. - * Used by wallet, chat, accounting (no public view). - * - * `requirePubkey` additionally demands a Nostr identity. Only chat sets - * it: chat is Nostr end-to-end and cannot function without a key. Wallet - * and accounting are payment/ledger surfaces and must stay reachable - * without one — per ADR-0001, LNbits is a liquidity service, not an - * identity provider, so core payment flows cannot be gated on identity. + * Used by wallet, chat, libra (no public view). */ -export function installStrictAuthGuard( - router: Router, - opts: { requirePubkey?: boolean } = {}, -): void { +export function installStrictAuthGuard(router: Router): void { router.beforeEach(async (to) => { const auth = await authReady - const authed = - isFullyAuthed(auth) && - (!opts.requirePubkey || !!auth.currentUser?.value?.pubkey) + const authed = isFullyAuthed(auth) if (to.path === '/login') { return authed ? '/' : true }