Auth slice 3: dev-only fallback + playthrough owner checks

resolveUserId now returns null for an anonymous request in production (no
shared identity); the fixed dev user only applies locally. Player-scoped
routes (create/advance/goto, achievements, reach, notebook, phone, dial)
require a user and verify ownership via ownsPlaythrough — a player can no
longer read or act on another's playthrough. Verified: dev anon still plays;
cross-user access returns 403/404.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-22 22:39:52 +02:00
co-authored by Claude Opus 4.8
parent 93febcaef9
commit 5754fa1f55
3 changed files with 49 additions and 13 deletions
+5 -2
View File
@@ -34,9 +34,12 @@ export function hasAdminClaim(req: Request) {
* when the external handoff is wired — the `user_id` column stays the same.
*/
export const DEVELOPMENT_TEST_USER_ID = 'osint-test-player'
export function resolveUserId(req: Request): string {
export function resolveUserId(req: Request): string | null {
const sub = req.authClaims?.sub
return typeof sub === 'string' && sub.length > 0 ? sub : DEVELOPMENT_TEST_USER_ID
if (typeof sub === 'string' && sub.length > 0) return sub
// In production an absent token is anonymous (no shared identity); locally it
// resolves to a single dev user so the game is playable without an issuer.
return process.env.NODE_ENV === 'production' ? null : DEVELOPMENT_TEST_USER_ID
}
export function resolvePlayerName(req: Request): string {