72 lines
3.1 KiB
TypeScript
72 lines
3.1 KiB
TypeScript
import { activityRedirectHref } from './activity-redirect.js';
|
|
|
|
const origin = 'https://electric-cherry.invalid';
|
|
const pagePath =
|
|
/^\/(?:$|activity|operations|autoscaling|account|bank|afk|capacity|metrics|server-keys|settings(?:\/users)?|servers\/[^/]+|hosts(?:\/[^/]+)?|collections(?:\/launches\/[^/]+)?|(?:scripts|configs|plugins|betas|campaigns|maintenance|provisioning|matches)(?:\/[^/]+)?|game-files|leaderboard(?:\/players\/[^/]+(?:\/[^/]+)?)?)$/;
|
|
|
|
/** Only return to application pages, never an external URL or a mutation/API endpoint. */
|
|
export function safeReturnHref(value: string | null | undefined, fallback: string): string {
|
|
if (
|
|
!value ||
|
|
value.length > 12000 ||
|
|
!value.startsWith('/') ||
|
|
value.startsWith('//') ||
|
|
// eslint-disable-next-line no-control-regex -- Reject control characters in redirect paths.
|
|
/[\\\x00-\x1f\x7f]/.test(value)
|
|
)
|
|
return fallback;
|
|
try {
|
|
const url = new URL(value, origin);
|
|
if (url.origin !== origin || !pagePath.test(url.pathname)) return fallback;
|
|
if (url.pathname === '/activity' || url.pathname === '/operations')
|
|
return activityRedirectHref(url);
|
|
return url.pathname + url.search + url.hash;
|
|
} catch {
|
|
return fallback;
|
|
}
|
|
}
|
|
|
|
export function contextHref(destination: string, source: URL | string): string {
|
|
const current = source instanceof URL ? source.pathname + source.search + source.hash : source;
|
|
const url = new URL(destination, origin);
|
|
const returnTo = safeReturnHref(current, '/');
|
|
url.searchParams.set('returnTo', returnTo);
|
|
return url.pathname + url.search + url.hash;
|
|
}
|
|
|
|
export function returnLabel(href: string): string {
|
|
const url = new URL(href, origin);
|
|
const path = url.pathname;
|
|
if (path.startsWith('/servers/')) return 'Back to server';
|
|
if (path.startsWith('/leaderboard/players/')) return 'Back to player';
|
|
if (path.startsWith('/collections/launches/')) return 'Back to collection launch';
|
|
if (path === '/collections' && url.searchParams.get('view') === 'active')
|
|
return 'Back to active launches';
|
|
if (path === '/collections' && url.searchParams.get('view') === 'history')
|
|
return 'Back to launch history';
|
|
if (path.startsWith('/matches/')) return 'Back to match';
|
|
if (path === '/hosts/operations') return 'Back to host operation history';
|
|
if (path.startsWith('/hosts/')) return 'Back to host';
|
|
const names: Record<string, string> = {
|
|
'': 'Servers',
|
|
autoscaling: 'Autoscaling',
|
|
collections: 'Collections',
|
|
hosts: 'Hosts',
|
|
capacity: 'Capacity',
|
|
scripts: 'Scripts',
|
|
configs: 'Configs',
|
|
plugins: 'Plugins',
|
|
'game-files': 'Game Files',
|
|
betas: 'Betas',
|
|
campaigns: 'Campaigns',
|
|
maintenance: 'Maintenance',
|
|
provisioning: 'Server queues',
|
|
leaderboard: 'Leaderboard',
|
|
bank: 'Bank',
|
|
afk: 'AFK',
|
|
matches: 'Match History',
|
|
metrics: 'Metrics'
|
|
};
|
|
return `Back to ${names[path.split('/')[1]] ?? 'previous page'}`;
|
|
}
|