forked from baron/baron-sso
115 lines
2.8 KiB
TypeScript
115 lines
2.8 KiB
TypeScript
export const DEFAULT_SESSION_RENEW_THRESHOLD_MS = 10 * 60 * 1000;
|
|
export const DEFAULT_SESSION_RENEW_THROTTLE_MS = 30 * 1000;
|
|
export const SESSION_EXPIRY_STORAGE_KEY = "baron_session_expiry_enabled";
|
|
|
|
type SessionExpiryReadableStorage = Pick<Storage, "getItem">;
|
|
type SessionExpiryWritableStorage = Pick<Storage, "setItem">;
|
|
|
|
export type SessionRenewDecisionParams = {
|
|
expiresAtSec?: number | null;
|
|
nowMs: number;
|
|
isEnabled: boolean;
|
|
isAuthenticated: boolean;
|
|
isLoading: boolean;
|
|
isRenewInFlight: boolean;
|
|
lastAttemptAtMs: number;
|
|
thresholdMs?: number;
|
|
throttleMs?: number;
|
|
};
|
|
|
|
export type SessionExpiryPreferenceParams = {
|
|
defaultEnabled?: boolean;
|
|
storage?: SessionExpiryReadableStorage | null;
|
|
};
|
|
|
|
export type DevelopmentSessionRedirectParams = {
|
|
appMode: string;
|
|
defaultEnabled?: boolean;
|
|
storage?: SessionExpiryReadableStorage | null;
|
|
};
|
|
|
|
function browserStorage() {
|
|
if (typeof window === "undefined") {
|
|
return null;
|
|
}
|
|
|
|
return window.localStorage;
|
|
}
|
|
|
|
export function readSessionExpiryEnabled({
|
|
defaultEnabled = true,
|
|
storage = browserStorage(),
|
|
}: SessionExpiryPreferenceParams = {}) {
|
|
const stored = storage?.getItem(SESSION_EXPIRY_STORAGE_KEY) ?? null;
|
|
return stored === null ? defaultEnabled : stored !== "false";
|
|
}
|
|
|
|
export function writeSessionExpiryEnabled(
|
|
isEnabled: boolean,
|
|
storage: SessionExpiryWritableStorage | null = browserStorage(),
|
|
) {
|
|
storage?.setItem(SESSION_EXPIRY_STORAGE_KEY, String(isEnabled));
|
|
}
|
|
|
|
export function shouldSuppressDevelopmentSessionRedirect({
|
|
appMode,
|
|
defaultEnabled = appMode !== "development",
|
|
storage = browserStorage(),
|
|
}: DevelopmentSessionRedirectParams) {
|
|
return (
|
|
appMode === "development" &&
|
|
!readSessionExpiryEnabled({ defaultEnabled, storage })
|
|
);
|
|
}
|
|
|
|
function hasRenewPreconditions({
|
|
isAuthenticated,
|
|
isLoading,
|
|
isRenewInFlight,
|
|
}: SessionRenewDecisionParams) {
|
|
return isAuthenticated && !isLoading && !isRenewInFlight;
|
|
}
|
|
|
|
function isRenewWindowOpen({
|
|
expiresAtSec,
|
|
nowMs,
|
|
lastAttemptAtMs,
|
|
thresholdMs = DEFAULT_SESSION_RENEW_THRESHOLD_MS,
|
|
throttleMs = DEFAULT_SESSION_RENEW_THROTTLE_MS,
|
|
}: SessionRenewDecisionParams) {
|
|
if (typeof expiresAtSec !== "number") {
|
|
return false;
|
|
}
|
|
|
|
const remainingMs = expiresAtSec * 1000 - nowMs;
|
|
if (remainingMs <= 0 || remainingMs > thresholdMs) {
|
|
return false;
|
|
}
|
|
|
|
if (nowMs - lastAttemptAtMs < throttleMs) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
export function shouldAttemptSlidingSessionRenew(
|
|
params: SessionRenewDecisionParams,
|
|
) {
|
|
if (!params.isEnabled || !hasRenewPreconditions(params)) {
|
|
return false;
|
|
}
|
|
|
|
return isRenewWindowOpen(params);
|
|
}
|
|
|
|
export function shouldAttemptUnlimitedSessionRenew(
|
|
params: SessionRenewDecisionParams,
|
|
) {
|
|
if (params.isEnabled || !hasRenewPreconditions(params)) {
|
|
return false;
|
|
}
|
|
|
|
return isRenewWindowOpen(params);
|
|
}
|