/** * Checks the JSON bodies that the federation routes (`routes/federation.ts`, * `routes/oauth.ts`) receive before they read them. They check the shapes * only: whether an instance answers, or a code or an invite works, is the * services' check. * * @module */ import { type AuthorizeRequest, type FederationLoginRequest, type FederationSessionRequest, isPeerStatus, type SetPeerRequest, } from "../../shared/federation.ts"; /** Returns whether `obj` is an object whose `keys` are all strings. */ function hasStrings(obj: unknown, keys: string[]): boolean { return !!obj && typeof obj === "object" && keys.every((k) => typeof (obj as Record)[k] === "string"); } /** Checks whether `obj` is a {@link FederationLoginRequest}. */ export function isFederationLoginRequest( obj: unknown, ): obj is FederationLoginRequest { if (!hasStrings(obj, ["instance"])) return false; const invite = (obj as Record).inviteToken; return invite === undefined || typeof invite === "string"; } /** Checks whether `obj` is a {@link FederationSessionRequest}. */ export function isFederationSessionRequest( obj: unknown, ): obj is FederationSessionRequest { return hasStrings(obj, ["code", "state"]); } /** Checks whether `obj` is an {@link AuthorizeRequest}. */ export function isAuthorizeRequest(obj: unknown): obj is AuthorizeRequest { return hasStrings(obj, [ "clientId", "redirectUri", "state", "codeChallenge", "codeChallengeMethod", "nonce", ]); } /** Checks whether `obj` is a {@link SetPeerRequest}. */ export function isSetPeerRequest(obj: unknown): obj is SetPeerRequest { return hasStrings(obj, ["instance"]) && isPeerStatus((obj as Record).status); }