Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 28 additions & 1 deletion src/mpcCoreKit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,11 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
if (this.isNodejsOrRN(this.options.uxMode)) {
throw CoreKitError.oauthLoginUnsupported(`Oauth login is NOT supported in ${this.options.uxMode} mode.`);
}

if (this.state.factorKey) {
throw CoreKitError.oauthLoginUnsupported("Instance is alreay login or rehydrated");
}

const { importTssKey, registerExistingSFAKey } = params;
const tkeyServiceProvider = this.torusSp;

Expand Down Expand Up @@ -892,6 +897,19 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
// manual call syncLocalMetadataTransitions() required to sync local transitions to storage
await this.tKey._syncShareMetadata();
await this.tKey.syncLocalMetadataTransitions();

if (this.sessionManager && this.sessionId) {
const payload: SessionData = {
postBoxKey: this.state.postBoxKey,
postboxKeyNodeIndexes: this.state.postboxKeyNodeIndexes || [],
factorKey: this.state.factorKey?.toString("hex"),
tssShareIndex: this.state.tssShareIndex as number,
tssPubKey: this.state.tssPubKey?.toString("hex"),
signatures: this.signatures,
userInfo: this.state.userInfo,
};
this.sessionManager.updateSession(payload);
}
} catch (error: unknown) {
log.error("sync metadata error", error);
throw error;
Expand Down Expand Up @@ -1107,6 +1125,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
shareDescription: FactorKeyTypeShareDescription.Other,
updateMetadata: false,
});
await this.setDeviceFactor(factorKey);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this means the factor key was previously not persisted here, which is kind of catastrophic. We should have a test that asserts this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tests added

} else {
await this.addFactorDescription({
factorKey,
Expand Down Expand Up @@ -1199,8 +1218,16 @@ export class Web3AuthMPCCoreKit implements ICoreKit {
signatures: result.signatures,
userInfo: result.userInfo,
});

// update device factor if not present upon rehydration
if (this.options.disableHashedFactorKey) {
const deviceFactorKey = await this.getDeviceFactor();
if (!deviceFactorKey && this.state.factorKey && this.state.tssShareIndex === TssShareType.DEVICE) {
await this.setDeviceFactor(this.state.factorKey);
}
}
} catch (err) {
log.warn("failed to authorize session", err);
log.warn("failed to authorize session please use new", err);
}
}

Expand Down
61 changes: 51 additions & 10 deletions tests/ed25519.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,27 @@ import { UX_MODE_TYPE } from "@toruslabs/customauth";
import { tssLib } from "@toruslabs/tss-frost-lib";
import BN from "bn.js";

