From 20763afed7e0583f78d78b0c273384500fc7578c Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Thu, 6 Nov 2025 20:57:17 +0800 Subject: [PATCH 1/7] fix: checkIfFactorKeyValid, check in factorEncs --- src/mpcCoreKit.ts | 6 ++++++ tests/factors.spec.ts | 31 +++++++++++++++++++++++++++---- tests/gating.spec.ts | 3 ++- tests/sessionTime.spec.ts | 9 ++++++++- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 3cae7ff..f573c03 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1283,6 +1283,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit { private async checkIfFactorKeyValid(factorKey: BN): Promise { this.checkReady(); + const factorKeyPrivate = factorKeyCurve.keyFromPrivate(factorKey.toBuffer()); + const factorPubX = factorKeyPrivate.getPublic().getX().toString("hex").padStart(64, "0"); + const existingFactorEnc = this.tkey.metadata.factorEncs[this.tkey.tssTag][factorPubX]; + if (!existingFactorEnc) { + return false; + } const factorKeyMetadata = await this.tKey?.readMetadata(factorKey); if (!factorKeyMetadata || factorKeyMetadata.message === "KEY_NOT_FOUND" || factorKeyMetadata.message === "SHARE_DELETED") { return false; diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index 539e892..659802b 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -1,7 +1,7 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint, KeyType, Point, secp256k1 } from "@tkey/common-types"; +import { EllipticPoint, getPubKeyPoint, 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"; @@ -158,7 +158,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = }); // enable mfa - + let browserFactor: string; await t.test("enable MFA", async function () { const instance = await newInstance(); assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); @@ -179,7 +179,7 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = const instance2 = await newInstance(); assert.strictEqual(instance2.status, COREKIT_STATUS.REQUIRED_SHARE); - const browserFactor = await instance2.getDeviceFactor(); + browserFactor = await instance2.getDeviceFactor(); const factorBN = new BN(recoverFactor, "hex") @@ -210,9 +210,32 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = } else { await signSecp256k1Data({ coreKitInstance: instance3, msg: "hello world" }); } - }); + // replace factor + await t.test("replace factor", async function () { + const instance = await newInstance(); + + const deviceFactorKeyBN = new BN(browserFactor, "hex") + await instance.inputFactorKey(deviceFactorKeyBN); + assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); + + const newFactorkey = await instance.createFactor({ shareType: TssShareType.DEVICE }); + await instance.inputFactorKey(new BN(newFactorkey, "hex")); + + assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); + + + const deviceFactorPub = getPubKeyPoint(deviceFactorKeyBN); + await instance.deleteFactor(deviceFactorPub, browserFactor); + + try { + await instance.inputFactorKey(deviceFactorKeyBN); + throw Error("should not be able to deleted input factor"); + } catch (e) { + assert(e instanceof Error); + } + }); }); }; diff --git a/tests/gating.spec.ts b/tests/gating.spec.ts index 586386f..a2007ff 100644 --- a/tests/gating.spec.ts +++ b/tests/gating.spec.ts @@ -23,7 +23,8 @@ const variable: TestVariable[] = [ description: "should not be gated when on devnet", web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", - email: defaultTestEmail, + // tkey tests seems use this verifierid, metadata retrun only have tkey that do not support tss + email: defaultTestEmail + '1', web3ClientID: "torus-key-test", expectedErrorThrown: false, }, diff --git a/tests/sessionTime.spec.ts b/tests/sessionTime.spec.ts index b5a4b2c..6a84f7f 100644 --- a/tests/sessionTime.spec.ts +++ b/tests/sessionTime.spec.ts @@ -23,7 +23,14 @@ const defaultTestEmail = "testEmail1"; const isBasePlan = (id: string) => id === "BCriFlI9ihm81N-bc7x6N-xbqwBLuxfRDMmSH87spKH27QTNOPj1W9s2K3-mp9NzXuaRiqxvAGHyuGlXG5wLD1g"; // BasePlan up to 1 day only const variable: TestVariable[] = [ - { web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", email: defaultTestEmail, web3ClientID: "torus-key-test", sessionTime: 3600 }, + { + web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, + uxMode: "nodejs", + // tkey tests seems use this verifierid, metadata retrun only have tkey that do not support tss + email: defaultTestEmail + "1", + web3ClientID: "torus-key-test", + sessionTime: 3600 + }, { web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET, uxMode: "nodejs", From ff1ecbac1a584ce2b46ff8ad1d4cda606e9b4a9e Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:14:04 +0800 Subject: [PATCH 2/7] fix: Optional Chaining for FactorEncs Access --- src/mpcCoreKit.ts | 2 +- tests/gating.spec.ts | 3 +-- tests/sessionTime.spec.ts | 9 +-------- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index f573c03..0120a58 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1285,7 +1285,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { this.checkReady(); const factorKeyPrivate = factorKeyCurve.keyFromPrivate(factorKey.toBuffer()); const factorPubX = factorKeyPrivate.getPublic().getX().toString("hex").padStart(64, "0"); - const existingFactorEnc = this.tkey.metadata.factorEncs[this.tkey.tssTag][factorPubX]; + const existingFactorEnc = this.tkey.metadata.factorEncs?.[this.tkey.tssTag]?.[factorPubX]; if (!existingFactorEnc) { return false; } diff --git a/tests/gating.spec.ts b/tests/gating.spec.ts index a2007ff..586386f 100644 --- a/tests/gating.spec.ts +++ b/tests/gating.spec.ts @@ -23,8 +23,7 @@ const variable: TestVariable[] = [ description: "should not be gated when on devnet", web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", - // tkey tests seems use this verifierid, metadata retrun only have tkey that do not support tss - email: defaultTestEmail + '1', + email: defaultTestEmail, web3ClientID: "torus-key-test", expectedErrorThrown: false, }, diff --git a/tests/sessionTime.spec.ts b/tests/sessionTime.spec.ts index 6a84f7f..b5a4b2c 100644 --- a/tests/sessionTime.spec.ts +++ b/tests/sessionTime.spec.ts @@ -23,14 +23,7 @@ const defaultTestEmail = "testEmail1"; const isBasePlan = (id: string) => id === "BCriFlI9ihm81N-bc7x6N-xbqwBLuxfRDMmSH87spKH27QTNOPj1W9s2K3-mp9NzXuaRiqxvAGHyuGlXG5wLD1g"; // BasePlan up to 1 day only const variable: TestVariable[] = [ - { - web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, - uxMode: "nodejs", - // tkey tests seems use this verifierid, metadata retrun only have tkey that do not support tss - email: defaultTestEmail + "1", - web3ClientID: "torus-key-test", - sessionTime: 3600 - }, + { web3AuthNetwork: WEB3AUTH_NETWORK.DEVNET, uxMode: "nodejs", email: defaultTestEmail, web3ClientID: "torus-key-test", sessionTime: 3600 }, { web3AuthNetwork: WEB3AUTH_NETWORK.MAINNET, uxMode: "nodejs", From 7b0ef62948d314fb83543a51fd9507f837d85e00 Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Fri, 7 Nov 2025 16:42:10 +0800 Subject: [PATCH 3/7] fix: add new user indication --- src/mpcCoreKit.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 0120a58..9b52e8d 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -86,6 +86,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public torusSp: TSSTorusServiceProvider | null = null; + // new user indication + // only true during new user sign up, after reinit or rehydration, the flag will be always false + public newUser: boolean = false; + private options: Web3AuthOptionsWithDefaults; private storageLayer: TorusStorageLayer | null = null; @@ -1093,6 +1097,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { // mutation function private async handleNewUser(importTssKey?: string, isSfaKey?: boolean) { + this.newUser = true; await this.atomicSync(async () => { // Generate or use hash factor and initialize tkey with it. let factorKey: BN; From 4192a7ef6ced63d676a4a3a949aa9aaa9a52b10d Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:12:29 +0800 Subject: [PATCH 4/7] fix: other condition set new user to false --- src/mpcCoreKit.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 9b52e8d..0fcc2a9 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1151,6 +1151,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { } private async handleExistingUser() { + this.newUser = false await this.tKey.initialize({ neverInitializeNewKey: true }); if (this.options.disableHashedFactorKey) { return; @@ -1414,6 +1415,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { this.tkey = null; this.torusSp = null; this.storageLayer = null; + this.newUser = false; this.state = { accountIndex: 0 }; } From 8fc4198c3cb184f311055224ecddcefa9bd2b726 Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Fri, 5 Dec 2025 13:36:18 +0800 Subject: [PATCH 5/7] fix: lint --- src/mpcCoreKit.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 0fcc2a9..01774c2 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1151,7 +1151,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { } private async handleExistingUser() { - this.newUser = false + this.newUser = false; await this.tKey.initialize({ neverInitializeNewKey: true }); if (this.options.disableHashedFactorKey) { return; From 50d2f1514ea7b4943b270c1826587625ef403589 Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Thu, 13 Aug 2026 14:40:35 +0800 Subject: [PATCH 6/7] chore: update package-lock.json to use npm registry for Babel dependencies --- tests/factors.spec.ts | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index 659802b..aac3f4e 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -1,8 +1,8 @@ import assert from "node:assert"; import test from "node:test"; -import { EllipticPoint, getPubKeyPoint, KeyType, Point, secp256k1 } from "@tkey/common-types"; -import { factorKeyCurve } from "@tkey/tss"; +import { EllipticPoint, KeyType, Point, secp256k1 } from "@tkey/common-types"; +import { factorKeyCurve, getPubKeyPoint } 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"; @@ -195,12 +195,9 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = - try { + await assert.rejects(async () => { await instance3.inputFactorKey(factorBN.subn(1)); - throw Error("should not be able to input factor"); - } catch (e) { - assert(e instanceof Error); - } + }); await instance3.inputFactorKey(new BN(browserFactor, "hex")); assert.strictEqual(instance3.status, COREKIT_STATUS.LOGGED_IN); @@ -226,15 +223,12 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); - const deviceFactorPub = getPubKeyPoint(deviceFactorKeyBN); + const deviceFactorPub = getPubKeyPoint(deviceFactorKeyBN, factorKeyCurve); await instance.deleteFactor(deviceFactorPub, browserFactor); - try { + await assert.rejects(async () => { await instance.inputFactorKey(deviceFactorKeyBN); - throw Error("should not be able to deleted input factor"); - } catch (e) { - assert(e instanceof Error); - } + }); }); }); }; From e72a70a09924728d07c2495becb81855dc185e61 Mon Sep 17 00:00:00 2001 From: ieow <4881057+ieow@users.noreply.github.com> Date: Thu, 13 Aug 2026 15:13:17 +0800 Subject: [PATCH 7/7] feat: implement isNewUser method and refactor new user indication handling --- src/interfaces.ts | 5 +++++ src/mpcCoreKit.ts | 11 +++++++---- tests/factors.spec.ts | 18 ++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/interfaces.ts b/src/interfaces.ts index fec6ca3..8b816ee 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -199,6 +199,11 @@ export interface ICoreKit { **/ status: COREKIT_STATUS; + /** + * True only during new user sign up. After reinit or rehydration this is always false. + */ + isNewUser(): boolean; + /** * The current sdk state. */ diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 01774c2..164c091 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -86,10 +86,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public torusSp: TSSTorusServiceProvider | null = null; - // new user indication - // only true during new user sign up, after reinit or rehydration, the flag will be always false - public newUser: boolean = false; - private options: Web3AuthOptionsWithDefaults; private storageLayer: TorusStorageLayer | null = null; @@ -106,6 +102,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit { private ready = false; + // only true during new user sign up; after reinit or rehydration this is always false + private newUser: boolean = false; + private _tssLib: TssLibType; private wasmLib: DKLSWasmLib | FrostWasmLib; @@ -197,6 +196,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit { return this._keyType !== KeyType.ed25519; } + public isNewUser(): boolean { + return this.newUser; + } + private get verifier(): string { if (this.state.userInfo?.aggregateVerifier) { return this.state.userInfo.aggregateVerifier; diff --git a/tests/factors.spec.ts b/tests/factors.spec.ts index aac3f4e..c2d941e 100644 --- a/tests/factors.spec.ts +++ b/tests/factors.spec.ts @@ -83,6 +83,20 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = await test(`#Factor manipulation - manualSync ${testVariable.manualSync} `, async function (t) { await beforeTest(); + await t.test("hashed factor auto login", async function () { + const instance = await newInstance(); + assert.strictEqual(instance.status, COREKIT_STATUS.LOGGED_IN); + assert.strictEqual(instance.getTssFactorPub().length, 1); + if (testVariable.manualSync) { + await instance.commitChanges(); + } + await instance.logout(); + + const instance2 = await newInstance(); + assert.strictEqual(instance2.status, COREKIT_STATUS.LOGGED_IN); + assert.strictEqual(instance2.getTssFactorPub().length, 1); + }); + await t.test("should be able to create factor", async function () { const coreKitInstance = await newInstance(); assert.equal(coreKitInstance.status, COREKIT_STATUS.LOGGED_IN); @@ -202,6 +216,10 @@ export const FactorManipulationTest = async (testVariable: FactorTestVariable) = await instance3.inputFactorKey(new BN(browserFactor, "hex")); assert.strictEqual(instance3.status, COREKIT_STATUS.LOGGED_IN); + await assert.rejects(async () => { + await instance3.enableMFA({}); + }, /MFA is already enabled/); + if ( tssLib && tssLib.keyType === KeyType.ed25519) { await signEd25519Data({ coreKitInstance: instance3, msg: "hello world" }); } else {