44 lines
1.2 KiB
TypeScript
44 lines
1.2 KiB
TypeScript
export const CROSS_TAB_CHANNEL_NAME = 'hipctf.auth.v1';
|
|
export const CROSS_TAB_STORAGE_KEY = 'hipctf.auth.invalidate.v1';
|
|
export const CROSS_TAB_EVENT_TYPE = 'hipctf.session.invalidated';
|
|
|
|
export interface CrossTabInvalidationMessage {
|
|
type: 'session-invalidated';
|
|
origin: string;
|
|
ts: number;
|
|
}
|
|
|
|
export function encodeInvalidationMessage(origin: string): CrossTabInvalidationMessage {
|
|
return {
|
|
type: 'session-invalidated',
|
|
origin,
|
|
ts: Date.now(),
|
|
};
|
|
}
|
|
|
|
export function isCrossTabInvalidationMessage(
|
|
value: unknown,
|
|
): value is CrossTabInvalidationMessage {
|
|
if (!value || typeof value !== 'object') return false;
|
|
const v = value as Record<string, unknown>;
|
|
return (
|
|
v['type'] === 'session-invalidated' &&
|
|
typeof v['origin'] === 'string' &&
|
|
typeof v['ts'] === 'number'
|
|
);
|
|
}
|
|
|
|
export function isStorageInvalidationEvent(
|
|
event: { key?: string | null; newValue?: string | null } | null | undefined,
|
|
): boolean {
|
|
if (!event) return false;
|
|
if (event.key !== CROSS_TAB_STORAGE_KEY) return false;
|
|
if (event.newValue == null) return false;
|
|
try {
|
|
const parsed = JSON.parse(event.newValue) as unknown;
|
|
return isCrossTabInvalidationMessage(parsed);
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|