UNPKG

@upbond/upbond-embed

Version:
306 lines (282 loc) 9.86 kB
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable no-console */ /* eslint-disable prefer-const */ import timingSafeEqual from "@ansugroup/timing-safe-equal"; import { ObjectMultiplex, Substream } from "@toruslabs/openlogin-jrpc"; import * as crypto from "crypto-browserify"; // import * as ethers from "ethers"; // import Web3Token from "web3-token"; import config from "./config"; import UpbondInpageProvider from "./inpage-provider"; // import { ConsentDidResponse } from "./interfaces"; export default class Consent { communicationMux: ObjectMultiplex; provider: UpbondInpageProvider; consentConfigurations: { scopes: string[]; enabled: boolean; }; flowConfig: string; publicKey: string; isLoggedIn: boolean; didIntervalRequest: number; isDidDeployed: boolean; consentStreamName: { consent: string; listenerStream: string; getConsentData: string }; didCreationCb: Record<any, any>; constructor({ publicKey, scope, consentStream, provider, isLoggedIn = false, didIntervalRequest = 5000, }: { publicKey: string; scope: string[]; consentStream: ObjectMultiplex; provider: UpbondInpageProvider; isLoggedIn?: boolean; didIntervalRequest?: number; }) { if (publicKey) { this.didIntervalRequest = didIntervalRequest; this.isLoggedIn = isLoggedIn; this.consentConfigurations = { enabled: false, scopes: scope, }; this.flowConfig = "normal"; this.publicKey = publicKey; this.communicationMux = consentStream; this.provider = provider; this.isDidDeployed = false; this.consentStreamName = { consent: "consent", listenerStream: "did_listener_stream", getConsentData: "did_get_consent_data", }; this.didCreationCb = {}; this.listenDidCreation(); } } init() { if (!this.publicKey) { throw new Error(`Missing secret public key`); } if (!this.consentConfigurations.scopes || this.consentConfigurations.scopes.length === 0) { throw new Error(`Missing scope`); } console.log(`Consent management ready to go`); this.consentConfigurations.enabled = true; const stream = this.communicationMux.getStream(this.consentStreamName.consent) as Substream; stream.write({ name: "init", data: { scope: this.consentConfigurations.scopes, publicKey: this.publicKey, host: window.location.host, }, }); } getDid(): Promise<{ jwt: string; jwtPresentation: string; }> { return new Promise((resolve, reject) => { const stream = this.communicationMux.getStream(this.consentStreamName.consent) as Substream; stream.write({ name: "request", data: { scope: this.consentConfigurations.scopes, publicKey: this.publicKey, host: window.location.host, }, }); stream.on("data", (data) => { if (data.name === "error") { if (data.data.code && data.data.code === 401) { this.isDidDeployed = false; this.didCreationCb = data.data.params; resolve({ jwt: "", jwtPresentation: "", }); } reject(new Error(data.data.msg)); } else { this.isDidDeployed = true; resolve(data.data); } }); }); } // requestDIDCreationOrFilledForm(clientId: string, params: { [x: string]: any }, secKey: string): Promise<ConsentDidResponse> { // return new Promise((resolve, reject) => { // try { // const ethProvider = new ethers.providers.Web3Provider(this.provider); // const signer = ethProvider.getSigner(); // Web3Token.sign( // async (msg: string) => { // const data = { // domain: "example.com", // scope: this.consentConfigurations.scopes, // type: "did_creation_request", // data: { // clientId, // clientSecret: secKey, // params, // }, // expires_in: "3 days", // msg, // }; // const tx = await signer.signMessage(JSON.stringify(data)); // return tx; // }, // { // domain: "example.com", // expires_in: "3 days", // } // ); // const stream = this.communicationMux.getStream("consent") as Substream; // stream.on("data", (data) => { // if (data.name === "consent_response") { // resolve(data.data); // } else if (data.name === "consent_error") { // reject(data.data.msg); // } // }); // stream.on("error", (err) => { // reject(err); // }); // } catch (error) { // if (error.message && error.message.includes("user rejected signing")) { // reject(new Error("User rejected your request")); // } // reject(error); // } // }); // } // requestUserData(did: { jwt: string; jwtPresentation: string }, cb?: (stream: Substream) => void): Promise<ConsentDidResponse> { // return new Promise((resolve, reject) => { // if (!this.isDidDeployed || (did.jwt === "" && did.jwtPresentation === "")) { // const data = this.requestDIDCreationOrFilledForm( // this.consentApiKey, // Object.keys(this.didCreationCb).length > 0 ? this.didCreationCb : {}, // this.key // ); // resolve(data); // return; // } // if (cb && typeof cb !== "function") { // reject(new Error(`Callback must be a function`)); // } // if (!did || !did.jwt || !did.jwtPresentation) { // reject(new Error(`Missing did object`)); // } // const { jwt, jwtPresentation } = did; // const stream = this.communicationMux.getStream("consent") as Substream; // try { // const ethProvider = new ethers.providers.Web3Provider(this.provider); // const signer = ethProvider.getSigner(); // Web3Token.sign( // async (msg: string) => { // const data = { // domain: this.isLocalhost() ? "example.com" : new URL(window.location.origin).hostname, // scope: this.consentConfigurations.scopes, // type: "consent_request", // data: { // vc: jwt, // vp: jwtPresentation, // }, // expires_in: "3 days", // msg, // }; // const tx = await signer.signMessage(JSON.stringify(data)); // return tx; // }, // { // domain: this.isLocalhost() ? "example.com" : new URL(window.location.origin).hostname, // expires_in: "3 days", // } // ); // if (cb) { // const consentStream = this.communicationMux.getStream("consent_stream") as Substream; // cb(consentStream); // } // stream.on("data", (data) => { // if (data.name === "consent_response") { // resolve(data.data); // stream.destroy(); // } else if (data.name === "consent_error") { // reject(data.data.msg); // stream.destroy(); // } // }); // stream.on("error", (err) => { // reject(err); // stream.destroy(); // }); // } catch (error) { // if (error.message && error.message.includes("user rejected signing")) { // reject(new Error("User rejected your request")); // stream.destroy(); // } // reject(error); // stream.destroy(); // } // }); // } // getUserData(): Promise<ConsentDidResponse> { // return new Promise((resolve, reject) => { // const stream = this.communicationMux.getStream(this.consentStreamName.getConsentData) as Substream; // stream.write({ // name: this.consentStreamName.getConsentData, // data: { // clientId: this.consentApiKey, // secretKey: this.key, // origin: window.location.origin, // }, // }); // stream.on("data", (ev) => { // if (ev.name === "result") { // resolve(ev.data); // } // reject(new Error("Consent does not exist")); // }); // }); // } protected listenDidCreation() { const stream = this.communicationMux.getStream(this.consentStreamName.listenerStream) as Substream; stream.write({ name: config.DID_STREAM_NAME.REQUEST, data: { interval: this.didIntervalRequest, }, }); stream.on("data", (ev) => { if (ev.name && ev.name === config.DID_STREAM_NAME.RESULT) { if (ev.data) { this.isDidDeployed = true; } else { this.isDidDeployed = false; } } }); } protected isLocalhost(): boolean { return new URL(window.location.origin).hostname === "localhost"; } protected _createDigest(encodedData: crypto.BinaryLike, format: crypto.BinaryToTextEncoding) { return crypto.createHmac("sha256", this.publicKey).update(encodedData).digest(format); } protected _decode(value: string) { let [encodedData, sourceDigest] = value.split("!"); if (!encodedData || !sourceDigest) throw new Error("invalid value(s)"); const json = Buffer.from(encodedData, "base64").toString("utf8"); const decodedData = JSON.parse(json); const checkDigest = this._createDigest(encodedData, "base64"); const digestsEqual = timingSafeEqual(sourceDigest, checkDigest); if (!digestsEqual) throw new Error("invalid value(s)"); return decodedData; } }