UNPKG

heimdall-tide

Version:

SDK for communicating with a Tide Enclave

187 lines 7.29 kB
"use strict"; // // Tide Protocol - Infrastructure for a TRUE Zero-Trust paradigm // Copyright (C) 2022 Tide Foundation Ltd // // This program is free software and is subject to the terms of // the Tide Community Open Code License as published by the // Tide Foundation Limited. You may modify it and redistribute // it in accordance with and subject to the terms of that License. // This program is distributed WITHOUT WARRANTY of any kind, // including without any implied warranty of MERCHANTABILITY or // FITNESS FOR A PARTICULAR PURPOSE. // See the Tide Community Open Code License for more details. // You should have received a copy of the Tide Community Open // Code License along with this program. // If not, see https://tide.org/licenses_tcoc2-0-0-en Object.defineProperty(exports, "__esModule", { value: true }); exports.windowType = exports.Heimdall = void 0; class Heimdall { constructor(init) { this.enclaveOrigin = init.homeOrkOrigin; this.voucherURL = init.voucherURL; this.signed_client_origin = init.signed_client_origin; this.vendorId = init.vendorId; } enclaveClosed() { return this.enclaveWindow.closed; } getOrkUrl() { throw new Error("Method not implemented."); } async open() { switch (this._windowType) { case windowType.Popup: return this.openPopUp(); case windowType.Redirect: throw new Error("Method not implemented."); case windowType.Hidden: return this.openHiddenIframe(); } } send(data) { switch (this._windowType) { case windowType.Popup: this.sendPostWindowMessage(data); break; case windowType.Redirect: throw new Error("Method not implemented."); case windowType.Hidden: this.sendPostWindowMessage(data); break; } } async recieve(type) { switch (this._windowType) { case windowType.Popup: return this.waitForWindowPostMessage(type); case windowType.Redirect: throw new Error("Method not implemented."); case windowType.Hidden: return this.waitForWindowPostMessage(type); } } close() { switch (this._windowType) { case windowType.Popup: this.closePopupEnclave(); break; case windowType.Redirect: throw new Error("Method not implemented."); case windowType.Hidden: this.closeHiddenIframe(); break; default: throw "Unknown window type"; } } onerror(data) { throw new Error("Method not implemented."); } async openPopUp() { const left_pos = (window.length / 2) - 400; const w = window.open(this.getOrkUrl(), "_blank", `width=800,height=800,left=${left_pos}`); if (!w) return false; this.enclaveWindow = w; await this.waitForWindowPostMessage("pageLoaded"); // we need to wait for the page to load before we send sensitive data return true; } async closeHiddenIframe() { window.document .querySelectorAll('iframe#heimdall') .forEach(iframe => iframe.remove()); } async openHiddenIframe() { try { // Remove any existing iframes with heimdall id this.closeHiddenIframe(); // 1. Create the iframe const iframe = document.createElement('iframe'); // Create iframe error listener const iframeErrorListener = new Promise((res) => { iframe.onerror = () => res(false); iframe.addEventListener("error", () => { res(false); // failed to load }); }); iframe.src = this.getOrkUrl().toString(); iframe.style.display = 'none'; // hide it visually iframe.id = "heimdall"; // in case multiple frames get popped up - we only want one iframe.setAttribute('aria-hidden', 'true'); // accessibility hint // 2. Add it to the document document.body.appendChild(iframe); // 3. Keep a reference to its window for postMessage this.enclaveWindow = iframe.contentWindow; if (!this.enclaveWindow) return false; // Create an iframe success listener const pageLoaded = new Promise(async (res) => { await this.waitForWindowPostMessage("pageLoaded"); res(true); // page loaded }); const timeout = new Promise((resolve) => { setTimeout(() => resolve(false), 2000); // 2-second timeout }); const loadedResult = await Promise.race([iframeErrorListener, pageLoaded, timeout]); return loadedResult; } catch { return false; } } closePopupEnclave() { this.enclaveWindow.close(); } async waitForWindowPostMessage(responseTypeToAwait) { return new Promise((resolve) => { const handler = (event) => { const response = this.processEvent(event.data, event.origin, responseTypeToAwait); if (response.ok) { resolve(response.message); window.removeEventListener("message", handler); } else { if (response.print) console.error("[HEIMDALL] Recieved enclave error: " + response.error); } }; window.addEventListener("message", handler, false); }); } sendPostWindowMessage(message) { this.enclaveWindow.postMessage(message, this.enclaveOrigin); } processEvent(data, origin, expectedType) { if (origin !== new URL(this.enclaveOrigin).origin) { // Something's not right... The message has come from an unknown domain... return { ok: false, print: false, error: "WRONG WINDOW SENT MESSAGE" }; } switch (data.type) { case "newORKUrl": this.enclaveOrigin = new URL(data.url).origin; break; case "error": this.onerror(data); return { ok: false, print: false, error: "handled error" }; } if (expectedType !== data.type) { console.log("[HEIMDALL] Received type{" + data.type + "} but waiting for type{" + expectedType + "}"); return { ok: false, print: false, error: "handled error" }; } else { console.log("[HEIMDALL] Correctly received type{" + data.type + "}"); return { ok: true, message: data.message }; } } } exports.Heimdall = Heimdall; var windowType; (function (windowType) { windowType[windowType["Popup"] = 0] = "Popup"; windowType[windowType["Redirect"] = 1] = "Redirect"; windowType[windowType["Hidden"] = 2] = "Hidden"; })(windowType || (exports.windowType = windowType = {})); ; ; //# sourceMappingURL=heimdall.js.map