import type { H3Event } from 'h3' import { sessionConfig } from './server-session' /** * Short-lived sealed cookie proving the current browser completed GitHub * user-OAuth and was confirmed as an administrator of a specific installation. * * The atproto callback checks this before binding a DID to an installation, so * a connecting user can't claim an installation they don't actually control by * crafting `/connect?installation_id=`. Reuses the session password * for sealing; a distinct cookie name and a 15-minute TTL keep it scoped to a * single connect flow. */ interface InstallOwnershipData { installationId: number verifiedAt: number } const COOKIE_NAME = 'synchub-install-ownership' const TTL_SECONDS = 15 * 60 function ownershipConfig() { return { ...sessionConfig(), name: COOKIE_NAME, maxAge: TTL_SECONDS } } export async function markInstallOwned(event: H3Event, installationId: number): Promise { const session = await useSession(event, ownershipConfig()) await session.update({ installationId, verifiedAt: Date.now() }) } /** * Return true if the current browser proved ownership of `installationId` * within the TTL. Does not clear the cookie; the caller clears it after a * successful bind so it can't be replayed. */ export async function hasVerifiedInstall(event: H3Event, installationId: number): Promise { const session = await useSession(event, ownershipConfig()) const { installationId: owned, verifiedAt } = session.data if (typeof owned !== 'number' || typeof verifiedAt !== 'number') return false if (owned !== installationId) return false if (Date.now() - verifiedAt > TTL_SECONDS * 1000) return false return true } export async function clearInstallOwnership(event: H3Event): Promise { const session = await useSession(event, ownershipConfig()) await session.clear() }