UNPKG

@oraichain/customauth

Version:

CustomAuth login with torus to get user private key

110 lines (99 loc) 3.65 kB
import { BroadcastChannel } from "@toruslabs/broadcast-channel"; import { LOGIN_TYPE, UX_MODE_TYPE } from "../utils/enums"; import { broadcastChannelOptions, randomId } from "../utils/helpers"; import log from "../utils/loglevel"; import PopupHandler from "../utils/PopupHandler"; import { Auth0ClientOptions, ILoginHandler, LoginWindowResponse, PopupResponse, MultifactorsGenericObject, MultifactorsVerifierResponse, } from "./interfaces"; abstract class AbstractLoginHandler implements ILoginHandler { public nonce: string = randomId(); public finalURL: URL; // Not using object constructor because of this issue // https://github.com/microsoft/TypeScript/issues/5326 constructor( readonly clientId: string, readonly redirect_uri: string, readonly typeOfLogin: LOGIN_TYPE, readonly uxMode: UX_MODE_TYPE, readonly redirectToOpener?: boolean, readonly jwtParams?: Auth0ClientOptions, readonly customState?: MultifactorsGenericObject ) {} get state(): string { return encodeURIComponent( window.btoa( JSON.stringify({ ...(this.customState || {}), instanceId: this.nonce, typeOfLogin: this.typeOfLogin, redirectToOpener: this.redirectToOpener || false, }) ) ); } handleLoginWindow(params: { locationReplaceOnRedirect?: boolean; popupFeatures?: string }): Promise<LoginWindowResponse> { const verifierWindow = new PopupHandler({ url: this.finalURL, features: params.popupFeatures }); return new Promise<LoginWindowResponse>((resolve, reject) => { let bc: BroadcastChannel; const handleData = async (ev: { error: string; data: PopupResponse }) => { try { const { error, data } = ev; const { instanceParams, hashParams: { access_token: accessToken, id_token: idToken, ...rest }, } = data || {}; if (error) { log.error(ev); reject(new Error(`Error: ${error}. Info: ${JSON.stringify(ev.data || {})}`)); return; } if (ev.data) { if (!this.redirectToOpener && bc) await bc.postMessage({ success: true }); resolve({ accessToken, idToken: idToken || "", ...rest, // State has to be last here otherwise it will be overwritten state: instanceParams, }); } } catch (error) { log.error(error); reject(error); } }; if (!this.redirectToOpener) { bc = new BroadcastChannel(`redirect_channel_${this.nonce}`, broadcastChannelOptions); bc.addEventListener("message", async (ev) => { await handleData(ev); bc.close(); verifierWindow.close(); }); } else { const postMessageEventHandler = async (postMessageEvent: MessageEvent) => { if (!postMessageEvent.data) return; const ev = postMessageEvent.data; if (ev.channel !== `redirect_channel_${this.nonce}`) return; window.removeEventListener("message", postMessageEventHandler); handleData(ev); verifierWindow.close(); }; window.addEventListener("message", postMessageEventHandler); } verifierWindow.open(); verifierWindow.once("close", () => { if (bc) bc.close(); reject(new Error("user closed popup")); }); }); } abstract getUserInfo(params: LoginWindowResponse): Promise<MultifactorsVerifierResponse>; abstract setFinalUrl(): void; } export default AbstractLoginHandler;