feat: harden sessions and track downstream acknowledgements
This commit is contained in:
+45
-2
@@ -12,10 +12,13 @@ export type SessionUser = {
|
||||
};
|
||||
|
||||
export type LoginSession = {
|
||||
accessToken: string;
|
||||
tokenType: string;
|
||||
portal: Portal;
|
||||
user: SessionUser;
|
||||
idleTimeoutSeconds: number;
|
||||
lockRecoverySeconds: number;
|
||||
absoluteExpiresAt: string;
|
||||
lastActivityAt: string;
|
||||
recentAuthenticationExpiresAt: string;
|
||||
};
|
||||
|
||||
const sessionKey = 'cmpp-auth-session';
|
||||
@@ -37,6 +40,46 @@ export function clearSession() {
|
||||
window.localStorage.removeItem(sessionKey);
|
||||
}
|
||||
|
||||
export function updateSessionTiming(timing: Partial<Omit<LoginSession, 'portal' | 'user'>>) {
|
||||
const current = readSession();
|
||||
if (current) writeSession({ ...current, ...timing });
|
||||
}
|
||||
|
||||
let lastUserActivityAt = Date.now();
|
||||
let reauthenticationHandler: (() => Promise<void>) | undefined;
|
||||
|
||||
export function markUserActivity() {
|
||||
lastUserActivityAt = Date.now();
|
||||
}
|
||||
|
||||
export function getLastUserActivityAt() {
|
||||
return lastUserActivityAt;
|
||||
}
|
||||
|
||||
export function hasRecentUserActivity() {
|
||||
return Date.now() - lastUserActivityAt < 60_000;
|
||||
}
|
||||
|
||||
export function setReauthenticationHandler(handler?: () => Promise<void>) {
|
||||
reauthenticationHandler = handler;
|
||||
}
|
||||
|
||||
export function requestReauthentication() {
|
||||
if (!reauthenticationHandler) return Promise.reject(new Error('请重新验证当前密码后再操作'));
|
||||
return reauthenticationHandler();
|
||||
}
|
||||
|
||||
export function dispatchSessionEvent(type: 'locked' | 'unlocked' | 'logout', detail?: Record<string, unknown>) {
|
||||
window.dispatchEvent(new CustomEvent(`cmpp-session-${type}`, { detail }));
|
||||
try {
|
||||
const channel = new BroadcastChannel('cmpp-session');
|
||||
channel.postMessage({ type, detail });
|
||||
channel.close();
|
||||
} catch {
|
||||
// BroadcastChannel is an enhancement; the current tab still receives the DOM event.
|
||||
}
|
||||
}
|
||||
|
||||
export function getSessionTenantId() {
|
||||
return readSession()?.user.tenantId ?? undefined;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user