import { AsyncStorage, COREKIT_STATUS, ed25519, MemoryStorage, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src";
import { AsyncStorage, COREKIT_STATUS, ed25519, MemoryStorage, TssShareType, WEB3AUTH_NETWORK, WEB3AUTH_NETWORK_TYPE, Web3AuthMPCCoreKit } from "../src";
import { bufferToElliptic, criticalResetAccount, mockLogin, mockLogin2 } from "./setup";

type TestVariable = {
web3AuthNetwork: WEB3AUTH_NETWORK_TYPE;
uxMode: UX_MODE_TYPE | "nodejs";
manualSync?: boolean;
email: string;
importedEmail: string
};

const defaultTestEmail = "testEmailForLoginEd25519";
const defaultTestEmail = "testEmailForLoginEd25519-01";
const importedEmail = "testEmailImportEd25519-01"

const variable: TestVariable[] = [
{ web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", email: defaultTestEmail },
{ web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", email: defaultTestEmail, importedEmail },
// { web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET, uxMode: UX_MODE.REDIRECT, email: defaultTestEmail },

{ web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", manualSync: true, email: defaultTestEmail },
{ web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", manualSync: true, email: defaultTestEmail , importedEmail },
// { web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET, uxMode: UX_MODE.REDIRECT, manualSync: true, email: defaultTestEmail },

];

const checkLogin = async (coreKitInstance: Web3AuthMPCCoreKit, accountIndex = 0) => {
Expand All @@ -39,7 +43,7 @@ const storageInstance = new MemoryStorage();

variable.forEach((testVariable) => {
const { web3AuthNetwork, uxMode, manualSync, email } = testVariable;
const newCoreKitInstance = () =>
const newCoreKitInstance = ( params: {disableSessionManager : boolean } = {disableSessionManager: true}) =>
new Web3AuthMPCCoreKit({
web3AuthClientId: "torus-key-test",
web3AuthNetwork,
Expand All @@ -48,11 +52,12 @@ variable.forEach((testVariable) => {
tssLib,
storage: storageInstance,
manualSync,
disableSessionManager: params.disableSessionManager
});

async function resetAccount() {
async function resetAccount( resetEmail: string) {
const resetInstance = newCoreKitInstance();
const { idToken, parsedToken } = await mockLogin(email);
const { idToken, parsedToken } = await mockLogin(resetEmail);
await resetInstance.init({ handleRedirectResult: false, rehydrate: false });
await resetInstance.loginWithJWT({
verifier: "torus-test-health",
Expand All @@ -69,9 +74,11 @@ variable.forEach((testVariable) => {
let checkTssShare: BN;

test(`#Login Test with JWT + logout: ${testNameSuffix}`, async (t) => {
await resetAccount();
await resetAccount(email);
await resetAccount(importedEmail);

await t.test("#Login", async function () {
const coreKitInstance = newCoreKitInstance();
const coreKitInstance = newCoreKitInstance({disableSessionManager: false});

// mocklogin
const { idToken, parsedToken } = await mockLogin(email);
Expand All @@ -98,7 +105,7 @@ variable.forEach((testVariable) => {
});

await t.test("#relogin ", async function () {
const coreKitInstance = newCoreKitInstance();
const coreKitInstance = newCoreKitInstance({ disableSessionManager: false });
// rehydrate
await coreKitInstance.init({ handleRedirectResult: false });
await checkLogin(coreKitInstance);
Expand Down Expand Up @@ -147,5 +154,39 @@ variable.forEach((testVariable) => {
const valid = ed25519().verify(msgBuffer, signature, coreKitInstance.getPubKeyEd25519());
assert(valid);
});

await t.test("#able to export import", async function () {
const coreKitInstance = newCoreKitInstance();
await coreKitInstance.init({ handleRedirectResult: false, rehydrate: false });
const localToken = await mockLogin2(email);
await coreKitInstance.loginWithJWT({
verifier: "torus-test-health",
verifierId: email,
idToken: localToken.idToken,
});

await coreKitInstance.enableMFA({});
if (manualSync) {
await coreKitInstance.commitChanges();
}
const exportedSeed = await coreKitInstance._UNSAFE_exportTssEd25519Seed();

const coreKitInstance2 = newCoreKitInstance();
await coreKitInstance2.init({ handleRedirectResult: false, rehydrate: false });
const localToken2 = await mockLogin2(importedEmail);
await coreKitInstance2.loginWithJWT({
verifier: "torus-test-health",
verifierId: importedEmail,
idToken: localToken2.idToken,
importTssKey: exportedSeed.toString("hex"),
});

const exportedSeed2 = await coreKitInstance2._UNSAFE_exportTssEd25519Seed();

assert(exportedSeed.toString("hex") === (exportedSeed2.toString("hex")));
});



});
});
44 changes: 38 additions & 6 deletions tests/factors.spec.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import assert from "node:assert";
import test from "node:test";

import { EllipticPoint, Point } from "@tkey/common-types";
import { EllipticPoint, KeyType, Point, secp256k1 } from "@tkey/common-types";
import { factorKeyCurve } from "@tkey/tss";
import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib";
import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib";
import BN from "bn.js";

import { COREKIT_STATUS, IAsyncStorage, IStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "../src";
import { AsyncStorage, COREKIT_STATUS, ed25519, IAsyncStorage, IStorage, MemoryStorage, sigToRSV, TssLibType, TssShareType, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "../src";
import { AsyncMemoryStorage, bufferToElliptic, criticalResetAccount, mockLogin } from "./setup";
import { keccak256 } from "@toruslabs/metadata-helpers";

type FactorTestVariable = {
manualSync?: boolean;
Expand All @@ -28,6 +29,26 @@ function getPubKeys(kit: Web3AuthMPCCoreKit, indices: number[]): EllipticPoint[]
return pubKeys;
}

async function signSecp256k1Data( params : { coreKitInstance: Web3AuthMPCCoreKit, msg: string, }) {
const {coreKitInstance, msg } = params
const msgBuffer1 = Buffer.from(msg);
const msgHash = keccak256(msgBuffer1);

const signature = sigToRSV(await coreKitInstance.sign(msgHash, true));

const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint;
const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey());
assert(pubkey.eq(publicKeyPoint));
}

async function signEd25519Data(params: { coreKitInstance: Web3AuthMPCCoreKit, msg: string }) {
const { coreKitInstance, msg } = params;
const msgBuffer = Buffer.from(msg)
const signature = ed25519().makeSignature((await coreKitInstance.sign(msgBuffer)).toString("hex"));
const valid = ed25519().verify(msgBuffer, signature, coreKitInstance.getPubKeyEd25519());
assert(valid);
}

export const FactorManipulationTest = async (testVariable: FactorTestVariable) => {
const { email, tssLib } = testVariable;
const newInstance = async () => {
Expand All @@ -39,6 +60,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) =
tssLib: tssLib || tssLibDKLS,
storage: testVariable.storage,
manualSync: testVariable.manualSync,
disableSessionManager: true
});

const { idToken, parsedToken } = await mockLogin(email);
Expand All @@ -55,6 +77,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) =
const resetInstance = await newInstance();
await criticalResetAccount(resetInstance);
await resetInstance.logout();
await new AsyncStorage(resetInstance._storageKey, testVariable.storage).resetStore();
}

await test(`#Factor manipulation - manualSync ${testVariable.manualSync} `, async function (t) {
Expand Down Expand Up @@ -163,6 +186,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) =
// login with mfa factor
await instance2.inputFactorKey(new BN(recoverFactor, "hex"));
assert.strictEqual(instance2.status, COREKIT_STATUS.LOGGED_IN);

await instance2.logout();

// new instance
Expand All @@ -180,16 +204,24 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) =

await instance3.inputFactorKey(new BN(browserFactor, "hex"));
assert.strictEqual(instance3.status, COREKIT_STATUS.LOGGED_IN);

if ( tssLib && tssLib.keyType === KeyType.ed25519) {
await signEd25519Data({ coreKitInstance: instance3, msg: "hello world" });
} else {
await signSecp256k1Data({ coreKitInstance: instance3, msg: "hello world" });
}

});

});
};

const variable: FactorTestVariable[] = [
{ manualSync: true, storage: new MemoryStorage(), email: "testmail1012" },
{ manualSync: false, storage: new MemoryStorage(), email: "testmail1013" },
{ manualSync: true, storage: new MemoryStorage(), email: "testmail1012-1" },
{ manualSync: false, storage: new MemoryStorage(), email: "testmail1013-1" },

{ manualSync: true, storage: new AsyncMemoryStorage(), email: "testmail1014" },
{ manualSync: false, storage: new AsyncMemoryStorage(), email: "testmail1015" },
{ manualSync: true, storage: new AsyncMemoryStorage(), email: "testmail1014-1" },
{ manualSync: false, storage: new AsyncMemoryStorage(), email: "testmail1015-1" },

{ manualSync: true, storage: new MemoryStorage(), email: "testmail1012ed25519", tssLib: tssLibFROST },
];
Expand Down
75 changes: 60 additions & 15 deletions tests/importRecovery.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,63 @@ import test from "node:test";
import { tssLib as tssLibDKLS } from "@toruslabs/tss-dkls-lib";
import { tssLib as tssLibFROST } from "@toruslabs/tss-frost-lib";

import { AsyncStorage, MemoryStorage, TssLibType, TssShareType, WEB3AUTH_NETWORK } from "../src";
import { bufferToElliptic, criticalResetAccount, newCoreKitLogInInstance } from "./setup";
import { MemoryStorage, sigToRSV, TssLibType, TssShareType, WEB3AUTH_NETWORK, Web3AuthMPCCoreKit } from "../src";
import { bufferToElliptic, criticalResetAccount, mockLogin } from "./setup";
import { EllipticPoint, KeyType, secp256k1 } from "@tkey/common-types";
import { keccak256 } from "@toruslabs/metadata-helpers";

type ImportKeyTestVariable = {
manualSync?: boolean;
email: string;
importKeyEmail: string;
tssLib: TssLibType;
};
async function signSecp256k1Data( params : { coreKitInstance: Web3AuthMPCCoreKit, msg: string, }) {
const {coreKitInstance, msg } = params
const msgBuffer1 = Buffer.from(msg);
const msgHash = keccak256(msgBuffer1);

const signature = sigToRSV(await coreKitInstance.sign(msgHash, true));

const pubkey = secp256k1.recoverPubKey(msgHash, signature, signature.v) as EllipticPoint;
const publicKeyPoint = bufferToElliptic(coreKitInstance.getPubKey());
assert(pubkey.eq(publicKeyPoint));
}
const storageInstance = new MemoryStorage();
export const ImportTest = async (testVariable: ImportKeyTestVariable) => {
async function newCoreKitInstance(email: string, importTssKey?: string) {
return newCoreKitLogInInstance({
network: WEB3AUTH_NETWORK.DEVNET,
manualSync: testVariable.manualSync,
email: email,
storageInstance,
tssLib: testVariable.tssLib,
importTssKey,
});
const instance = new Web3AuthMPCCoreKit({
web3AuthClientId: "torus-key-test",
web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET,
baseUrl: "http://localhost:3000",
uxMode: "nodejs",
tssLib: testVariable.tssLib,
storage: storageInstance,
manualSync: testVariable.manualSync,
disableSessionManager: true
});

const { idToken, parsedToken } = await mockLogin(email);
await instance.init({ handleRedirectResult: false, rehydrate: false });
await instance.loginWithJWT({
verifier: "torus-test-health",
verifierId: parsedToken.email,
idToken,
importTssKey
});
return instance;

}

async function resetAccount(email: string) {
const kit = await newCoreKitInstance(email);
console.log('tss pub key', kit.state.tssPubKey)
await criticalResetAccount(kit);
if (testVariable.manualSync) {
await kit.commitChanges();
}
await kit.logout();
await new AsyncStorage(kit._storageKey, storageInstance).resetStore();
// await new AsyncStorage(kit._storageKey, storageInstance).resetStore();
}

test(`import recover tss key : ${testVariable.manualSync}`, async function (t) {
Expand All @@ -50,6 +79,9 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => {
shareType: TssShareType.DEVICE,
});

if (testVariable.tssLib.keyType === KeyType.secp256k1) {
await signSecp256k1Data({ coreKitInstance, msg: "hello world" });
}
const factorKeyRecovery = await coreKitInstance.createFactor({
shareType: TssShareType.RECOVERY,
});
Expand All @@ -62,8 +94,21 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => {
const exportedTssKey1 = await coreKitInstance._UNSAFE_exportTssKey();
await coreKitInstance.logout();

const instance = new Web3AuthMPCCoreKit({
web3AuthClientId: "torus-key-test",
web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET,
baseUrl: "http://localhost:3000",
uxMode: "nodejs",
tssLib: testVariable.tssLib,
storage: storageInstance,
manualSync: testVariable.manualSync,
disableSessionManager: true
});

await instance.init({rehydrate: false, handleRedirectResult: false})

// Recover key from any two factors.
const recoveredTssKey = await coreKitInstance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery]);
const recoveredTssKey = await instance._UNSAFE_recoverTssKey([factorKeyDevice, factorKeyRecovery]);
assert.strictEqual(recoveredTssKey, exportedTssKey1);

// Initialize new instance and import existing key.
Expand Down Expand Up @@ -105,9 +150,9 @@ export const ImportTest = async (testVariable: ImportKeyTestVariable) => {
};

const variable: ImportKeyTestVariable[] = [
{ manualSync: false, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS },
{ manualSync: true, email: "emailexport", importKeyEmail: "emailimport", tssLib: tssLibDKLS },
{ manualSync: false, email: "emailexport_ed25519", importKeyEmail: "emailimport_ed25519", tssLib: tssLibFROST },
{ manualSync: false, email: "emailexport-01", importKeyEmail: "emailimport-001", tssLib: tssLibDKLS },
{ manualSync: true, email: "emailexport-01", importKeyEmail: "emailimport-001", tssLib: tssLibDKLS },
// { manualSync: false, email: "emailexport_ed25519", importKeyEmail: "emailimport_ed25519", tssLib: tssLibFROST },
];

variable.forEach(async (testVariable) => {
Expand Down
Loading