UNPKG

@quadible/web-sdk

Version:

The web sdk for Quadible's behavioral authentication service.

121 lines 4.95 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.withIframe = withIframe; exports.selectorToElement = selectorToElement; exports.addStyleString = addStyleString; exports.isAnyParentCrossOrigin = isAnyParentCrossOrigin; const async_1 = require("./async"); const data_1 = require("./data"); async function withIframe(action, initialHtml, domPollInterval = 50) { const d = document; // document.body can be null while the page is loading while (!d.body) { await (0, async_1.wait)(domPollInterval); } const iframe = d.createElement('iframe'); try { await new Promise((_resolve, _reject) => { let isComplete = false; const resolve = () => { isComplete = true; _resolve(); }; const reject = (error) => { isComplete = true; _reject(error); }; iframe.onload = resolve; iframe.onerror = reject; const { style } = iframe; style.setProperty('display', 'block', 'important'); // Required for browsers to calculate the layout style.position = 'absolute'; style.top = '0'; style.left = '0'; style.visibility = 'hidden'; if (initialHtml && 'srcdoc' in iframe) { iframe.srcdoc = initialHtml; } else { iframe.src = 'about:blank'; } d.body.appendChild(iframe); // WebKit in WeChat doesn't fire the iframe's `onload` for some reason. // This code checks for the loading state manually. // See https://github.com/fingerprintjs/fingerprintjs/issues/645 const checkReadyState = () => { // The ready state may never become 'complete' in Firefox despite the 'load' event being fired. // So an infinite setTimeout loop can happen without this check. // See https://github.com/fingerprintjs/fingerprintjs/pull/716#issuecomment-986898796 if (isComplete) { return; } // Make sure iframe.contentWindow and iframe.contentWindow.document are both loaded // The contentWindow.document can miss in JSDOM (https://github.com/jsdom/jsdom). if (iframe.contentWindow?.document?.readyState === 'complete') { resolve(); } else { setTimeout(checkReadyState, 10); } }; checkReadyState(); }); while (!iframe.contentWindow?.document?.body) { await (0, async_1.wait)(domPollInterval); } return await action(iframe, iframe.contentWindow); } finally { iframe.parentNode?.removeChild(iframe); } } function selectorToElement(selector) { const [tag, attributes] = (0, data_1.parseSimpleCssSelector)(selector); const element = document.createElement(tag ?? 'div'); for (const name of Object.keys(attributes)) { const value = attributes[name].join(' '); // Changing the `style` attribute can cause a CSP error, therefore we change the `style.cssText` property. // https://github.com/fingerprintjs/fingerprintjs/issues/733 if (name === 'style') { addStyleString(element.style, value); } else { element.setAttribute(name, value); } } return element; } function addStyleString(style, source) { // We don't use `style.cssText` because browsers must block it when no `unsafe-eval` CSP is presented: https://csplite.com/csp145/#w3c_note // Even though the browsers ignore this standard, we don't use `cssText` just in case. for (const property of source.split(';')) { const match = /^\s*([\w-]+)\s*:\s*(.+?)(\s*!([\w-]+))?\s*$/.exec(property); if (match) { const [, name, value, , priority] = match; style.setProperty(name, value, priority || ''); // The last argument can't be undefined in IE11 } } } function isAnyParentCrossOrigin() { let currentWindow = window; for (;;) { const parentWindow = currentWindow.parent; if (!parentWindow || parentWindow === currentWindow) { return false; // The top page is reached } try { if (parentWindow.location.origin !== currentWindow.location.origin) { return true; } } catch (error) { // The error is thrown when `origin` is accessed on `parentWindow.location` when the parent is cross-origin if (error instanceof Error && error.name === 'SecurityError') { return true; } throw error; } currentWindow = parentWindow; } } //# sourceMappingURL=dom.js.map