A CLI for publishing standard.site documents to ATProto
at main 74 lines 2.0 kB view raw
1import { JoseKey } from "@atproto/jwk-jose"; 2import type { 3 Key, 4 InternalStateData, 5 SessionStore, 6 StateStore, 7} from "@atproto/oauth-client"; 8import type { Database } from "bun:sqlite"; 9import { kvGet, kvSet, kvDel } from "./db"; 10 11type SerializedStateData = Omit<InternalStateData, "dpopKey"> & { 12 dpopJwk: Record<string, unknown>; 13}; 14 15type SerializedSession = Omit<Parameters<SessionStore["set"]>[1], "dpopKey"> & { 16 dpopJwk: Record<string, unknown>; 17}; 18 19function serializeKey(key: Key): Record<string, unknown> { 20 const jwk = key.privateJwk; 21 if (!jwk) throw new Error("Private DPoP JWK is missing"); 22 return jwk as Record<string, unknown>; 23} 24 25async function deserializeKey(jwk: Record<string, unknown>): Promise<Key> { 26 return JoseKey.fromJWK(jwk) as unknown as Key; 27} 28 29export function createStateStore(db: Database, ttl = 600): StateStore { 30 return { 31 async set(key, { dpopKey, ...rest }) { 32 const data: SerializedStateData = { 33 ...rest, 34 dpopJwk: serializeKey(dpopKey), 35 }; 36 kvSet(db, `oauth_state:${key}`, JSON.stringify(data), ttl); 37 }, 38 async get(key) { 39 const raw = kvGet(db, `oauth_state:${key}`); 40 if (!raw) return undefined; 41 const { dpopJwk, ...rest }: SerializedStateData = JSON.parse(raw); 42 const dpopKey = await deserializeKey(dpopJwk); 43 return { ...rest, dpopKey }; 44 }, 45 async del(key) { 46 kvDel(db, `oauth_state:${key}`); 47 }, 48 }; 49} 50 51export function createSessionStore( 52 db: Database, 53 ttl = 60 * 60 * 24 * 14, 54): SessionStore { 55 return { 56 async set(sub, { dpopKey, ...rest }) { 57 const data: SerializedSession = { 58 ...rest, 59 dpopJwk: serializeKey(dpopKey), 60 }; 61 kvSet(db, `oauth_session:${sub}`, JSON.stringify(data), ttl); 62 }, 63 async get(sub) { 64 const raw = kvGet(db, `oauth_session:${sub}`); 65 if (!raw) return undefined; 66 const { dpopJwk, ...rest }: SerializedSession = JSON.parse(raw); 67 const dpopKey = await deserializeKey(dpopJwk); 68 return { ...rest, dpopKey }; 69 }, 70 async del(sub) { 71 kvDel(db, `oauth_session:${sub}`); 72 }, 73 }; 74}