93 lines
2.3 KiB
JavaScript
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,
|
|
};
|