Files
classroomio/packages/db/src/utils/custom-domain/trusted-origin.ts
T

95 lines
2.4 KiB
TypeScript

import { getVerifiedCustomDomainHostnames } from '../../queries/organization/organization';
const CLASSROOMIO_ROOT = 'classroomio.com';
/** Lowercase hostnames with verified custom domains ( warmed at API boot + updated on domain routes ). */
const verifiedCustomDomainHostnames = new Set<string>();
function originMatchesStaticEntry(origin: string, entry: string): boolean {
const trimmedEntry = entry.trim();
if (!trimmedEntry.includes('*')) {
return origin === trimmedEntry;
}
const regex = new RegExp(
`^${trimmedEntry
.split('*')
.map((part) => part.replace(/[.+?^${}()|[\]\\]/g, '\\$&'))
.join('.*')}$`
);
return regex.test(origin);
}
function isClassroomioHost(hostname: string): boolean {
const host = hostname.toLowerCase();
return host === CLASSROOMIO_ROOT || host.endsWith(`.${CLASSROOMIO_ROOT}`);
}
export function trustCustomDomainHostname(hostname: string): void {
const normalized = hostname.trim().toLowerCase();
if (normalized) {
verifiedCustomDomainHostnames.add(normalized);
}
}
export function untrustCustomDomainHostname(hostname: string): void {
verifiedCustomDomainHostnames.delete(hostname.trim().toLowerCase());
}
export async function preloadVerifiedCustomDomainOrigins(): Promise<void> {
const hostnames = await getVerifiedCustomDomainHostnames();
verifiedCustomDomainHostnames.clear();
for (const hostname of hostnames) {
verifiedCustomDomainHostnames.add(hostname);
}
}
/**
* Resolves whether a browser `Origin` header value is allowed for CORS / Better Auth.
* `staticTrustedOriginEntries` may include exact origins or `*` patterns (e.g. https://*.classroomio.com).
*/
export function resolveTrustedBrowserOrigin(
origin: string | undefined | null,
staticTrustedOriginEntries: readonly string[]
): string | undefined {
if (!origin || origin === 'null') {
return undefined;
}
let parsed: URL;
try {
parsed = new URL(origin);
} catch {
return undefined;
}
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
return undefined;
}
for (const entry of staticTrustedOriginEntries) {
if (originMatchesStaticEntry(origin, entry)) {
return origin;
}
}
const hostname = parsed.hostname;
if (isClassroomioHost(hostname)) {
return origin;
}
if (verifiedCustomDomainHostnames.has(hostname.toLowerCase())) {
return origin;
}
return undefined;
}