Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/auth/security.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,10 @@ export async function authenticateSessionToken(env: Env, token: string | undefin
if (!token) return null;
const session = await getAuthSessionByTokenHash(env, await hashToken(token));
if (!session) return null;
if (session.revokedAt || Date.parse(session.expiresAt) <= Date.now()) return null;
// Fail closed on an unparseable expiry: Date.parse → NaN makes `NaN <= Date.now()` false, which would
// otherwise authenticate a session whose stored expires_at is malformed/empty as if it never expired.
const expiresAtMs = Date.parse(session.expiresAt);
if (session.revokedAt || !Number.isFinite(expiresAtMs) || expiresAtMs <= Date.now()) return null;
await touchAuthSession(env, session.id);
return { kind: "session", actor: session.login, session };
}
Expand Down
5 changes: 5 additions & 0 deletions test/unit/auth.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ describe("private-beta auth and rate limiting", () => {
const expired = await createSessionForGitHubUser(env, { login: "expired-user" });
await env.DB.prepare("update auth_sessions set expires_at = ? where login = ?").bind("2020-01-01T00:00:00.000Z", "expired-user").run();
await expect(authenticatePrivateToken(env, expired.token)).resolves.toBeNull();

// Fail closed when the stored expiry is unparseable (NaN), not authenticate it as a never-expiring session.
const malformed = await createSessionForGitHubUser(env, { login: "malformed-expiry-user" });
await env.DB.prepare("update auth_sessions set expires_at = ? where login = ?").bind("not-a-date", "malformed-expiry-user").run();
await expect(authenticatePrivateToken(env, malformed.token)).resolves.toBeNull();
});

it("handles auth helper fallbacks for cookies, login lists, and token comparison", async () => {
Expand Down
Loading