import type { Cookies } from "@sveltejs/kit";
import { CURRENT_DID_KEY } from "#lib/auth/accounts.ts";
import { open } from "#lib/server/sealed.ts";
import { githubEnv } from "#lib/server/github/env.ts";
import { GITHUB_TOKEN_COOKIE } from "#lib/server/github/cookies.ts";
interface GitHubSession {
token: string;
did: string;
exp: number;
}
// session is bound to opening account to prevent cross-account token reuse
export const sessionActor = async (
cookies: Cookies,
platform?: App.Platform
): Promise<{ token: string; did: string } | null> => {
const session = await open<GitHubSession>(
cookies.get(GITHUB_TOKEN_COOKIE),
githubEnv(platform).secret
);
const did = cookies.get(CURRENT_DID_KEY);
if (!session?.token || !did || !session.did || session.exp <= Date.now() || session.did !== did)
return null;
return { token: session.token, did: session.did };
};
export const sessionToken = async (
cookies: Cookies,
platform?: App.Platform
): Promise<string | null> => (await sessionActor(cookies, platform))?.token ?? null;
const jwtPayload = (jwt: string): Record<string, unknown> | null => {
const parts = jwt.split(".");
if (parts.length !== 3) return null;
try {
const json = atob(parts[1].replaceAll("-", "+").replaceAll("_", "/"));
const value: unknown = JSON.parse(json);
return value !== null && typeof value === "object" && !Array.isArray(value)
? (value as Record<string, unknown>)
: null;
} catch {
return null;
}
};
// unverified claim; downstream migrator verifies jwt signature
export const claimedServiceAuthDid = (authorization: string | null): string | null => {
if (!authorization?.startsWith("Bearer ")) return null;
const iss = jwtPayload(authorization.slice("Bearer ".length))?.iss;
return typeof iss === "string" && iss ? iss : null;
};