diff --git a/backend/src/routes/registries.ts b/backend/src/routes/registries.ts index 5e3efa50..178c0480 100644 --- a/backend/src/routes/registries.ts +++ b/backend/src/routes/registries.ts @@ -11,17 +11,14 @@ function isValidRegistryUrl(url: string, type: string): boolean { if (type === 'dockerhub') return true; const trimmed = url.trim(); if (!trimmed) return false; - const lower = trimmed.toLowerCase(); - if (lower.startsWith('javascript:') || lower.startsWith('data:') || lower.startsWith('file:') || lower.startsWith('ftp:')) { - return false; - } + let parsed: URL; try { - const parsed = new URL(trimmed.includes('://') ? trimmed : `https://${trimmed}`); - if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false; - if (!parsed.hostname) return false; + parsed = new URL(trimmed.includes('://') ? trimmed : `https://${trimmed}`); } catch { return false; } + if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') return false; + if (!parsed.hostname) return false; return true; } diff --git a/backend/src/services/TemplateService.ts b/backend/src/services/TemplateService.ts index 9b69d7fb..70f3bbd8 100644 --- a/backend/src/services/TemplateService.ts +++ b/backend/src/services/TemplateService.ts @@ -233,7 +233,9 @@ export class TemplateService { console.log(`[Templates] Fetching from registry: ${registryUrl}`); const debug = isDebugEnabled(); - if (registryUrl.includes('api.linuxserver.io')) { + let registryHost = ''; + try { registryHost = new URL(registryUrl).hostname.toLowerCase(); } catch { /* invalid URL, treated as non-LSIO */ } + if (registryHost === 'api.linuxserver.io') { const response = await axios.get(registryUrl, { timeout: 20_000 }); // Official LSIO API Schema Mapping const lsioApps = response.data?.data?.repositories?.linuxserver ?? {};