'use strict'; const MAX_ORIGIN_LENGTH = 512; const ALTA_SUFFIXES = Object.freeze(['avasecurity.com', 'avigilon.com']); function policyError(message = 'Invalid Alta deployment origin') { const error = new TypeError(message); error.code = 'INVALID_ALTA_ORIGIN'; return error; } function canonicalizeAltaOrigin(value) { if (typeof value !== 'string' || value.length === 0 || value.length > MAX_ORIGIN_LENGTH) { throw policyError(); } if (value !== value.trim() || /[\u0000-\u0020\u007f]/.test(value)) { throw policyError(); } let parsed; try { parsed = new URL(value); } catch { throw policyError(); } if (parsed.protocol !== 'https:' || parsed.username || parsed.password || parsed.hash || parsed.search) { throw policyError(); } if (parsed.port && parsed.port !== '443') { throw policyError(); } if (parsed.pathname !== '/' && parsed.pathname !== '') { throw policyError(); } const hostname = parsed.hostname.toLowerCase(); const suffix = ALTA_SUFFIXES.find((candidate) => hostname.endsWith(`.${candidate}`)); if (!suffix) { throw policyError(); } const subdomain = hostname.slice(0, -(suffix.length + 1)); const labels = subdomain.split('.'); if (labels.some((label) => !/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/.test(label))) { throw policyError(); } return `https://${hostname}`; } function isAltaOrigin(value) { try { canonicalizeAltaOrigin(value); return true; } catch { return false; } } function assertSameAltaOrigin(candidate, expectedOrigin) { if (typeof candidate !== 'string' || /[\u0000-\u0020\u007f]/.test(candidate)) { throw policyError('Invalid Alta request URL'); } let target; try { target = new URL(candidate); } catch { throw policyError('Invalid Alta request URL'); } const expected = canonicalizeAltaOrigin(expectedOrigin); const actual = canonicalizeAltaOrigin(target.origin); if ( actual !== expected || target.origin !== expected || target.username || target.password || target.hash ) { throw policyError('Alta request URL changed origin'); } return target; } module.exports = { ALTA_SUFFIXES, MAX_ORIGIN_LENGTH, assertSameAltaOrigin, canonicalizeAltaOrigin, isAltaOrigin, validateAltaOrigin: canonicalizeAltaOrigin, };