@revenuecat/purchases-ui-js
Version:
Web components for Paywalls. Powered by RevenueCat
53 lines (52 loc) • 1.99 kB
JavaScript
const SAFE_WEB_VIEW_PROTOCOL = "https:";
/**
* Returns a sanitized URL if it is a well-formed absolute `https:` URL,
* otherwise `null`.
*
* The web view embeds remote, third-party bundles, so only `https` is allowed:
* `http`, `data:`, `blob:`, `javascript:`, protocol-relative (`//host`) and
* relative URLs are all rejected, as are URLs carrying embedded credentials
* (`https://user:pass@host`). Whitespace and control characters (code points
* <= 0x20) are stripped before validation so obfuscated payloads such as
* "https\t://" or "jAvAsCrIpT:" cannot slip through. The normalized, parsed
* `href` is returned (not the raw input) so no control characters reach the
* iframe `src`.
*/
export function sanitizeWebViewUrl(url) {
const normalized = Array.from(url)
.filter((character) => character.charCodeAt(0) > 0x20)
.join("");
let parsed;
try {
parsed = new URL(normalized);
}
catch {
return null;
}
if (parsed.protocol.toLowerCase() !== SAFE_WEB_VIEW_PROTOCOL) {
return null;
}
// Reject embedded credentials: they have no place in an asset URL and can be
// used to obscure the real host (e.g. `https://trusted.com@evil.com`).
if (parsed.username !== "" || parsed.password !== "") {
return null;
}
return parsed.href;
}
/**
* Returns whether `url` resolves to the same origin as `hostOrigin` (typically
* `window.location.origin`). Used as a guard before applying the
* `allow-scripts allow-same-origin` sandbox: that combination is only safe when
* the framed bundle is on a different origin than the host page, otherwise it
* could script and un-sandbox the host. Callers should pass an already
* sanitized URL; an unparseable URL conservatively reports `true` (treat as
* same-origin -> block).
*/
export function isSameOriginAsHost(url, hostOrigin) {
try {
return new URL(url).origin === hostOrigin;
}
catch {
return true;
}
}