41 lines
1.3 KiB
TypeScript
41 lines
1.3 KiB
TypeScript
export interface AuthCheckProfile {
|
|
loggedInSelector: string | null;
|
|
loginUrlPatterns: string[];
|
|
}
|
|
|
|
export interface AuthCheckInput {
|
|
profile: AuthCheckProfile;
|
|
finalUrl: string;
|
|
statusCode: number;
|
|
loggedInSelectorPresent: boolean;
|
|
}
|
|
|
|
export type AuthExpiry = { expired: false } | { expired: true; reason: string };
|
|
|
|
function urlMatches(url: string, glob: string): boolean {
|
|
// Minimal glob: '**' = '.*', '*' = '[^/]*'
|
|
// Use a sentinel for '**' so the second '*' substitution doesn't clobber the '.*'.
|
|
const DOUBLE = '\x00DOUBLE\x00';
|
|
const escaped = glob
|
|
.replace(/\*\*/g, DOUBLE)
|
|
.replace(/[.+?^${}()|[\]\\]/g, '\\$&')
|
|
.replace(/\*/g, '[^/]*')
|
|
.split(DOUBLE).join('.*');
|
|
return new RegExp('^' + escaped + '$').test(url);
|
|
}
|
|
|
|
export function detectAuthExpiry(input: AuthCheckInput): AuthExpiry {
|
|
if (input.statusCode === 401 || input.statusCode === 403) {
|
|
return { expired: true, reason: `HTTP ${input.statusCode}` };
|
|
}
|
|
for (const pattern of input.profile.loginUrlPatterns) {
|
|
if (urlMatches(input.finalUrl, pattern)) {
|
|
return { expired: true, reason: 'redirected to login URL' };
|
|
}
|
|
}
|
|
if (input.profile.loggedInSelector && !input.loggedInSelectorPresent) {
|
|
return { expired: true, reason: 'logged-in selector not found' };
|
|
}
|
|
return { expired: false };
|
|
}
|