Introduce origin migration handling with outdated route guards, redirect logic, and migration-related error views.
- Add `originMigration.js` for handling allowed origins, standalone contexts, and redirect routes. - Create `OutdatedGateway.vue` and `OutdatedInstallation.vue` error views with timer-based redirection and user instructions. - Update router to include `/outdated-installation` and `/outdated-gateway` paths. - Implement unit tests for migration utility methods and route guards. - Remove debug `console.log` statements across multiple components.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
export const OUTDATED_INSTALLATION_ROUTE_NAME = 'outdated-installation';
|
||||
export const OUTDATED_GATEWAY_ROUTE_NAME = 'outdated-gateway';
|
||||
|
||||
const EXEMPT_ROUTE_NAMES = new Set([
|
||||
OUTDATED_INSTALLATION_ROUTE_NAME,
|
||||
OUTDATED_GATEWAY_ROUTE_NAME,
|
||||
]);
|
||||
|
||||
const normalizeAllowedOrigins = (allowedOrigins = []) => {
|
||||
return new Set(
|
||||
allowedOrigins
|
||||
.map((origin) => {
|
||||
try {
|
||||
return new URL(origin).origin;
|
||||
} catch (_error) {
|
||||
return origin;
|
||||
}
|
||||
})
|
||||
.filter(Boolean),
|
||||
);
|
||||
};
|
||||
|
||||
export const isOriginAllowed = (currentOrigin, allowedOrigins = []) => {
|
||||
if (!currentOrigin) return true;
|
||||
const allowedOriginSet = normalizeAllowedOrigins(allowedOrigins);
|
||||
return allowedOriginSet.has(currentOrigin);
|
||||
};
|
||||
|
||||
export const isStandaloneContext = (win) => {
|
||||
const resolvedWindow = win || (typeof window !== 'undefined' ? window : undefined);
|
||||
if (!resolvedWindow) return false;
|
||||
const iosStandalone = resolvedWindow.navigator?.standalone === true;
|
||||
const mediaStandalone = typeof resolvedWindow.matchMedia === 'function'
|
||||
&& resolvedWindow.matchMedia('(display-mode: standalone)').matches;
|
||||
return iosStandalone || mediaStandalone;
|
||||
};
|
||||
|
||||
export const shouldBypassOriginGate = (route) => {
|
||||
return EXEMPT_ROUTE_NAMES.has(route?.name);
|
||||
};
|
||||
|
||||
export const resolveOriginMigrationRoute = ({
|
||||
to,
|
||||
currentOrigin,
|
||||
allowedOrigins,
|
||||
standalone,
|
||||
}) => {
|
||||
if (shouldBypassOriginGate(to)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isOriginAllowed(currentOrigin, allowedOrigins)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (standalone) {
|
||||
return { name: OUTDATED_INSTALLATION_ROUTE_NAME };
|
||||
}
|
||||
|
||||
return {
|
||||
name: OUTDATED_GATEWAY_ROUTE_NAME,
|
||||
query: {
|
||||
redirect: to?.fullPath || '/',
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export const sanitizeRedirectPath = (redirectPath) => {
|
||||
if (typeof redirectPath !== 'string') return '/';
|
||||
if (!redirectPath.startsWith('/')) return '/';
|
||||
return redirectPath;
|
||||
};
|
||||
|
||||
export const buildMigrationUrl = (migrationOrigin, redirectPath) => {
|
||||
const safePath = sanitizeRedirectPath(redirectPath);
|
||||
try {
|
||||
return new URL(safePath, migrationOrigin).toString();
|
||||
} catch (_error) {
|
||||
return migrationOrigin;
|
||||
}
|
||||
};
|
||||
|
||||
export const startRedirectCountdown = ({
|
||||
seconds = 5,
|
||||
onTick,
|
||||
onRedirect,
|
||||
setIntervalFn = setInterval,
|
||||
clearIntervalFn = clearInterval,
|
||||
setTimeoutFn = setTimeout,
|
||||
clearTimeoutFn = clearTimeout,
|
||||
}) => {
|
||||
let remainingSeconds = seconds;
|
||||
const intervalId = setIntervalFn(() => {
|
||||
remainingSeconds = Math.max(remainingSeconds - 1, 0);
|
||||
if (typeof onTick === 'function') {
|
||||
onTick(remainingSeconds);
|
||||
}
|
||||
if (remainingSeconds === 0) {
|
||||
clearIntervalFn(intervalId);
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
const timeoutId = setTimeoutFn(() => {
|
||||
if (typeof onRedirect === 'function') {
|
||||
onRedirect();
|
||||
}
|
||||
}, seconds * 1000);
|
||||
|
||||
return () => {
|
||||
clearIntervalFn(intervalId);
|
||||
clearTimeoutFn(timeoutId);
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user