@upbond/upbond-embed
Version:
Embed script for Upbond
306 lines (282 loc) • 9.86 kB
text/typescript
/* 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;
}
}