UNPKG

@shopify/app-bridge

Version:

**Shopify is doubling our engineering staff in 2021! [Join our team and work on libraries like this one.](https://smrtr.io/5GGrc)**

69 lines (68 loc) 2.65 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.makeSafe = exports.isSafe = void 0; var FILE_URI_MATCH = /\/\/\//; var INVALID_RELATIVE_URL = /[/\\][/\\]/; var VALID_PROTOCOLS = ['https:', 'http:']; var DUMMY_HOSTNAME = 'http://test.com'; function isSafe(redirectUrl, _a) { var _b = _a === void 0 ? {} : _a, _c = _b.allowedDomains, allowedDomains = _c === void 0 ? [] : _c, _d = _b.subdomains, subdomains = _d === void 0 ? [] : _d, matchPath = _b.matchPath, requireAbsolute = _b.requireAbsolute, requireSSL = _b.requireSSL; if (FILE_URI_MATCH.test(redirectUrl)) { return false; } if (redirectUrl.startsWith('/')) { if (allowedDomains.length > 0 || subdomains.length > 0 || requireAbsolute || requireSSL) { return false; } if (matchPath) { // Creating a new URL expands the pathname in case of things like `/a/../b` return pathMatches(new URL(redirectUrl, DUMMY_HOSTNAME), redirectUrl, matchPath); } return !INVALID_RELATIVE_URL.test(redirectUrl); } var url; try { url = new URL(redirectUrl); } catch (error) { return false; } if (!VALID_PROTOCOLS.includes(url.protocol)) { return false; } if (requireSSL && url.protocol !== 'https:') { return false; } if (url.username || url.password) { return false; } if (matchPath && !pathMatches(url, redirectUrl, matchPath)) { return false; } if (!hostIsValid(url, allowedDomains, subdomains)) { return false; } return true; } exports.isSafe = isSafe; function hostIsValid(url, allowedDomains, subdomains) { if (!subdomains.every(function (subdomain) { return subdomain.startsWith('.'); })) { throw new TypeError('Subdomains must begin with .'); } var hostname = url.hostname; return ((allowedDomains.length === 0 && subdomains.length === 0) || allowedDomains.includes(hostname) || subdomains.some(function (subdomain) { return hostname.endsWith(subdomain); })); } function pathMatches(url, originalUrl, matcher) { var pathname = url.pathname; // Gets just the unresolve pathname, i.e., `http://foo.com/a/../b => /a/../b var originalPathname = originalUrl.replace(url.origin, '').split('?')[0]; return typeof matcher === 'string' ? pathname === matcher && originalPathname === matcher : matcher.test(pathname) && matcher.test(originalPathname); } function makeSafe(url, fallback, options) { return isSafe(url, options) ? encodeURI(url) : fallback; } exports.makeSafe = makeSafe;