Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mfa flow for custom verifiers #146

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
5 changes: 0 additions & 5 deletions examples/vue-example/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion examples/vue-example/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"@web3auth/ethereum-provider": "^1.0.0",
"bs58": "^4.0.1",
"core-js": "^3.15.2",
"openlogin": "file:../../packages/wrapper/",
"vue": "^2.6.14",
"web3": "^1.7.0"
},
Expand Down
29 changes: 28 additions & 1 deletion examples/vue-example/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
<div class="grid grid-cols-2 gap-2">
<button class="btn" @click="getUserInfo">Get user info</button>
<button class="btn" @click="getEd25519Key">Get Ed25519Key</button>
<button @click="enableMfa">Setup Mfa</button>
<button @click="showSettings">Show Settings</button>
</div>
</div>
<div class="col-span-2 text-left">
Expand Down Expand Up @@ -111,7 +113,7 @@ export default Vue.extend({
},
async mounted() {
this.loading = true;
const openlogin = getOpenLoginInstance();
const openlogin = getOpenLoginInstance(whitelabel);
await openlogin.init();
if (openlogin.privKey) {
this.privKey = openlogin.privKey;
Expand Down Expand Up @@ -143,6 +145,7 @@ export default Vue.extend({
// login_hint: '[email protected]',
// },
// sessionTime: 30, //seconds
curve: "ed25519",
});
if (privKey) {
this.privKey = openlogin.privKey;
Expand All @@ -169,6 +172,7 @@ export default Vue.extend({
mfaLevel: "mandatory",
loginProvider: "",
redirectUrl: `${window.origin}`,
curve: "ed25519",
});
if (privKey) {
this.privKey = privKey;
Expand Down Expand Up @@ -202,6 +206,29 @@ export default Vue.extend({
const userInfo = await openlogin.getUserInfo();
this.printToConsole(userInfo);
},
async enableMfa() {
const openlogin = getOpenLoginInstance();

try {
await openlogin.enableMfa();
} catch (error) {
console.log("error", error);
} finally {
this.privKey = openlogin.privKey;
}
},

async showSettings() {
const openlogin = getOpenLoginInstance();

try {
await openlogin.showSettings();
} catch (error) {
console.log("error", error);
} finally {
this.privKey = openlogin.privKey;
}
},

getEd25519Key() {
const openlogin = getOpenLoginInstance();
Expand Down
2 changes: 1 addition & 1 deletion examples/vue-example/src/lib/loginConfig.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { LOGIN_PROVIDER } from "@toruslabs/openlogin";
import { LoginConfig } from "@toruslabs/openlogin-jrpc";
import { LOGIN_PROVIDER } from "openlogin";

export default {
// email_passwordless: {
Expand Down
7 changes: 3 additions & 4 deletions examples/vue-example/src/lib/openlogin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import OpenLogin from "@toruslabs/openlogin";
import { WhiteLabelData } from "@toruslabs/openlogin-jrpc";
import OpenLogin from "openlogin";

import loginConfig from "./loginConfig";

Expand All @@ -14,13 +14,12 @@ export function getOpenLoginInstance(whiteLabel?: WhiteLabelData) {
// clientId is not required for localhost, you can set it to any string
// for development
clientId: YOUR_PROJECT_ID,
network: "testnet",
uxMode: "redirect",
network: "development",
uxMode: "popup",
whiteLabel,
loginConfig,
storageKey: "session",
});
}
if (whiteLabel) openLoginInstance.state.whiteLabel = whiteLabel;
return openLoginInstance;
}
1 change: 1 addition & 0 deletions packages/openlogin-jrpc/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -241,5 +241,6 @@ export type SessionInfo = {
_whiteLabelData?: WhiteLabelData;
_loginConfig: LoginConfig;
_sessionId?: string;
_isNewSession?: boolean;
_sessionNamespace?: string;
};
61 changes: 60 additions & 1 deletion packages/openlogin/src/OpenLogin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { getRpcPromiseCallback, JRPCRequest, LoginConfig, OriginData, SessionInf
import { base64url, jsonToBase64, keccak, randomId } from "@toruslabs/openlogin-utils";
import merge from "lodash.merge";

import { ALLOWED_INTERACTIONS, OPENLOGIN_METHOD, OPENLOGIN_NETWORK, UX_MODE } from "./constants";
import { ALLOWED_INTERACTIONS, OPENLOGIN_METHOD, OPENLOGIN_NETWORK, SESSION_EXPIRED, UX_MODE } from "./constants";
import {
BaseLogoutParams,
BaseRedirectParams,
Expand Down Expand Up @@ -43,6 +43,7 @@ export type OpenLoginState = {
whiteLabel: WhiteLabelData;
loginConfig: LoginConfig;
storageServerUrl: string;
isMfaEnabled: boolean;
sessionNamespace: string;
};

Expand Down Expand Up @@ -112,6 +113,7 @@ class OpenLogin {
support3PC: !options.no3PC,
whiteLabel: options.whiteLabel,
storageServerUrl: options._storageServerUrl,
isMfaEnabled: false,
sessionNamespace: options._sessionNamespace,
};
}
Expand Down Expand Up @@ -212,6 +214,60 @@ class OpenLogin {
return { privKey: this.privKey };
}

async enableMfa(): Promise<void> {
try {
this._syncState(await this._getData());
const storeData = this.state.store.getStore();
if (!this.privKey) throw new Error("Please login first.");
if (storeData.isMfaEnabled) {
throw new Error("Mfa is already enabled for this account");
}
const params: Record<string, unknown> = {};
// defaults
params.redirectUrl = this.state.redirectUrl;

await this.request<void>({
method: OPENLOGIN_METHOD.ENABLE_MFA,
params: [params],
startUrl: this.state.startUrl,
popupUrl: this.state.popupUrl,
allowedInteractions: [ALLOWED_INTERACTIONS.POPUP, ALLOWED_INTERACTIONS.REDIRECT],
});
this._syncState(await this._getData());
} catch (error) {
if (error?.message === SESSION_EXPIRED) {
this._syncState(await this._getData());
this.state.store.set("sessionId", "");
}
throw error;
}
}

async showSettings(): Promise<void> {
try {
this._syncState(await this._getData());
if (!this.privKey) throw new Error("Please login first.");

const params: Record<string, unknown> = {};
// defaults
params.redirectUrl = this.state.redirectUrl;

await this.request<void>({
method: OPENLOGIN_METHOD.SHOW_SETTINGS,
params: [params],
startUrl: this.state.startUrl,
popupUrl: this.state.popupUrl,
allowedInteractions: [ALLOWED_INTERACTIONS.POPUP, ALLOWED_INTERACTIONS.REDIRECT],
});
} catch (error) {
if (error?.message === SESSION_EXPIRED) {
this._syncState(await this._getData());
this.state.store.set("sessionId", "");
}
throw error;
}
}

async logout(logoutParams: Partial<BaseLogoutParams> & Partial<BaseRedirectParams> = {}): Promise<void> {
const params: Record<string, unknown> = {};
// defaults
Expand All @@ -235,6 +291,7 @@ class OpenLogin {
});

this.state.privKey = "";
this.state.store.set("sessionId", "");
return res;
}

Expand Down Expand Up @@ -278,6 +335,7 @@ class OpenLogin {
if (!session._sessionId) {
const sessionId = randomId();
session._sessionId = sessionId as string;
session._isNewSession = true;
this.state.store.set("sessionId", sessionId);
}

Expand Down Expand Up @@ -496,6 +554,7 @@ class OpenLogin {
typeOfLogin: (storeData.typeOfLogin as LOGIN_PROVIDER_TYPE | CUSTOM_LOGIN_PROVIDER_TYPE) || "",
dappShare: (storeData.dappShare as string) || "",
idToken: (storeData.idToken as string) || "",
isMfaEnabled: (storeData.isMfaEnabled as boolean) || false,
oAuthIdToken: (storeData.oAuthIdToken as string) || "",
oAuthAccessToken: (storeData.oAuthAccessToken as string) || "",
};
Expand Down
4 changes: 4 additions & 0 deletions packages/openlogin/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ export const UX_MODE = {
export const OPENLOGIN_METHOD = {
LOGIN: "openlogin_login",
LOGOUT: "openlogin_logout",
ENABLE_MFA: "openlogin_enable_mfa",
SHOW_SETTINGS: "openlogin_show_settings",
CHECK_3PC_SUPPORT: "openlogin_check_3PC_support",
SET_PID_DATA: "openlogin_set_pid_data",
GET_DATA: "openlogin_get_data",
Expand Down Expand Up @@ -59,3 +61,5 @@ export const MFA_LEVELS = {
MANDATORY: "mandatory",
NONE: "none",
} as const;

export const SESSION_EXPIRED = "SESSION_EXPIRED";
6 changes: 6 additions & 0 deletions packages/openlogin/src/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -309,4 +309,10 @@ export type OpenloginUserInfo = {
* custom verifiers.
*/
oAuthAccessToken?: string;

/**
* If `true` means that mfa of the account is enabled.
*
*/
isMfaEnabled: boolean;
};
7 changes: 7 additions & 0 deletions packages/openlogin/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -205,3 +205,10 @@ export function getPopupFeatures(): string {
const features = `titlebar=0,toolbar=0,status=0,location=0,menubar=0,height=${h / systemZoom},width=${w / systemZoom},top=${top},left=${left}`;
return features;
}

export const isNullishValue = (val: unknown): boolean => {
if (val === "") return true;
if (val === null) return true;
if (val === undefined) return true;
return false;
};