Files
ThothII/frontend/src/auth/authOperation.ts
T

66 lines
1.9 KiB
TypeScript

import { getAuthGeneration, getAuthState } from "./authState";
export type AuthOperationGuard = Readonly<{
authGeneration: number;
issuer: string;
subject: string;
sessionId: string | null;
disposalEpoch: number;
}>;
export type AuthOperationPrecondition = Readonly<{
operation: AuthOperationGuard;
isCurrent: () => boolean;
}>;
export class StaleAuthOperationError extends Error {
constructor() {
super("The authenticated operation is no longer current");
this.name = "StaleAuthOperationError";
}
}
export function captureAuthOperation(options: {
sessionId?: string | null;
disposalEpoch?: number;
} = {}): AuthOperationGuard | null {
const user = getAuthState();
if (!user) return null;
return {
authGeneration: getAuthGeneration(),
issuer: user.issuer,
subject: user.subject,
sessionId: options.sessionId ?? null,
disposalEpoch: options.disposalEpoch ?? 0,
};
}
export function isAuthOperationCurrent(
operation: AuthOperationGuard | null,
options: { sessionId?: string | null; disposalEpoch: number },
): boolean {
if (!operation) return false;
const user = getAuthState();
return Boolean(
user
&& getAuthGeneration() === operation.authGeneration
&& user.issuer === operation.issuer
&& user.subject === operation.subject
&& operation.sessionId === (options.sessionId ?? null)
&& operation.disposalEpoch === options.disposalEpoch,
);
}
export function requireCurrentAuthOperation(
operation: AuthOperationGuard | null,
options: { sessionId?: string | null; disposalEpoch: number },
): asserts operation is AuthOperationGuard {
if (!isAuthOperationCurrent(operation, options)) throw new StaleAuthOperationError();
}
export function requireAuthOperationPrecondition(
precondition: AuthOperationPrecondition | undefined,
): void {
if (precondition && !precondition.isCurrent()) throw new StaleAuthOperationError();
}