UNPKG

heimdall-tide

Version:

SDK for communicating with a Tide Enclave

218 lines 8.57 kB
import { Heimdall, windowType } from "../heimdall"; export class RequestEnclave extends Heimdall { constructor() { super(...arguments); this._windowType = windowType.Hidden; this.initDone = this.recieve("init done"); } init(data) { if (!data.doken) throw 'Doken not provided'; this.doken = data.doken; this.dokenRefreshCallback = data.dokenRefreshCallback; this.requireReloginCallback = data.requireReloginCallback; this.recieve("hidden enclave").then((data) => this.handleHiddenEnclaveResponse(data)); this.open().then((success) => { if (success) { this.send({ type: "init", message: { doken: this.doken } }); } else throw 'Error opening enclave'; }); return this; } async handleHiddenEnclaveResponse(msg) { // Below is the session key mismatch flow that was implemented but then it was decided a basic relogin was more elegent // Keeping it though because it is nearly identical to the flow where a tide user delegates a token to another tide user // This would require the second tide user to sign a new delegated token with their current session key // This would be gold in a cvk scenario // if(msg == "session key mismatch" && this._windowType == windowType.Hidden){ // this.initDone = this.recieve("init done"); // await the REOPENED HIDDEN ENCLAVE INIT DONE SIGNAL // // looks like the hidden iframe has not allowed data to be stored on the browser OR the session key is mismatched with whats on the enclave vs doken // // either way we gotta get a doken with the appropriate session key // // Close the hidden enclave // this.close(); // // We're now going to open the request enclave as a popup with the mismatched doken // // The page should recognise the doken is mismatched, generate a new one, then close // this._windowType = windowType.Popup; // // open popup // await this.open(); // // send doken to refresh // this.send({ // type: "init", // message:{ // doken: this.doken // } // }); // // wait for new doken // const resp = await this.recieve("refreshed doken"); // this.doken = resp.doken; // if(this.requireReloginCallback) this.requireReloginCallback(); // // close pop up enclave // this.close(); // // reset page to hidden iframe // this._windowType = windowType.Hidden; // // open hidden iframe // this.open().then((success: boolean) => { // if(success){ // this.send({ // type: "init", // message: { // doken: this.doken // } // }); // }else throw 'Error opening enclave'; // }); // } if (msg == "session key mismatch") { this.close(); this.requireReloginCallback(); // should initiate a full client page reload, killing this } else if (msg == "storage issue") { // Convert hidden enclave into popup this.close(); this._windowType = windowType.Popup; this.open().then((success) => { if (success) { this.send({ type: "init", message: { doken: this.doken } }); } else throw 'Error opening enclave'; }); } this.recieve("hidden enclave").then((data) => this.handleHiddenEnclaveResponse(data)); } getOrkUrl() { // construct ork url const url = new URL(this.enclaveOrigin); // Set hidden status url.searchParams.set("hidden", this._windowType == windowType.Hidden ? "true" : "false"); // Set vendor public url.searchParams.set("vendorId", this.vendorId); // Set client origin url.searchParams.set("origin", encodeURIComponent(window.location.origin)); // Set client origin signature (by vendor) url.searchParams.set("originsig", encodeURIComponent(this.signed_client_origin)); // Set voucher url url.searchParams.set("voucherURL", encodeURIComponent(this.voucherURL)); // Set requestsed enclave url.searchParams.set("type", "request"); return url; } checkEnclaveOpen() { if (this.enclaveClosed()) { // Enclave was closed! // We need to reopen the enclave and await the init again this.initDone = this.recieve("init done"); this.open().then((success) => { if (success) { this.send({ type: "init", message: { doken: this.doken } }); } else throw 'Error opening enclave'; }); } } async execute(data) { this.checkEnclaveOpen(); await this.initDone; const pre_resp = this.recieve("sign request completed"); this.send({ type: "request", message: { flow: "sign", request: data, } }); const resp = await pre_resp; if (!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp; if (!resp.every((d) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays'; return resp; } async decrypt(data) { this.checkEnclaveOpen(); await this.initDone; const pre_resp = this.recieve("decrypt request completed"); this.send({ type: "request", message: { flow: "decrypt", request: data } }); const resp = await pre_resp; if (!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp; if (!resp.every((d) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays'; return resp; } async encrypt(data) { this.checkEnclaveOpen(); await this.initDone; const pre_resp = this.recieve("encrypt request completed"); this.send({ type: "request", message: { flow: "encrypt", request: data } }); const resp = await pre_resp; if (!Array.isArray(resp)) throw 'Expecting request completed data to be an array, not' + resp; if (!resp.every((d) => d instanceof Uint8Array)) throw 'Expecting all entries in response to be Uint8Arrays'; return resp; } async updateDoken(doken) { this.doken = doken; this.send({ type: "doken refresh", message: { doken: this.doken } }); } async onerror(data) { if (typeof data.message === "string") { switch (data.message) { case "expired": if (!this.dokenRefreshCallback) { console.error("[HEIMDALL] Doken on enclave has expired but there is no Doken Refresh Callback registered"); return; } console.log("[HEIMDALL] Refreshing doken"); this.doken = await this.dokenRefreshCallback(); this.send({ type: "doken refresh", message: { doken: this.doken } }); break; default: this.close(); throw new Error("[HEIMDALL] Recieved enclave error: " + data.message); } } } } //# sourceMappingURL=RequestEnclave.js.map