66 lines
1.9 KiB
TypeScript
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();
|
|
}
|