~james/core

core/web/src/lib/auth/orgSessions.ts -rw-r--r-- 1.9 KiB
452f17b7 — james chore(import): snapshot james.dad.town/core at f70c71c7696a 15 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
53
54
55
56
57
58
import type { Did } from "@atcute/lexicons/syntax";
import {
	OAuthUserAgent,
	deleteStoredSession,
	getSession,
	type Session
} from "@atcute/oauth-browser-client";
import {
	forgetOrgDid,
	loadOrgControllers,
	loadOrgDids,
	orgDidsControlledBy
} from "#lib/auth/accounts.ts";

// org sessions are minted from a controller's session and are useless to the
// user once that controller signs out, so they get revoked alongside it
export interface OrgSessionDependencies {
	loadOrgDids: () => Did[];
	loadOrgControllers: () => Record<string, Did>;
	getSession: (sub: Did, options?: { allowStale?: boolean }) => Promise<Session>;
	createAgent: (session: Session) => Pick<OAuthUserAgent, "signOut">;
	deleteStoredSession: (sub: Did) => void;
	forgetOrgDid: (did: Did) => void;
}

const defaultDependencies: OrgSessionDependencies = {
	loadOrgDids,
	loadOrgControllers,
	getSession,
	createAgent: (session) => new OAuthUserAgent(session),
	deleteStoredSession,
	forgetOrgDid
};

const revokeOne = async (orgDid: Did, deps: OrgSessionDependencies): Promise<void> => {
	try {
		// allowStale skips a refresh, the token is about to be revoked anyway
		const session = await deps.getSession(orgDid, { allowStale: true });
		await deps.createAgent(session).signOut();
	} catch {
		// nothing to revoke, or the pds refused, either way drop the local copy
		deps.deleteStoredSession(orgDid);
	}
	deps.forgetOrgDid(orgDid);
};

const revoke = async (orgDids: Did[], deps: OrgSessionDependencies): Promise<void> => {
	await Promise.allSettled(orgDids.map((orgDid) => revokeOne(orgDid, deps)));
};

export const revokeOrgSessionsFor = (
	controllerDid: Did,
	deps: OrgSessionDependencies = defaultDependencies
): Promise<void> => revoke(orgDidsControlledBy(deps.loadOrgControllers(), controllerDid), deps);

export const revokeAllOrgSessions = (
	deps: OrgSessionDependencies = defaultDependencies
): Promise<void> => revoke(deps.loadOrgDids(), deps);