diff --git a/src/__tests__/helpers/session-secret.ts b/src/__tests__/helpers/session-secret.ts new file mode 100644 index 000000000..d1db58feb --- /dev/null +++ b/src/__tests__/helpers/session-secret.ts @@ -0,0 +1,11 @@ +/** + * A session cookie secret of the exact shape `createSession` mints (`hls_` + * and 32 random bytes in hex). The session lookup refuses any other shape + * before it asks the database, so a fixture that invents a readable secret + * tests the refusal, not the lookup. + */ +import { randomBytes } from "node:crypto"; + +export function fixtureSessionSecret(): string { + return `hls_${randomBytes(32).toString("hex")}`; +} diff --git a/src/app/api/auth/native/complete/__tests__/route.test.ts b/src/app/api/auth/native/complete/__tests__/route.test.ts index 540b12105..e82eeed96 100644 --- a/src/app/api/auth/native/complete/__tests__/route.test.ts +++ b/src/app/api/auth/native/complete/__tests__/route.test.ts @@ -45,6 +45,7 @@ import { GET } from "../route"; import { checkAuthSurfaceRateLimit } from "@/lib/rate-limit"; import { mintNativeHandoff } from "@/lib/auth/native-handoff"; import { prisma } from "@/lib/db"; +import { fixtureSessionSecret } from "@/__tests__/helpers/session-secret"; import { NATIVE_HANDOFF_STATE_COOKIE, encodeNativeHandoffState, @@ -71,7 +72,7 @@ function makeRequest(opts: { ); } if (opts.withSession !== false) { - r.cookies.set("healthlog_session", "hls_sessionsecret"); + r.cookies.set("healthlog_session", fixtureSessionSecret()); } return r; } diff --git a/src/app/api/auth/oidc/callback/__tests__/route.test.ts b/src/app/api/auth/oidc/callback/__tests__/route.test.ts index 370884fba..a01fa9212 100644 --- a/src/app/api/auth/oidc/callback/__tests__/route.test.ts +++ b/src/app/api/auth/oidc/callback/__tests__/route.test.ts @@ -101,6 +101,7 @@ import { verifyIdToken, } from "@/lib/auth/oidc"; import { mintNativeHandoff } from "@/lib/auth/oidc-native-handoff"; +import { fixtureSessionSecret } from "@/__tests__/helpers/session-secret"; const CONFIG = { issuerUrl: "https://idp.example.com", @@ -616,7 +617,8 @@ describe("GET /api/auth/oidc/callback — duplicate-callback idempotency", () => const req = new NextRequest( "http://localhost/api/auth/oidc/callback?code=abc&state=STATE", ); - if (withSession) req.cookies.set("healthlog_session", "hls_valid_secret"); + if (withSession) + req.cookies.set("healthlog_session", fixtureSessionSecret()); return req; } diff --git a/tests/integration/session-time-zone.test.ts b/tests/integration/session-time-zone.test.ts index 3743de7e8..4a58deab4 100644 --- a/tests/integration/session-time-zone.test.ts +++ b/tests/integration/session-time-zone.test.ts @@ -23,6 +23,7 @@ import { } from "vitest"; import { PrismaClient } from "@/generated/prisma/client"; +import { fixtureSessionSecret } from "@/__tests__/helpers/session-secret"; import { getPrismaClient, truncateAllTables } from "./setup"; const ZONE = "Europe/Berlin"; @@ -167,17 +168,19 @@ describe("on a database whose default zone is Europe/Berlin", () => { const { validateSessionFromCookieValue } = await import("@/lib/auth/session"); const { hashToken } = await import("@/lib/auth/hmac"); + const liveSecret = fixtureSessionSecret(); + const expiredSecret = fixtureSessionSecret(); const live = await getPrismaClient().session.create({ data: { userId: USER_ID, - tokenHash: hashToken("hls_live-secret"), + tokenHash: hashToken(liveSecret), expiresAt: new Date(Date.now() + 60 * 60_000), }, }); await getPrismaClient().session.create({ data: { userId: USER_ID, - tokenHash: hashToken("hls_expired-secret"), + tokenHash: hashToken(expiredSecret), expiresAt: new Date(Date.now() - 60_000), }, }); @@ -185,10 +188,10 @@ describe("on a database whose default zone is Europe/Berlin", () => { 60_000, ); await expect( - validateSessionFromCookieValue("hls_live-secret"), + validateSessionFromCookieValue(liveSecret), ).resolves.not.toBeNull(); await expect( - validateSessionFromCookieValue("hls_expired-secret"), + validateSessionFromCookieValue(expiredSecret), ).resolves.toBeNull(); });