60 lines
2.3 KiB
TypeScript
60 lines
2.3 KiB
TypeScript
|
|
/**
|
|
* Normalize a user-supplied custom app URL. Accepts a bare host ("jellyfin.lan",
|
|
* "10.0.0.5:8096") or a full URL; when no scheme is present, http:// is prepended
|
|
* (LAN resources are usually plain HTTP). Returns the normalized href, or null when
|
|
* the input is empty (clears the override) or not a valid http(s) URL. Restricting to
|
|
* http/https is the XSS guard — javascript:/data: URLs never make it into an href.
|
|
*/
|
|
export function normalizeCustomUrl(input: string | null | undefined): string | null {
|
|
const trimmed = (input ?? '').trim();
|
|
if (!trimmed) return null;
|
|
const withScheme = /^https?:\/\//i.test(trimmed) ? trimmed : `http://${trimmed}`;
|
|
try {
|
|
const url = new URL(withScheme);
|
|
if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;
|
|
return url.href;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function getServiceLink(ui_location: string, customUrl?: string | null): string {
|
|
// A user-set custom URL (reverse proxy / local DNS) overrides the computed default. Only
|
|
// accepted when it normalizes to a valid http(s) URL — otherwise fall through to the default.
|
|
const normalizedCustom = normalizeCustomUrl(customUrl);
|
|
if (normalizedCustom) {
|
|
return normalizedCustom;
|
|
}
|
|
|
|
// "https:8480" / "http:8480" — an explicit scheme + port served on the current host. Checked
|
|
// before the URL parse below because new URL("https:8480") would mis-parse 8480 as the host.
|
|
const schemePort = ui_location.match(/^(https?):(\d+)$/);
|
|
if (schemePort) {
|
|
return `${schemePort[1]}://${window.location.hostname}:${schemePort[2]}`;
|
|
}
|
|
|
|
// Check if the ui location is a valid URL
|
|
try {
|
|
const url = new URL(ui_location);
|
|
// If it is a valid URL, return it as is
|
|
return url.href;
|
|
} catch (e) {
|
|
// If it fails, it means it's not a valid URL
|
|
}
|
|
|
|
// Check if the ui location is a port number
|
|
const parsedPort = parseInt(ui_location, 10);
|
|
if (!isNaN(parsedPort)) {
|
|
// If it's a port number, return a link to the service on that port
|
|
return `http://${window.location.hostname}:${parsedPort}`;
|
|
}
|
|
|
|
const pathPattern = /^\/.+/;
|
|
if (pathPattern.test(ui_location)) {
|
|
// If it starts with a slash, treat it as a full path
|
|
return ui_location;
|
|
}
|
|
|
|
return `/${ui_location}`;
|
|
} |