Files
Alta-Proxy-Tool/src/url-policy.js
T

93 lines
2.3 KiB
JavaScript

'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,
};