fix(self-host): tie the public address to a single origin (#2605)

This commit is contained in:
Hampus authored and GitHub committed 2026-09-08 22:17:39 +02:00
1 parent 6c36d934f7
commit 8cc485cf81
17 files changed
+903 -61

No files matched your search

+49 -4
View File
@@ -13,6 +13,14 @@ export interface DomainConfig {
gift_domain?: string;
}
type PublicOriginScheme = 'http' | 'https';
interface PublicOrigin {
public_scheme: PublicOriginScheme;
base_domain: string;
public_port: number;
}
export interface DerivedEndpoints {
api: string;
api_client: string;
@@ -36,8 +44,45 @@ function isStandardPort(scheme: string, port: number): boolean {
);
}
function stripTrailingDot(host: string): string {
return host.endsWith('.') ? host.slice(0, -1) : host;
export function canonicalizeDomain(value: string): string {
const trimmed = value.trim().toLowerCase();
return trimmed.endsWith('.') ? trimmed.slice(0, -1) : trimmed;
}
function defaultPortForScheme(scheme: PublicOriginScheme): number {
return scheme === 'https' ? 443 : 80;
}
export function parsePublicOrigin(origin: string): PublicOrigin | null {
const trimmed = origin.trim();
if (trimmed.length === 0) {
return null;
}
let parsed: URL;
try {
parsed = new URL(trimmed);
} catch {
return null;
}
const scheme = parsed.protocol.slice(0, -1);
if (scheme !== 'http' && scheme !== 'https') {
return null;
}
if (parsed.pathname !== '/' || parsed.search.length > 0 || parsed.hash.length > 0) {
return null;
}
if (parsed.username.length > 0 || parsed.password.length > 0) {
return null;
}
const base_domain = canonicalizeDomain(parsed.hostname);
if (base_domain.length === 0) {
return null;
}
return {
public_scheme: scheme,
base_domain,
public_port: parsed.port.length === 0 ? defaultPortForScheme(scheme) : Number.parseInt(parsed.port, 10),
};
}
export function buildUrl(scheme: string, domain: string, port?: number, path?: string): string {
@@ -47,7 +92,7 @@ export function buildUrl(scheme: string, domain: string, port?: number, path?: s
}
export function normalizePublicEndpoint(url: string, baseDomain: string, publicPort?: number): string {
const domain = stripTrailingDot(baseDomain.trim().toLowerCase());
const domain = canonicalizeDomain(baseDomain);
if (domain.length === 0 || !publicPort) {
return url;
}
@@ -57,7 +102,7 @@ export function normalizePublicEndpoint(url: string, baseDomain: string, publicP
} catch {
return url;
}
if (stripTrailingDot(parsed.hostname.toLowerCase()) !== domain) {
if (canonicalizeDomain(parsed.hostname) !== domain) {
return url;
}
if (isStandardPort(parsed.protocol.slice(0, -1), publicPort)) {