~james/core

ref: 452f17b75181d62d1d92016edecd38e1d70fecab core/web/src/lib/server/github/session.ts -rw-r--r-- 1.8 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 16 hours ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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;
};