From 86435544040ecf1650f9c5866f6dddc50178f51c Mon Sep 17 00:00:00 2001 From: ieow Date: Mon, 30 Oct 2023 16:01:47 +0800 Subject: [PATCH 1/7] feat: remote sign refresh --- package.json | 3 +- src/mpcCoreKit.ts | 58 ++++++++++++++++++- src/utils.ts | 143 +++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 192 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 54e0b80a..2ea2a7e1 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@toruslabs/eccrypto": "4.0.0", "@toruslabs/fetch-node-details": "^13.0.1", "@toruslabs/fnd-base": "^13.0.1", + "@toruslabs/http-helpers": "^5.0.0", "@toruslabs/metadata-helpers": "^5.x", "@toruslabs/openlogin-session-manager": "^3.0.0", "@toruslabs/torus.js": "^11.0.6", @@ -64,11 +65,11 @@ "@toruslabs/config": "^2.0.2", "@toruslabs/eslint-config-typescript": "^3.0.1", "@toruslabs/torus-scripts": "^5.0.5", + "@toruslabs/tss-lib-node": "^1.1.3", "@types/chai": "^4.3.6", "@types/elliptic": "^6.4.14", "@types/node": "^20.6.3", "@typescript-eslint/eslint-plugin": "^6.7.0", - "@toruslabs/tss-lib-node" : "^1.1.3", "chai": "^4.3.8", "cross-env": "^7.0.3", "dotenv": "^16.3.1", diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 4844e4f4..33047c6e 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -7,6 +7,7 @@ import { TorusStorageLayer } from "@tkey-mpc/storage-layer-torus"; import { AGGREGATE_VERIFIER, TORUS_METHOD, TorusAggregateLoginResponse, TorusLoginResponse, UX_MODE } from "@toruslabs/customauth"; import { generatePrivate } from "@toruslabs/eccrypto"; import { NodeDetailManager } from "@toruslabs/fetch-node-details"; +import { post } from "@toruslabs/http-helpers"; import { keccak256 } from "@toruslabs/metadata-helpers"; import { OpenloginSessionManager } from "@toruslabs/openlogin-session-manager"; import TorusUtils, { TorusKey } from "@toruslabs/torus.js"; @@ -87,12 +88,16 @@ export class Web3AuthMPCCoreKit implements ICoreKit { private ready = false; - constructor(options: Web3AuthOptions) { + private remoteClientUrl: string | undefined; + + constructor(options: Web3AuthOptions, remoteClientUrl?: string) { // log.info("======================================================"); // log.info(`WEB3AUTH SDK : ${name}:${version}`); // log.info("======================================================"); + this.remoteClientUrl = remoteClientUrl.at(-1) === "/" ? remoteClientUrl.slice(0, -1) : remoteClientUrl; + if (!options.chainConfig) options.chainConfig = DEFAULT_CHAIN_CONFIG; if (options.chainConfig.chainNamespace !== CHAIN_NAMESPACES.EIP155) { throw new Error("You must specify a eip155 chain config."); @@ -657,7 +662,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { throw new Error("Cannot delete current active factor"); } - await deleteFactorAndRefresh(this.tKey, factorPub, this.state.factorKey, this.signatures); + await deleteFactorAndRefresh(this.tKey, factorPub, this.state.factorKey, this.signatures, this.remoteClientUrl); const factorPubHex = fpp.toBufferSEC1(true).toString("hex"); const allDesc = this.tKey.metadata.getShareDescription(); const keyDesc = allDesc[factorPubHex]; @@ -955,7 +960,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { if (!this.state.factorKey) throw new Error("factorKey not present"); // Generate new share. - await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures); + await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures, this.remoteClientUrl); // Update local share. const { tssIndex } = await this.tKey.getTSSShare(this.state.factorKey); @@ -1099,4 +1104,51 @@ export class Web3AuthMPCCoreKit implements ICoreKit { (this.tKey.serviceProvider as TorusServiceProvider).verifierName = state.userInfo.verifier; (this.tKey.serviceProvider as TorusServiceProvider).verifierId = state.userInfo.verifierId; } + + public async remoteSign(msgHash: Buffer, factorPub: string) { + // PreSetup + const { torusNodeTSSEndpoints } = await this.nodeDetailManager.getNodeDetails({ + verifier: "test-verifier", + verifierId: "test@example.com", + }); + + const tssCommits = this.tKey.getTSSCommits(); + + const tssNonce = this.getTssNonce() || 0; + + const vid = `${this.verifier}${DELIMITERS.Delimiter1}${this.verifierId}`; + const sessionId = `${vid}${DELIMITERS.Delimiter2}default${DELIMITERS.Delimiter3}${tssNonce}${DELIMITERS.Delimiter4}`; + + const parties = 4; + const clientIndex = parties - 1; + + const { nodeIndexes } = await (this.tKey.serviceProvider as TorusServiceProvider).getTSSPubKey( + this.tKey.tssTag, + this.tKey.metadata.tssNonces[this.tKey.tssTag] + ); + + const { endpoints, tssWSEndpoints, partyIndexes } = generateTSSEndpoints(torusNodeTSSEndpoints, parties, clientIndex, nodeIndexes); + + const factor = TkeyPoint.fromCompressedPub(factorPub); + const factorEnc = this.tKey.getFactorEncs(factor); + + const data = { + dataRequired: { + factorEnc, + sessionId, + tssNonce, + nodeIndexes, + tssCommits: tssCommits.map((commit) => commit.toJSON()), + signatures: this.signatures, + serverEndpoints: { endpoints, tssWSEndpoints, partyIndexes }, + }, + msgHash: msgHash.toString("hex"), + }; + + const result = await post(`${this.remoteClientUrl}/sign`, data); + // eslint-disable-next-line no-console + console.log(result); + + return result; + } } diff --git a/src/utils.ts b/src/utils.ts index 30a90d2d..a2ebfd9b 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,11 +1,14 @@ -import { getPubKeyPoint, Point, Point as TkeyPoint, randomSelection } from "@tkey-mpc/common-types"; +import { FactorEnc, getPubKeyPoint, Point as TkeyPoint, randomSelection } from "@tkey-mpc/common-types"; import ThresholdKey from "@tkey-mpc/core"; import { generatePrivate } from "@toruslabs/eccrypto"; +import { post } from "@toruslabs/http-helpers"; import { keccak256, StringifiedType } from "@toruslabs/torus.js"; +import type { PointHex } from "@toruslabs/tss-client/dist/types/types"; import BN from "bn.js"; import { SCALAR_LEN, VALID_SHARE_INDICES as VALID_TSS_INDICES } from "./constants"; import { UserInfo, Web3AuthState } from "./interfaces"; +import { Point } from "./point"; export const generateFactorKey = (): { private: BN; pub: TkeyPoint } => { const factorKey = new BN(generatePrivate()); @@ -72,9 +75,9 @@ export function parseToken(token: string) { * @param factorKeyForExistingTSSShare - Factor key for existing TSS share. * @param signatures - Signatures for authentication against RSS servers. */ -async function refreshTssShares( +export async function refreshTssShares( tKey: ThresholdKey, - factorPubs: Point[], + factorPubs: TkeyPoint[], tssIndices: number[], factorKeyForExistingTSSShare: BN, signatures: string[], @@ -99,12 +102,122 @@ async function refreshTssShares( }); } +export interface refreshRemoteTssType { + // from client + factorEnc: FactorEnc; + + factorPubs: TkeyPoint[]; + targetIndexes: number[]; + verifierNameVerifierId: string; + + tssTag: string; + tssCommits: TkeyPoint[]; + tssNonce: number; + newTSSServerPub: TkeyPoint; + // nodeIndexes : number[], + + serverOpts: { + serverEndpoints: string[]; + serverPubKeys: PointHex[]; + serverThreshold: number; + selectedServers: number[]; + authSignatures: string[]; + }; +} +export interface refreshRemoteTssReturnType { + tssTag: string; + tssNonce: number; + tssPolyCommits: TkeyPoint[]; + factorPubs: TkeyPoint[]; + factorEncs: { + [factorPubID: string]: FactorEnc; + }; +} +/** + * Refreshes TSS shares. Allows to change number of shares. New user shares are + * only produced for the target indices. + * @param tKey - Tkey instance to use. + * @param factorPubs - Factor pub keys after refresh. + * @param tssIndices - Target tss indices to generate new shares for. + * @param factorKeyForExistingTSSShare - Factor key for existing TSS share. + * @param signatures - Signatures for authentication against RSS servers. + */ +export async function remoteRefreshTssShares( + tKey: ThresholdKey, + factorPubs: TkeyPoint[], + tssIndices: number[], + // to replace with remoteFactorPub + factorKeyForExistingTSSShare: BN, + signatures: string[], + remoteClientUrl: string, + updateMetadata = false +) { + // const { tssShare, tssIndex } = await tKey.getTSSShare(factorKeyForExistingTSSShare); + + const rssNodeDetails = await tKey._getRssNodeDetails(); + const { serverEndpoints, serverPubKeys, serverThreshold } = rssNodeDetails; + let finalSelectedServers = randomSelection( + new Array(rssNodeDetails.serverEndpoints.length).fill(null).map((_, i) => i + 1), + Math.ceil(rssNodeDetails.serverEndpoints.length / 2) + ); + + const verifierNameVerifierId = tKey.serviceProvider.getVerifierNameVerifierId(); + + const tssCommits = tKey.metadata.tssPolyCommits[tKey.tssTag]; + const tssNonce: number = tKey.metadata.tssNonces[tKey.tssTag] || 0; + const { pubKey: newTSSServerPub, nodeIndexes } = await tKey.serviceProvider.getTSSPubKey(tKey.tssTag, tssNonce + 1); + // move to pre-refresh + if (nodeIndexes?.length > 0) { + finalSelectedServers = nodeIndexes.slice(0, Math.min(serverEndpoints.length, nodeIndexes.length)); + } + + // TODO: replace with factorPub Key + const factorKeyStr = factorKeyForExistingTSSShare.toString("hex"); + const point = Point.fromPrivateKey(factorKeyStr).toTkeyPoint(); + + const dataRequired = { + factorEnc: tKey.getFactorEncs(point), + factorPubs: factorPubs.map((pub) => pub.toJSON()), + targetIndexes: tssIndices, + verifierNameVerifierId, + tssTag: tKey.tssTag, + tssCommits: tssCommits.map((commit) => commit.toJSON()), + tssNonce, + newTSSServerPub: newTSSServerPub.toJSON(), + serverOpts: { + selectedServers: finalSelectedServers, + serverEndpoints, + serverPubKeys, + serverThreshold, + authSignatures: signatures, + }, + }; + + const result = (await post(`${remoteClientUrl}/refresh_tss`, { dataRequired })) as refreshRemoteTssReturnType; + + // eslint-disable-next-line no-console + console.log(result); + + tKey.metadata.addTSSData({ + tssTag: result.tssTag, + tssNonce: result.tssNonce, + tssPolyCommits: result.tssPolyCommits.map((commit) => TkeyPoint.fromJSON(commit)), + factorPubs: result.factorPubs.map((pub) => TkeyPoint.fromJSON(pub)), + factorEncs: result.factorEncs, + }); + + if (updateMetadata) { + await tKey._syncShareMetadata(); + } +} + export async function addFactorAndRefresh( tKey: ThresholdKey, - newFactorPub: Point, + newFactorPub: TkeyPoint, newFactorTSSIndex: number, factorKeyForExistingTSSShare: BN, - signatures: string[] + signatures: string[], + remoteRefreshUrl?: string ) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); @@ -122,10 +235,20 @@ export async function addFactorAndRefresh( const existingTSSIndexes = existingFactorPubs.map((fb) => tKey.getFactorEncs(fb).tssIndex); const updatedTSSIndexes = existingTSSIndexes.concat([newFactorTSSIndex]); - await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + if (!remoteRefreshUrl) { + await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + } else { + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures, remoteRefreshUrl); + } } -export async function deleteFactorAndRefresh(tKey: ThresholdKey, factorPubToDelete: Point, factorKeyForExistingTSSShare: BN, signatures: string[]) { +export async function deleteFactorAndRefresh( + tKey: ThresholdKey, + factorPubToDelete: TkeyPoint, + factorKeyForExistingTSSShare: BN, + signatures: string[], + remoteClientUrl?: string +) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); } @@ -143,7 +266,11 @@ export async function deleteFactorAndRefresh(tKey: ThresholdKey, factorPubToDele updatedFactorPubs.splice(factorIndex, 1); const updatedTSSIndexes = updatedFactorPubs.map((fb) => tKey.getFactorEncs(fb).tssIndex); - await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + if (!remoteClientUrl) { + await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + } else { + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures, remoteClientUrl); + } } export const getHashedPrivateKey = (postboxKey: string, clientId: string): BN => { From 5c86cb8dfa2ac9b19eaaab2370f9933e16f169f3 Mon Sep 17 00:00:00 2001 From: ieow Date: Wed, 1 Nov 2023 13:11:30 +0800 Subject: [PATCH 2/7] feat: integrate remoteSign to mpcCorekit --- package-lock.json | 798 +++++------------- package.json | 5 +- .../authenticator/authenticatorService.ts | 91 ++ src/helper/authenticator/smsService.ts | 97 +++ src/index.ts | 2 + src/interfaces.ts | 9 + src/mpcCoreKit.ts | 260 ++++-- src/utils.ts | 23 +- 8 files changed, 596 insertions(+), 689 deletions(-) create mode 100644 src/helper/authenticator/authenticatorService.ts create mode 100644 src/helper/authenticator/smsService.ts diff --git a/package-lock.json b/package-lock.json index 4288105d..8d1f764f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,7 +21,8 @@ "@toruslabs/eccrypto": "4.0.0", "@toruslabs/fetch-node-details": "^13.0.1", "@toruslabs/fnd-base": "^13.0.1", - "@toruslabs/metadata-helpers": "^4.x", + "@toruslabs/http-helpers": "^5.0.0", + "@toruslabs/metadata-helpers": "^5.x", "@toruslabs/openlogin-session-manager": "^3.0.0", "@toruslabs/torus.js": "^11.0.6", "@toruslabs/tss-client": "^1.7.1", @@ -31,14 +32,15 @@ "@web3auth/base-provider": "^7.0.1", "bn.js": "^5.2.1", "bowser": "^2.11.0", - "elliptic": "^6.5.4" + "elliptic": "^6.5.4", + "hi-base32": "^0.5.1" }, "devDependencies": { "@babel/register": "^7.22.15", "@toruslabs/config": "^2.0.2", "@toruslabs/eslint-config-typescript": "^3.0.1", "@toruslabs/torus-scripts": "^5.0.5", - "@toruslabs/tss-lib-node": "file:///Users/apollo/works/crypto/torus/clone26/tss-server/packages/tss-lib", + "@toruslabs/tss-lib-node": "^1.1.3", "@types/chai": "^4.3.6", "@types/elliptic": "^6.4.14", "@types/node": "^20.6.3", @@ -66,12 +68,6 @@ "@toruslabs/metadata-helpers": "^4.x" } }, - "../tss-server/packages/tss-lib": { - "name": "tss-lib", - "version": "1.1.0", - "dev": true, - "license": "BSD" - }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "dev": true, @@ -3397,27 +3393,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@tkey-mpc/core/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@tkey-mpc/security-questions": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/@tkey-mpc/security-questions/-/security-questions-9.0.2.tgz", @@ -3658,27 +3633,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@tkey-mpc/storage-layer-torus/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@tkey-mpc/storage-layer-torus/node_modules/ethereum-cryptography": { "version": "2.1.2", "license": "MIT", @@ -3714,6 +3668,28 @@ "@babel/runtime": "7.x" } }, + "node_modules/@toruslabs/base-controllers/node_modules/@toruslabs/http-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-3.4.0.tgz", + "integrity": "sha512-CoeJSL32mpp0gmYjxv48odu6pfjHk/rbJHDwCtYPcMHAl+qUQ/DTpVOOn9U0fGkD+fYZrQmZbRkXFgLhiT0ajQ==", + "dependencies": { + "lodash.merge": "^4.6.2", + "loglevel": "^1.8.1" + }, + "engines": { + "node": ">=14.17.0", + "npm": ">=6.x" + }, + "peerDependencies": { + "@babel/runtime": "^7.x", + "@sentry/types": "^7.x" + }, + "peerDependenciesMeta": { + "@sentry/types": { + "optional": true + } + } + }, "node_modules/@toruslabs/base-controllers/node_modules/@toruslabs/openlogin-jrpc": { "version": "3.2.0", "license": "ISC", @@ -3757,27 +3733,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/base-session-manager/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@toruslabs/broadcast-channel": { "version": "6.2.0", "license": "MIT", @@ -3839,6 +3794,28 @@ "elliptic": "^6.5.4" } }, + "node_modules/@toruslabs/broadcast-channel/node_modules/@toruslabs/http-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-3.4.0.tgz", + "integrity": "sha512-CoeJSL32mpp0gmYjxv48odu6pfjHk/rbJHDwCtYPcMHAl+qUQ/DTpVOOn9U0fGkD+fYZrQmZbRkXFgLhiT0ajQ==", + "dependencies": { + "lodash.merge": "^4.6.2", + "loglevel": "^1.8.1" + }, + "engines": { + "node": ">=14.17.0", + "npm": ">=6.x" + }, + "peerDependencies": { + "@babel/runtime": "^7.x", + "@sentry/types": "^7.x" + }, + "peerDependenciesMeta": { + "@sentry/types": { + "optional": true + } + } + }, "node_modules/@toruslabs/broadcast-channel/node_modules/@toruslabs/metadata-helpers": { "version": "3.2.0", "license": "MIT", @@ -3923,53 +3900,6 @@ } } }, - "node_modules/@toruslabs/customauth/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/customauth/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/customauth/node_modules/@scure/bip32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", - "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", - "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/customauth/node_modules/@scure/bip39": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@toruslabs/customauth/node_modules/@toruslabs/broadcast-channel": { "version": "8.0.0", "license": "MIT", @@ -3988,57 +3918,6 @@ "npm": ">=9.x" } }, - "node_modules/@toruslabs/customauth/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, - "node_modules/@toruslabs/customauth/node_modules/@toruslabs/metadata-helpers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/metadata-helpers/-/metadata-helpers-5.0.0.tgz", - "integrity": "sha512-ZUFfOHJVJC53c8wJYHjdF3bIgN2ZvfqehbTZ/zJ7oVFfrrd6O66V3gQ1i1zxBjH3yhOvZKQwc0DaMmh3G0NUXQ==", - "dependencies": { - "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/http-helpers": "^5.0.0", - "elliptic": "^6.5.4", - "ethereum-cryptography": "^2.1.2", - "json-stable-stringify": "^1.0.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/customauth/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", - "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, "node_modules/@toruslabs/eccrypto": { "version": "4.0.0", "license": "CC0-1.0", @@ -4098,27 +3977,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/fetch-node-details/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@toruslabs/fnd-base": { "version": "13.0.1", "license": "MIT", @@ -4134,235 +3992,6 @@ } }, "node_modules/@toruslabs/http-helpers": { - "version": "3.4.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=14.17.0", - "npm": ">=6.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, - "node_modules/@toruslabs/metadata-helpers": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@toruslabs/metadata-helpers/-/metadata-helpers-4.0.1.tgz", - "integrity": "sha512-0DFPxaNqmuVwFaEddl94dR/rpin5X+Odl1HR8cnzcrbzjLrOuKkGOdWtB6gnIqCUD6onMFO3156crgbHvagrLg==", - "dependencies": { - "@toruslabs/eccrypto": "^3.0.0", - "@toruslabs/http-helpers": "^4.0.0", - "elliptic": "^6.5.4", - "ethereum-cryptography": "^2.1.2", - "json-stable-stringify": "^1.0.2" - }, - "engines": { - "node": ">=16.18.1", - "npm": ">=8.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@noble/curves": { - "version": "1.1.0", - "license": "MIT", - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@noble/hashes": { - "version": "1.3.1", - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@scure/bip32": { - "version": "1.3.1", - "license": "MIT", - "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@scure/bip39": { - "version": "1.2.1", - "license": "MIT", - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@toruslabs/eccrypto": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/eccrypto/-/eccrypto-3.0.0.tgz", - "integrity": "sha512-+lFjV+0FZ3S4zH5T/Gnc795HoqpzLLDW28fSkibZRlx1Nx8uwbl3pyJSfya0C0bRHH1/+NTeBogUDijaRJ1NCw==", - "dependencies": { - "elliptic": "^6.5.4" - }, - "engines": { - "node": ">=16.18.1", - "npm": ">=8.x" - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/@toruslabs/http-helpers": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-4.0.0.tgz", - "integrity": "sha512-ef/Svevk54JANOn3Kf6UPf8X/vZlYHrusNFt8VV/LLahhVNXCXEcO8goC1bHkecu/u20CUyo9HJa0pn8fHh1sg==", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=16.18.1", - "npm": ">=8.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, - "node_modules/@toruslabs/metadata-helpers/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "license": "MIT", - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, - "node_modules/@toruslabs/openlogin": { - "version": "5.0.3", - "license": "ISC", - "dependencies": { - "@toruslabs/broadcast-channel": "^8.0.0", - "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/metadata-helpers": "^5.0.0", - "@toruslabs/openlogin-session-manager": "^3.0.0", - "@toruslabs/openlogin-utils": "^5.0.2", - "bowser": "^2.11.0", - "events": "^3.3.0", - "loglevel": "^1.8.1", - "ts-custom-error": "^3.3.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/openlogin-jrpc": { - "version": "2.13.0", - "license": "ISC", - "dependencies": { - "@toruslabs/openlogin-utils": "^2.13.0", - "end-of-stream": "^1.4.4", - "eth-rpc-errors": "^4.0.3", - "events": "^3.3.0", - "fast-safe-stringify": "^2.1.1", - "once": "^1.4.0", - "pump": "^3.0.0", - "readable-stream": "^3.6.0" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/openlogin-session-manager": { - "version": "3.0.0", - "license": "ISC", - "dependencies": { - "@toruslabs/base-session-manager": "^3.0.0", - "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/metadata-helpers": "5.0.0" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@noble/curves": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", - "dependencies": { - "@noble/hashes": "1.3.1" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@noble/hashes": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@scure/bip32": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", - "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", - "dependencies": { - "@noble/curves": "~1.1.0", - "@noble/hashes": "~1.3.1", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@scure/bip39": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", - "dependencies": { - "@noble/hashes": "~1.3.0", - "@scure/base": "~1.1.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@toruslabs/http-helpers": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-5.0.0.tgz", "integrity": "sha512-GmezWz9JeF6YyhjLSm+9XDF4YaeICEckY0Jbo43i86SjhfJYgRWqEi63VSiNsaqc/z810Q0FQvEk1TnBRX2tgA==", @@ -4384,52 +4013,28 @@ } } }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/@toruslabs/metadata-helpers": { + "node_modules/@toruslabs/metadata-helpers": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/@toruslabs/metadata-helpers/-/metadata-helpers-5.0.0.tgz", "integrity": "sha512-ZUFfOHJVJC53c8wJYHjdF3bIgN2ZvfqehbTZ/zJ7oVFfrrd6O66V3gQ1i1zxBjH3yhOvZKQwc0DaMmh3G0NUXQ==", - "dependencies": { - "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/http-helpers": "^5.0.0", - "elliptic": "^6.5.4", - "ethereum-cryptography": "^2.1.2", - "json-stable-stringify": "^1.0.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, - "node_modules/@toruslabs/openlogin-session-manager/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", - "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, - "node_modules/@toruslabs/openlogin-utils": { - "version": "2.13.0", - "license": "ISC", - "dependencies": { - "base64url": "^3.0.1", - "keccak": "^3.0.3", - "randombytes": "^2.1.0" + "dependencies": { + "@toruslabs/eccrypto": "^4.0.0", + "@toruslabs/http-helpers": "^5.0.0", + "elliptic": "^6.5.4", + "ethereum-cryptography": "^2.1.2", + "json-stable-stringify": "^1.0.2" + }, + "engines": { + "node": ">=18.x", + "npm": ">=9.x" }, "peerDependencies": { "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/openlogin/node_modules/@noble/curves": { + "node_modules/@toruslabs/metadata-helpers/node_modules/@noble/curves": { "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.1.0.tgz", - "integrity": "sha512-091oBExgENk/kGj3AZmtBDMpxQPDtxQABR2B9lb1JbVTs6ytdzZNwvhxQ4MWasRNEzlbEH8jCWFCwhF/Obj5AA==", + "license": "MIT", "dependencies": { "@noble/hashes": "1.3.1" }, @@ -4437,10 +4042,9 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@toruslabs/openlogin/node_modules/@noble/hashes": { + "node_modules/@toruslabs/metadata-helpers/node_modules/@noble/hashes": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.1.tgz", - "integrity": "sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==", + "license": "MIT", "engines": { "node": ">= 16" }, @@ -4448,10 +4052,9 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@toruslabs/openlogin/node_modules/@scure/bip32": { + "node_modules/@toruslabs/metadata-helpers/node_modules/@scure/bip32": { "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.1.tgz", - "integrity": "sha512-osvveYtyzdEVbt3OfwwXFr4P2iVBL5u1Q3q4ONBfDY/UpOuXmOlbgwc1xECEboY8wIays8Yt6onaWMUdUbfl0A==", + "license": "MIT", "dependencies": { "@noble/curves": "~1.1.0", "@noble/hashes": "~1.3.1", @@ -4461,10 +4064,9 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@toruslabs/openlogin/node_modules/@scure/bip39": { + "node_modules/@toruslabs/metadata-helpers/node_modules/@scure/bip39": { "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.1.tgz", - "integrity": "sha512-Z3/Fsz1yr904dduJD0NpiyRHhRYHdcnyh73FZWiV+/qhWi83wNJ3NWolYqCEN+ZWsUz2TWwajJggcRE9r1zUYg==", + "license": "MIT", "dependencies": { "@noble/hashes": "~1.3.0", "@scure/base": "~1.1.0" @@ -4473,63 +4075,99 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@toruslabs/openlogin/node_modules/@toruslabs/broadcast-channel": { - "version": "8.0.0", + "node_modules/@toruslabs/metadata-helpers/node_modules/ethereum-cryptography": { + "version": "2.1.2", "license": "MIT", "dependencies": { - "@babel/runtime": "^7.22.10", + "@noble/curves": "1.1.0", + "@noble/hashes": "1.3.1", + "@scure/bip32": "1.3.1", + "@scure/bip39": "1.2.1" + } + }, + "node_modules/@toruslabs/openlogin": { + "version": "5.0.3", + "license": "ISC", + "dependencies": { + "@toruslabs/broadcast-channel": "^8.0.0", "@toruslabs/eccrypto": "^4.0.0", "@toruslabs/metadata-helpers": "^5.0.0", + "@toruslabs/openlogin-session-manager": "^3.0.0", + "@toruslabs/openlogin-utils": "^5.0.2", "bowser": "^2.11.0", + "events": "^3.3.0", "loglevel": "^1.8.1", - "oblivious-set": "1.1.1", - "socket.io-client": "^4.7.2", - "unload": "^2.4.1" + "ts-custom-error": "^3.3.1" }, "engines": { "node": ">=18.x", "npm": ">=9.x" + }, + "peerDependencies": { + "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/openlogin/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-5.0.0.tgz", - "integrity": "sha512-GmezWz9JeF6YyhjLSm+9XDF4YaeICEckY0Jbo43i86SjhfJYgRWqEi63VSiNsaqc/z810Q0FQvEk1TnBRX2tgA==", + "node_modules/@toruslabs/openlogin-jrpc": { + "version": "2.13.0", + "license": "ISC", "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" + "@toruslabs/openlogin-utils": "^2.13.0", + "end-of-stream": "^1.4.4", + "eth-rpc-errors": "^4.0.3", + "events": "^3.3.0", + "fast-safe-stringify": "^2.1.1", + "once": "^1.4.0", + "pump": "^3.0.0", + "readable-stream": "^3.6.0" + }, + "peerDependencies": { + "@babel/runtime": "7.x" + } + }, + "node_modules/@toruslabs/openlogin-session-manager": { + "version": "3.0.0", + "license": "ISC", + "dependencies": { + "@toruslabs/base-session-manager": "^3.0.0", + "@toruslabs/eccrypto": "^4.0.0", + "@toruslabs/metadata-helpers": "5.0.0" }, "engines": { "node": ">=18.x", "npm": ">=9.x" }, "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" + "@babel/runtime": "7.x" + } + }, + "node_modules/@toruslabs/openlogin-utils": { + "version": "2.13.0", + "license": "ISC", + "dependencies": { + "base64url": "^3.0.1", + "keccak": "^3.0.3", + "randombytes": "^2.1.0" }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } + "peerDependencies": { + "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/openlogin/node_modules/@toruslabs/metadata-helpers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/metadata-helpers/-/metadata-helpers-5.0.0.tgz", - "integrity": "sha512-ZUFfOHJVJC53c8wJYHjdF3bIgN2ZvfqehbTZ/zJ7oVFfrrd6O66V3gQ1i1zxBjH3yhOvZKQwc0DaMmh3G0NUXQ==", + "node_modules/@toruslabs/openlogin/node_modules/@toruslabs/broadcast-channel": { + "version": "8.0.0", + "license": "MIT", "dependencies": { + "@babel/runtime": "^7.22.10", "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/http-helpers": "^5.0.0", - "elliptic": "^6.5.4", - "ethereum-cryptography": "^2.1.2", - "json-stable-stringify": "^1.0.2" + "@toruslabs/metadata-helpers": "^5.0.0", + "bowser": "^2.11.0", + "loglevel": "^1.8.1", + "oblivious-set": "1.1.1", + "socket.io-client": "^4.7.2", + "unload": "^2.4.1" }, "engines": { "node": ">=18.x", "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" } }, "node_modules/@toruslabs/openlogin/node_modules/@toruslabs/openlogin-utils": { @@ -4547,17 +4185,6 @@ "@babel/runtime": "7.x" } }, - "node_modules/@toruslabs/openlogin/node_modules/ethereum-cryptography": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-2.1.2.tgz", - "integrity": "sha512-Z5Ba0T0ImZ8fqXrJbpHcbpAvIswRte2wGNR/KePnu8GbbvgJ47lMxT/ZZPG6i9Jaht4azPDop4HaM00J0J59ug==", - "dependencies": { - "@noble/curves": "1.1.0", - "@noble/hashes": "1.3.1", - "@scure/bip32": "1.3.1", - "@scure/bip39": "1.2.1" - } - }, "node_modules/@toruslabs/rss-client": { "version": "1.5.0", "license": "MIT", @@ -4587,6 +4214,28 @@ "elliptic": "^6.5.4" } }, + "node_modules/@toruslabs/rss-client/node_modules/@toruslabs/http-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-3.4.0.tgz", + "integrity": "sha512-CoeJSL32mpp0gmYjxv48odu6pfjHk/rbJHDwCtYPcMHAl+qUQ/DTpVOOn9U0fGkD+fYZrQmZbRkXFgLhiT0ajQ==", + "dependencies": { + "lodash.merge": "^4.6.2", + "loglevel": "^1.8.1" + }, + "engines": { + "node": ">=14.17.0", + "npm": ">=6.x" + }, + "peerDependencies": { + "@babel/runtime": "^7.x", + "@sentry/types": "^7.x" + }, + "peerDependenciesMeta": { + "@sentry/types": { + "optional": true + } + } + }, "node_modules/@toruslabs/rss-client/node_modules/node-fetch": { "version": "2.7.0", "license": "MIT", @@ -4729,27 +4378,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@toruslabs/torus.js/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@toruslabs/torus.js/node_modules/ethereum-cryptography": { "version": "2.1.2", "license": "MIT", @@ -4776,8 +4404,10 @@ "version": "1.7.1" }, "node_modules/@toruslabs/tss-lib-node": { - "resolved": "../tss-server/packages/tss-lib", - "link": true + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@toruslabs/tss-lib-node/-/tss-lib-node-1.1.3.tgz", + "integrity": "sha512-yPJRHS0ykbWCthnUNe8pil3PNWFjqwKOw5vwW/UkHY8zEw4lpSQKnfGY2BSYW83ZEHak9b6E4y0dHQKKCkOpTA==", + "dev": true }, "node_modules/@tsconfig/node10": { "version": "1.0.9", @@ -5231,6 +4861,28 @@ "@babel/runtime": "7.x" } }, + "node_modules/@web3auth-mpc/base/node_modules/@toruslabs/http-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-3.4.0.tgz", + "integrity": "sha512-CoeJSL32mpp0gmYjxv48odu6pfjHk/rbJHDwCtYPcMHAl+qUQ/DTpVOOn9U0fGkD+fYZrQmZbRkXFgLhiT0ajQ==", + "dependencies": { + "lodash.merge": "^4.6.2", + "loglevel": "^1.8.1" + }, + "engines": { + "node": ">=14.17.0", + "npm": ">=6.x" + }, + "peerDependencies": { + "@babel/runtime": "^7.x", + "@sentry/types": "^7.x" + }, + "peerDependenciesMeta": { + "@sentry/types": { + "optional": true + } + } + }, "node_modules/@web3auth-mpc/ethereum-provider": { "version": "2.3.0", "license": "ISC", @@ -5256,6 +4908,28 @@ "@babel/runtime": "7.x" } }, + "node_modules/@web3auth-mpc/ethereum-provider/node_modules/@toruslabs/http-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@toruslabs/http-helpers/-/http-helpers-3.4.0.tgz", + "integrity": "sha512-CoeJSL32mpp0gmYjxv48odu6pfjHk/rbJHDwCtYPcMHAl+qUQ/DTpVOOn9U0fGkD+fYZrQmZbRkXFgLhiT0ajQ==", + "dependencies": { + "lodash.merge": "^4.6.2", + "loglevel": "^1.8.1" + }, + "engines": { + "node": ">=14.17.0", + "npm": ">=6.x" + }, + "peerDependencies": { + "@babel/runtime": "^7.x", + "@sentry/types": "^7.x" + }, + "peerDependenciesMeta": { + "@sentry/types": { + "optional": true + } + } + }, "node_modules/@web3auth/base": { "version": "7.0.1", "license": "ISC", @@ -5407,46 +5081,6 @@ "npm": ">=9.x" } }, - "node_modules/@web3auth/base-provider/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, - "node_modules/@web3auth/base-provider/node_modules/@toruslabs/metadata-helpers": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@toruslabs/metadata-helpers/-/metadata-helpers-5.0.0.tgz", - "integrity": "sha512-ZUFfOHJVJC53c8wJYHjdF3bIgN2ZvfqehbTZ/zJ7oVFfrrd6O66V3gQ1i1zxBjH3yhOvZKQwc0DaMmh3G0NUXQ==", - "dependencies": { - "@toruslabs/eccrypto": "^4.0.0", - "@toruslabs/http-helpers": "^5.0.0", - "elliptic": "^6.5.4", - "ethereum-cryptography": "^2.1.2", - "json-stable-stringify": "^1.0.2" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "7.x" - } - }, "node_modules/@web3auth/base-provider/node_modules/@toruslabs/openlogin-jrpc": { "version": "5.0.2", "license": "ISC", @@ -5507,27 +5141,6 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@web3auth/base/node_modules/@toruslabs/http-helpers": { - "version": "5.0.0", - "license": "MIT", - "dependencies": { - "lodash.merge": "^4.6.2", - "loglevel": "^1.8.1" - }, - "engines": { - "node": ">=18.x", - "npm": ">=9.x" - }, - "peerDependencies": { - "@babel/runtime": "^7.x", - "@sentry/types": "^7.x" - }, - "peerDependenciesMeta": { - "@sentry/types": { - "optional": true - } - } - }, "node_modules/@web3auth/base/node_modules/@toruslabs/openlogin-jrpc": { "version": "5.0.2", "license": "ISC", @@ -9682,6 +9295,11 @@ "he": "bin/he" } }, + "node_modules/hi-base32": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==" + }, "node_modules/hmac-drbg": { "version": "1.0.1", "license": "MIT", diff --git a/package.json b/package.json index 2ea2a7e1..4e24a43d 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "@toruslabs/fetch-node-details": "^13.0.1", "@toruslabs/fnd-base": "^13.0.1", "@toruslabs/http-helpers": "^5.0.0", - "@toruslabs/metadata-helpers": "^5.x", + "@toruslabs/metadata-helpers": "^4.x", "@toruslabs/openlogin-session-manager": "^3.0.0", "@toruslabs/torus.js": "^11.0.6", "@toruslabs/tss-client": "^1.7.1", @@ -58,7 +58,8 @@ "@web3auth/base-provider": "^7.0.1", "bn.js": "^5.2.1", "bowser": "^2.11.0", - "elliptic": "^6.5.4" + "elliptic": "^6.5.4", + "hi-base32": "^0.5.1" }, "devDependencies": { "@babel/register": "^7.22.15", diff --git a/src/helper/authenticator/authenticatorService.ts b/src/helper/authenticator/authenticatorService.ts new file mode 100644 index 00000000..cc7f53de --- /dev/null +++ b/src/helper/authenticator/authenticatorService.ts @@ -0,0 +1,91 @@ +import { generatePrivate } from "@toruslabs/eccrypto"; +import { post } from "@toruslabs/http-helpers"; +import { keccak256 } from "@toruslabs/metadata-helpers"; +import BN from "bn.js"; +import type { ec } from "elliptic"; +import base32 from "hi-base32"; + +import { CURVE } from "../../constants"; + +export class AuthenticatorService { + private authenticatorUrl: string; + + // private remoteClient: boolean = false; + + constructor(params: { authenticatorUrl: string }) { + const { authenticatorUrl } = params; + this.authenticatorUrl = authenticatorUrl; + // this.remoteClient = remoteClient || false; + } + + generateSecretKey(): string { + const key = generatePrivate().subarray(0, 20); + return base32.encode(key).toString().replace(/=/g, ""); + } + + async register(privKey: BN, secretKey: string): Promise<{ success: boolean; message?: string }> { + const privKeyPair: ec.KeyPair = CURVE.keyFromPrivate(privKey.toString(16, 64)); + const pubKey = privKeyPair.getPublic(); + const sig = CURVE.sign(keccak256(Buffer.from(secretKey, "utf8")), Buffer.from(privKey.toString(16, 64), "hex")); + + const data = { + pubKey: { + x: pubKey.getX().toString(16, 64), + y: pubKey.getY().toString(16, 64), + }, + sig: { + r: sig.r.toString(16, 64), + s: sig.s.toString(16, 64), + v: new BN(sig.recoveryParam as number).toString(16, 2), + }, + secretKey, + }; + + const resp = await post<{ + success: boolean; + message: string; + }>(`${this.authenticatorUrl}/register`, data); + + return resp; + } + + async addAuthenticatorRecovery(address: string, code: string, factorKey: BN) { + if (!factorKey) throw new Error("factorKey is not defined"); + if (!address) throw new Error("address is not defined"); + if (!code) throw new Error("code is not defined"); + + const data = { + address, + code, + data: { + // If the verification is complete, we save the factorKey for the user address. + // This factorKey is used to verify the user in the future on a new device and recover tss share. + factorKey: factorKey.toString(16, 64), + }, + }; + + await post(`${this.authenticatorUrl}/verify`, data); + } + + async verifyAuthenticatorRecovery(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } + + async verifyAuthenticatorRemoteSetup(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } +} diff --git a/src/helper/authenticator/smsService.ts b/src/helper/authenticator/smsService.ts new file mode 100644 index 00000000..17d16385 --- /dev/null +++ b/src/helper/authenticator/smsService.ts @@ -0,0 +1,97 @@ +import { post } from "@toruslabs/http-helpers"; +import { keccak256 } from "@toruslabs/metadata-helpers"; +import BN from "bn.js"; +import type { ec } from "elliptic"; + +import { CURVE } from "../../constants"; + +export class SmsService { + private smsbackendUrl: string; + + constructor(params: { smsbackendUrl: string }) { + const { smsbackendUrl } = params; + this.smsbackendUrl = smsbackendUrl; + } + + async registerSmsOTP(privKey: BN, number: string): Promise { + const privKeyPair: ec.KeyPair = CURVE.keyFromPrivate(privKey.toString(16, 64)); + const pubKey = privKeyPair.getPublic(); + const sig = CURVE.sign(keccak256(Buffer.from(number, "utf8")), Buffer.from(privKey.toString(16, 64), "hex")); + + const data = { + pubKey: { + x: pubKey.getX().toString(16, 64), + y: pubKey.getY().toString(16, 64), + }, + sig: { + r: sig.r.toString(16, 64), + s: sig.s.toString(16, 64), + v: new BN(sig.recoveryParam as number).toString(16, 2), + }, + number, + }; + + await post<{ + success: boolean; + id_token?: string; + message: string; + }>(`${this.smsbackendUrl}/register`, data); + + // this is to send sms to the user instantly after registration. + const startData = { + address: `${pubKey.getX().toString(16, 64)}${pubKey.getY().toString(16, 64)}`, + }; + + // Sends the user sms. + const resp2 = await post<{ success: boolean; code?: string }>(`${this.smsbackendUrl}/start`, startData); + // if (resp2.status !== 200) throw new Error("Error sending sms"); + return resp2.code; + } + + async addSmsRecovery(address: string, code: string, factorKey: BN) { + if (!factorKey) throw new Error("factorKey is not defined"); + if (!address) throw new Error("address is not defined"); + + const data = { + address, + code, + data: { + // If the verification is complete, we save the factorKey for the user address. + // This factorKey is used to verify the user in the future on a new device and recover tss share. + factorKey: factorKey.toString(16, 64), + }, + }; + + await post(`${this.smsbackendUrl}/verify`, data); + } + + async requestSMSOTP(address: string): Promise { + const startData = { + address, + }; + const resp2 = await post<{ success?: boolean; code?: string }>(`${this.smsbackendUrl}/start`, startData); + return resp2.code; + } + + async verifySMSOTPRecovery(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } + + async verifySMSOTPRemote(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } +} diff --git a/src/index.ts b/src/index.ts index 31dec0b2..53082d66 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,5 +1,7 @@ export * from "./constants"; export * from "./helper"; +export * from "./helper/authenticator/authenticatorService"; +export * from "./helper/authenticator/smsService"; export * from "./interfaces"; export * from "./mpcCoreKit"; export * from "./point"; diff --git a/src/interfaces.ts b/src/interfaces.ts index ab424705..8d065a35 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -117,6 +117,13 @@ export interface IdTokenLoginParams { additionalParams?: ExtraParams; } +export interface IRemoteClientState { + remoteFactorPub: string; + remoteClientUrl: string; + signature: string; + metadataShare: string; +} + export interface Web3AuthState { oAuthKey?: string; signatures?: string[]; @@ -124,6 +131,7 @@ export interface Web3AuthState { tssShareIndex?: number; tssPubKey?: Buffer; factorKey?: BN; + remoteClient?: IRemoteClientState; } export interface ICoreKit { @@ -359,6 +367,7 @@ export interface SessionData { tssPubKey: string; signatures: string[]; userInfo: UserInfo; + remoteClient?: IRemoteClientState; } export interface TkeyLocalStoreData { diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 33047c6e..0f2f3b84 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1,6 +1,15 @@ /* eslint-disable @typescript-eslint/member-ordering */ -import { BNString, encrypt, getPubKeyPoint, Point as TkeyPoint, SHARE_DELETED, ShareStore, StringifiedType } from "@tkey-mpc/common-types"; -import ThresholdKey, { CoreError, lagrangeInterpolation, Metadata } from "@tkey-mpc/core"; +import { + BNString, + encrypt, + EncryptedMessage, + getPubKeyPoint, + Point as TkeyPoint, + SHARE_DELETED, + ShareStore, + StringifiedType, +} from "@tkey-mpc/common-types"; +import ThresholdKey, { CoreError, lagrangeInterpolation } from "@tkey-mpc/core"; import { TorusServiceProvider } from "@tkey-mpc/service-provider-torus"; import { ShareSerializationModule } from "@tkey-mpc/share-serialization"; import { TorusStorageLayer } from "@tkey-mpc/storage-layer-torus"; @@ -60,7 +69,6 @@ import { getHashedPrivateKey, parseToken, scalarBNToBufferSEC1, - Web3AuthStateFromJSON, } from "./utils"; export class Web3AuthMPCCoreKit implements ICoreKit { @@ -88,16 +96,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit { private ready = false; - private remoteClientUrl: string | undefined; - - constructor(options: Web3AuthOptions, remoteClientUrl?: string) { + constructor(options: Web3AuthOptions) { // log.info("======================================================"); // log.info(`WEB3AUTH SDK : ${name}:${version}`); // log.info("======================================================"); - this.remoteClientUrl = remoteClientUrl.at(-1) === "/" ? remoteClientUrl.slice(0, -1) : remoteClientUrl; - if (!options.chainConfig) options.chainConfig = DEFAULT_CHAIN_CONFIG; if (options.chainConfig.chainNamespace !== CHAIN_NAMESPACES.EIP155) { throw new Error("You must specify a eip155 chain config."); @@ -178,7 +182,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { const { tkey } = this; if (!tkey) return COREKIT_STATUS.NOT_INITIALIZED; if (!tkey.metadata) return COREKIT_STATUS.INITIALIZED; - if (!tkey.privKey || !this.state.factorKey) return COREKIT_STATUS.REQUIRED_SHARE; + if (!tkey.privKey || (!this.state.factorKey && !this.state.remoteClient)) return COREKIT_STATUS.REQUIRED_SHARE; return COREKIT_STATUS.LOGGED_IN; } catch (e) {} return COREKIT_STATUS.NOT_INITIALIZED; @@ -290,7 +294,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { // if not redirect flow try to rehydrate session if available } else if (this.sessionManager.sessionId) { await this.rehydrateSession(); - if (this.state.factorKey) await this.setupProvider(); + if (this.state.factorKey || this.state.remoteClient) await this.setupProvider(); } // if not redirect flow or session rehydration, ask for factor key to login } @@ -435,6 +439,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public async inputFactorKey(factorKey: BN): Promise { this.checkReady(); + if (this.state.remoteClient) throw new Error("remoteClient is present, inputFactorKey are not allowed"); try { // input tkey device share when required share > 0 ( or not reconstructed ) // assumption tkey shares will not changed @@ -457,7 +462,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public getCurrentFactorKey(): IFactorKey { this.checkReady(); - if (!this.state.factorKey) throw new Error("factorKey not present"); + if (!this.state.factorKey && !this.state.remoteClient) throw new Error("factorKey not present"); if (!this.state.tssShareIndex) throw new Error("TSS Share Type (Index) not present"); try { return { @@ -521,7 +526,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public getTssFactorPub = (): string[] => { this.checkReady(); - if (!this.state.factorKey) throw new Error("factorKey not present"); + + if (!this.state.factorKey && !this.state.remoteClient) throw new Error("factorKey not present"); const factorPubsList = this.tKey.metadata.factorPubs[this.tKey.tssTag]; return factorPubsList.map((factorPub) => Point.fromTkeyPoint(factorPub).toBufferSEC1(true).toString("hex")); }; @@ -571,7 +577,14 @@ export class Web3AuthMPCCoreKit implements ICoreKit { return tssPubKey; }; - public sign = async (msgHash: Buffer) => { + public sign = async (msgHash: Buffer): Promise<{ v: number; r: Buffer; s: Buffer }> => { + if (this.state.remoteClient) { + return this.remoteSign(msgHash); + } + return this.localSign(msgHash); + }; + + public localSign = async (msgHash: Buffer) => { // PreSetup let { tssShareIndex, tssPubKey } = this.state; const { torusNodeTSSEndpoints } = await this.nodeDetailManager.getNodeDetails({ @@ -652,17 +665,33 @@ export class Web3AuthMPCCoreKit implements ICoreKit { }; async deleteFactor(factorPub: TkeyPoint, factorKey?: BNString): Promise { - if (!this.state.factorKey) throw new Error("Factor key not present"); + if (!this.state.factorKey && !this.state.remoteClient) throw new Error("Factor key not present"); if (!this.tKey.metadata.factorPubs) throw new Error("Factor pubs not present"); const remainingFactors = this.tKey.metadata.factorPubs[this.tKey.tssTag].length || 0; if (remainingFactors <= 1) throw new Error("Cannot delete last factor"); const fpp = Point.fromTkeyPoint(factorPub); - const stateFpp = Point.fromTkeyPoint(getPubKeyPoint(this.state.factorKey)); - if (fpp.equals(stateFpp)) { - throw new Error("Cannot delete current active factor"); + + if (this.state.remoteClient) { + const remoteStateFpp = this.state.remoteClient.remoteFactorPub; + if (fpp.equals(Point.fromTkeyPoint(getPubKeyPoint(new BN(remoteStateFpp, "hex"))))) { + throw new Error("Cannot delete current active factor"); + } + await deleteFactorAndRefresh( + this.tKey, + factorPub, + new BN(0), // not used in remoteClient + this.signatures, + TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub), + this.state.remoteClient.remoteClientUrl + ); + } else { + const stateFpp = Point.fromTkeyPoint(getPubKeyPoint(this.state.factorKey)); + if (fpp.equals(stateFpp)) { + throw new Error("Cannot delete current active factor"); + } + await deleteFactorAndRefresh(this.tKey, factorPub, this.state.factorKey, this.signatures); } - await deleteFactorAndRefresh(this.tKey, factorPub, this.state.factorKey, this.signatures, this.remoteClientUrl); const factorPubHex = fpp.toBufferSEC1(true).toString("hex"); const allDesc = this.tKey.metadata.getShareDescription(); const keyDesc = allDesc[factorPubHex]; @@ -722,7 +751,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { public async commitChanges(): Promise { this.checkReady(); - if (!this.state.factorKey) throw new Error("factorKey not present"); + if (!this.state.factorKey && !this.state.remoteClient) throw new Error("factorKey not present"); try { // in case for manualsync = true, _syncShareMetadata will not call syncLocalMetadataTransitions() @@ -744,6 +773,38 @@ export class Web3AuthMPCCoreKit implements ICoreKit { this.tKey.manualSync = manualSync; } + public async setupRemoteClient(params: { + remoteClientUrl: string; + remoteFactorPub: string; + metadataShare: string; + signature: string; + tssShareIndex: string; + }): Promise> { + const { remoteClientUrl, remoteFactorPub, metadataShare, signature, tssShareIndex } = params; + + const remoteClient = { + remoteClientUrl: remoteClientUrl.at(-1) === "/" ? remoteClientUrl.slice(0, -1) : remoteClientUrl, + remoteFactorPub, + metadataShare, + signature, + }; + + const sharestore = ShareStore.fromJSON(JSON.parse(metadataShare)); + this.tkey.inputShareStoreSafe(sharestore); + await this.tKey.reconstructKey(); + log.info(metadataShare); + log.info(signature); + + // setup Tkey + const tssPubKey = Point.fromTkeyPoint(this.tKey.getTSSPub()).toBufferSEC1(false); + this.updateState({ tssShareIndex: parseInt(tssShareIndex), tssPubKey, remoteClient }); + + // // Finalize setup. + // setup provider + await this.setupProvider(); + await this.createSession(); + } + // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore private async importTssKey(tssKey: string, factorPub: TkeyPoint, newTSSIndex: TssShareType = TssShareType.DEVICE): Promise { @@ -754,6 +815,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { } public async _UNSAFE_exportTssKey(): Promise { + if (this.state.remoteClient) throw new Error("export tss key not supported for remote client"); if (!this.state.factorKey) throw new Error("factorKey not present"); if (!this.state.signatures) throw new Error("signatures not present"); @@ -773,6 +835,10 @@ export class Web3AuthMPCCoreKit implements ICoreKit { } private async setupTkey(importTssKey?: string): Promise { + if (this.state.remoteClient) { + log.warn("remote client is present, setupTkey are skipped"); + return; + } if (!this.state.oAuthKey) { throw new Error("user not logged in"); } @@ -868,6 +934,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { tssPubKey: Buffer.from(result.tssPubKey.padStart(FIELD_ELEMENT_HEX_LEN, "0"), "hex"), signatures: result.signatures, userInfo: result.userInfo, + remoteClient: result.remoteClient, }); } catch (err) { log.error("error trying to authorize session", err); @@ -883,11 +950,14 @@ export class Web3AuthMPCCoreKit implements ICoreKit { try { const sessionId = OpenloginSessionManager.generateRandomSessionKey(); this.sessionManager.sessionId = sessionId; - const { oAuthKey, factorKey, userInfo, tssShareIndex, tssPubKey } = this.state; - if (!this.state.factorKey) throw new Error("factorKey not present"); - const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); - if (!oAuthKey || !factorKey || !tssShare || !tssPubKey || !userInfo) { - throw new Error("User not logged in"); + const { oAuthKey, factorKey, userInfo, tssShareIndex, tssPubKey, remoteClient } = this.state; + if (!this.state.factorKey && !this.state.remoteClient) throw new Error("factorKey not present"); + + if (!this.state.remoteClient) { + const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); + if (!oAuthKey || !factorKey || !tssShare || !tssPubKey || !userInfo) { + throw new Error("User not logged in"); + } } const payload: SessionData = { oAuthKey, @@ -896,6 +966,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { tssPubKey: Buffer.from(tssPubKey).toString("hex"), signatures: this.signatures, userInfo, + remoteClient, }; await this.sessionManager.createSession(payload); this.currentStorage.set("sessionId", sessionId); @@ -946,7 +1017,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { if (!this.tKey.metadata.factorEncs || typeof this.tKey.metadata.factorEncs[this.tKey.tssTag] !== "object") { throw new Error("factorEncs does not exist, failed in copy factor pub"); } - if (!this.state.factorKey) { + if (!this.state.factorKey && !this.state.remoteClient) { throw new Error("factorKey not present"); } if (VALID_SHARE_INDICES.indexOf(newFactorTSSIndex) === -1) { @@ -957,28 +1028,47 @@ export class Web3AuthMPCCoreKit implements ICoreKit { throw new Error("Maximum number of factors reached"); } if (this.state.tssShareIndex !== newFactorTSSIndex) { - if (!this.state.factorKey) throw new Error("factorKey not present"); - // Generate new share. - await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures, this.remoteClientUrl); - - // Update local share. - const { tssIndex } = await this.tKey.getTSSShare(this.state.factorKey); - this.updateState({ - tssShareIndex: tssIndex, - }); + if (!this.state.remoteClient) { + await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures); + } else { + await addFactorAndRefresh( + this.tKey, + newFactorPub, + newFactorTSSIndex, + this.state.factorKey, + this.signatures, + TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub), + this.state.remoteClient.remoteClientUrl + ); + } return; } + // TODO : fix this + let userEnc: EncryptedMessage; + if (this.state.remoteClient) { + const remoteFactorPub = TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub); + const factorEnc = this.tkey.getFactorEncs(remoteFactorPub); + const tssCommits = this.tkey.getTSSCommits(); + const dataRequired = { + factorEnc, + tssCommits, + factorPub: newFactorPub, + }; + + userEnc = (await post(`${this.state.remoteClient.remoteClientUrl}/api/mpc/copy_tss_share`, { dataRequired })) as EncryptedMessage; + } else { + const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); + userEnc = await encrypt(Point.fromTkeyPoint(newFactorPub).toBufferSEC1(false), scalarBNToBufferSEC1(tssShare)); + } - if (!this.state.factorKey) throw new Error("factorKey not present"); - const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); const updatedFactorPubs = this.tKey.metadata.factorPubs[this.tKey.tssTag].concat([newFactorPub]); const factorEncs = JSON.parse(JSON.stringify(this.tKey.metadata.factorEncs[this.tKey.tssTag])); const factorPubID = newFactorPub.x.toString(16, FIELD_ELEMENT_HEX_LEN); factorEncs[factorPubID] = { tssIndex: this.state.tssShareIndex, type: "direct", - userEnc: await encrypt(Point.fromTkeyPoint(newFactorPub).toBufferSEC1(false), scalarBNToBufferSEC1(tssShare)), + userEnc, serverEncs: [], }; this.tKey.metadata.addTSSData({ @@ -987,7 +1077,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { factorEncs, }); - if (!this.tKey.manualSync) await this.tKey._syncShareMetadata(); + // if (!this.tKey.manualSync) await this.tKey._syncShareMetadata(); } private async getMetadataShare(): Promise { @@ -1066,46 +1156,48 @@ export class Web3AuthMPCCoreKit implements ICoreKit { return sessionData.map((session) => JSON.stringify({ data: session.token, sig: session.signature })); } - public async serverSetup(oAuthKey: string, signatures: string[], verifier: string, verifierId: string, importTssKey?: string): Promise { - (this.tKey.serviceProvider as TorusServiceProvider).postboxKey = new BN(oAuthKey, "hex"); - (this.tKey.serviceProvider as TorusServiceProvider).verifierName = verifier; - (this.tKey.serviceProvider as TorusServiceProvider).verifierId = verifierId; - - this.updateState({ - oAuthKey, - userInfo: { verifier, verifierId } as UserInfo, - signatures, - }); - await this.setupTkey(importTssKey); - } - - public async serverSetupRehydrate({ state, tkeyJson }: { state: StringifiedType; tkeyJson: StringifiedType }) { - this.state = Web3AuthStateFromJSON(state); - - const metadata = Metadata.fromJSON(tkeyJson.metadata); - this.tKey.metadata = metadata; - - const { shares } = tkeyJson; - for (const key in shares) { - if (Object.prototype.hasOwnProperty.call(shares, key)) { - const shareStoreMapElement = shares[key]; - for (const shareElementKey in shareStoreMapElement) { - if (Object.prototype.hasOwnProperty.call(shareStoreMapElement, shareElementKey)) { - const shareStore = shareStoreMapElement[shareElementKey]; - shareStoreMapElement[shareElementKey] = ShareStore.fromJSON(shareStore); - } - } - this.tkey.shares[key] = shareStoreMapElement; - } - } - this.tkey.privKey = new BN(tkeyJson.privKey, "hex"); + // public async serverSetup(oAuthKey: string, signatures: string[], verifier: string, verifierId: string, importTssKey?: string): Promise { + // (this.tKey.serviceProvider as TorusServiceProvider).postboxKey = new BN(oAuthKey, "hex"); + // (this.tKey.serviceProvider as TorusServiceProvider).verifierName = verifier; + // (this.tKey.serviceProvider as TorusServiceProvider).verifierId = verifierId; + + // this.updateState({ + // oAuthKey, + // userInfo: { verifier, verifierId } as UserInfo, + // signatures, + // }); + // await this.setupTkey(importTssKey); + // } + + // public async serverSetupRehydrate({ state, tkeyJson }: { state: StringifiedType; tkeyJson: StringifiedType }) { + // this.state = Web3AuthStateFromJSON(state); + + // const metadata = Metadata.fromJSON(tkeyJson.metadata); + // this.tKey.metadata = metadata; + + // const { shares } = tkeyJson; + // for (const key in shares) { + // if (Object.prototype.hasOwnProperty.call(shares, key)) { + // const shareStoreMapElement = shares[key]; + // for (const shareElementKey in shareStoreMapElement) { + // if (Object.prototype.hasOwnProperty.call(shareStoreMapElement, shareElementKey)) { + // const shareStore = shareStoreMapElement[shareElementKey]; + // shareStoreMapElement[shareElementKey] = ShareStore.fromJSON(shareStore); + // } + // } + // this.tkey.shares[key] = shareStoreMapElement; + // } + // } + // this.tkey.privKey = new BN(tkeyJson.privKey, "hex"); + + // (this.tKey.serviceProvider as TorusServiceProvider).postboxKey = new BN(this.state.oAuthKey, "hex"); + // (this.tKey.serviceProvider as TorusServiceProvider).verifierName = state.userInfo.verifier; + // (this.tKey.serviceProvider as TorusServiceProvider).verifierId = state.userInfo.verifierId; + // } + + public async remoteSign(msgHash: Buffer): Promise<{ v: number; r: Buffer; s: Buffer }> { + if (!this.state.remoteClient.remoteClientUrl) throw new Error("remoteClientUrl not present"); - (this.tKey.serviceProvider as TorusServiceProvider).postboxKey = new BN(this.state.oAuthKey, "hex"); - (this.tKey.serviceProvider as TorusServiceProvider).verifierName = state.userInfo.verifier; - (this.tKey.serviceProvider as TorusServiceProvider).verifierId = state.userInfo.verifierId; - } - - public async remoteSign(msgHash: Buffer, factorPub: string) { // PreSetup const { torusNodeTSSEndpoints } = await this.nodeDetailManager.getNodeDetails({ verifier: "test-verifier", @@ -1127,9 +1219,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit { this.tKey.metadata.tssNonces[this.tKey.tssTag] ); + if (parties - 1 > nodeIndexes.length) { + throw new Error(`Not enough nodes to perform TSS - parties :${parties}, nodeIndexes:${nodeIndexes.length}`); + } const { endpoints, tssWSEndpoints, partyIndexes } = generateTSSEndpoints(torusNodeTSSEndpoints, parties, clientIndex, nodeIndexes); - const factor = TkeyPoint.fromCompressedPub(factorPub); + const factor = TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub); const factorEnc = this.tKey.getFactorEncs(factor); const data = { @@ -1137,7 +1232,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { factorEnc, sessionId, tssNonce, - nodeIndexes, + nodeIndexes: nodeIndexes.slice(0, parties - 1), tssCommits: tssCommits.map((commit) => commit.toJSON()), signatures: this.signatures, serverEndpoints: { endpoints, tssWSEndpoints, partyIndexes }, @@ -1145,10 +1240,9 @@ export class Web3AuthMPCCoreKit implements ICoreKit { msgHash: msgHash.toString("hex"), }; - const result = await post(`${this.remoteClientUrl}/sign`, data); - // eslint-disable-next-line no-console - console.log(result); + const result = await post(`${this.state.remoteClient.remoteClientUrl}/api/mpc/sign`, data); + const { r, s, v } = result as { v: number; r: string; s: string }; - return result; + return { v, r: Buffer.from(r, "hex"), s: Buffer.from(s, "hex") }; } } diff --git a/src/utils.ts b/src/utils.ts index a2ebfd9b..0c030f6f 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -8,7 +8,6 @@ import BN from "bn.js"; import { SCALAR_LEN, VALID_SHARE_INDICES as VALID_TSS_INDICES } from "./constants"; import { UserInfo, Web3AuthState } from "./interfaces"; -import { Point } from "./point"; export const generateFactorKey = (): { private: BN; pub: TkeyPoint } => { const factorKey = new BN(generatePrivate()); @@ -139,15 +138,14 @@ export interface refreshRemoteTssReturnType { * @param tKey - Tkey instance to use. * @param factorPubs - Factor pub keys after refresh. * @param tssIndices - Target tss indices to generate new shares for. - * @param factorKeyForExistingTSSShare - Factor key for existing TSS share. + * @param remoteFactorPub - Factor Pub for remote share. * @param signatures - Signatures for authentication against RSS servers. */ export async function remoteRefreshTssShares( tKey: ThresholdKey, factorPubs: TkeyPoint[], tssIndices: number[], - // to replace with remoteFactorPub - factorKeyForExistingTSSShare: BN, + remoteFactorPub: TkeyPoint, signatures: string[], remoteClientUrl: string, updateMetadata = false @@ -171,12 +169,10 @@ export async function remoteRefreshTssShares( finalSelectedServers = nodeIndexes.slice(0, Math.min(serverEndpoints.length, nodeIndexes.length)); } - // TODO: replace with factorPub Key - const factorKeyStr = factorKeyForExistingTSSShare.toString("hex"); - const point = Point.fromPrivateKey(factorKeyStr).toTkeyPoint(); + const factorEnc = tKey.getFactorEncs(remoteFactorPub); const dataRequired = { - factorEnc: tKey.getFactorEncs(point), + factorEnc, factorPubs: factorPubs.map((pub) => pub.toJSON()), targetIndexes: tssIndices, verifierNameVerifierId, @@ -193,10 +189,7 @@ export async function remoteRefreshTssShares( }, }; - const result = (await post(`${remoteClientUrl}/refresh_tss`, { dataRequired })) as refreshRemoteTssReturnType; - - // eslint-disable-next-line no-console - console.log(result); + const result = (await post(`${remoteClientUrl}/api/mpc/refresh_tss`, { dataRequired })) as refreshRemoteTssReturnType; tKey.metadata.addTSSData({ tssTag: result.tssTag, @@ -217,6 +210,7 @@ export async function addFactorAndRefresh( newFactorTSSIndex: number, factorKeyForExistingTSSShare: BN, signatures: string[], + remoteFactorPub?: TkeyPoint, remoteRefreshUrl?: string ) { if (!tKey) { @@ -238,7 +232,7 @@ export async function addFactorAndRefresh( if (!remoteRefreshUrl) { await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); } else { - await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures, remoteRefreshUrl); + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, remoteFactorPub, signatures, remoteRefreshUrl); } } @@ -247,6 +241,7 @@ export async function deleteFactorAndRefresh( factorPubToDelete: TkeyPoint, factorKeyForExistingTSSShare: BN, signatures: string[], + remoteFactorPub?: TkeyPoint, remoteClientUrl?: string ) { if (!tKey) { @@ -269,7 +264,7 @@ export async function deleteFactorAndRefresh( if (!remoteClientUrl) { await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); } else { - await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures, remoteClientUrl); + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, remoteFactorPub, signatures, remoteClientUrl); } } From 718e3f9e73494a2bfba7e60235e1cfca14b2156e Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 2 Nov 2023 13:27:29 +0800 Subject: [PATCH 3/7] stable: sms authentication integrated --- src/helper/authenticator/smsService.ts | 63 ++++++++++++++++++++++---- src/interfaces.ts | 2 +- src/mpcCoreKit.ts | 36 +++++++-------- src/utils.ts | 23 ++++------ 4 files changed, 81 insertions(+), 43 deletions(-) diff --git a/src/helper/authenticator/smsService.ts b/src/helper/authenticator/smsService.ts index 17d16385..cf94ad85 100644 --- a/src/helper/authenticator/smsService.ts +++ b/src/helper/authenticator/smsService.ts @@ -1,16 +1,50 @@ import { post } from "@toruslabs/http-helpers"; import { keccak256 } from "@toruslabs/metadata-helpers"; +import { log } from "@web3auth/base"; import BN from "bn.js"; import type { ec } from "elliptic"; import { CURVE } from "../../constants"; +import { IRemoteClientState } from "../../interfaces"; +import { Web3AuthMPCCoreKit } from "../../mpcCoreKit"; export class SmsService { private smsbackendUrl: string; - constructor(params: { smsbackendUrl: string }) { + private coreKitInstance: Web3AuthMPCCoreKit; + + private authenticatorType: string = "sms"; + + private factorPub: string = ""; + + private tssIndex: number; + + constructor(params: { smsbackendUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { const { smsbackendUrl } = params; this.smsbackendUrl = smsbackendUrl; + this.authenticatorType = params.authenticatorType || "sms"; + this.coreKitInstance = params.coreKitInstance; + this.getDescriptionsAndUpdate(); + } + + getDescriptionsAndUpdate() { + const arrayOfDescriptions = Object.entries(this.coreKitInstance.getKeyDetails().shareDescriptions).map(([key, value]) => { + const parsedDescription = (value || [])[0] ? JSON.parse(value[0]) : {}; + return { + key, + description: parsedDescription, + }; + }); + + const shareDescriptionsMobile = arrayOfDescriptions.find(({ description }) => description.authenticator === this.authenticatorType); + log.info("shareDescriptionsMobile", shareDescriptionsMobile); + + if (shareDescriptionsMobile) { + this.factorPub = shareDescriptionsMobile.key; + this.tssIndex = shareDescriptionsMobile.description.tssShareIndex; + } + + return shareDescriptionsMobile; } async registerSmsOTP(privKey: BN, number: string): Promise { @@ -31,11 +65,13 @@ export class SmsService { number, }; + // eslint-disable-next-line no-console + console.log(data); await post<{ success: boolean; id_token?: string; message: string; - }>(`${this.smsbackendUrl}/register`, data); + }>(`${this.smsbackendUrl}/api/v1/register`, data); // this is to send sms to the user instantly after registration. const startData = { @@ -43,7 +79,7 @@ export class SmsService { }; // Sends the user sms. - const resp2 = await post<{ success: boolean; code?: string }>(`${this.smsbackendUrl}/start`, startData); + const resp2 = await post<{ success: boolean; code?: string }>(`${this.smsbackendUrl}/api/v1/start`, startData); // if (resp2.status !== 200) throw new Error("Error sending sms"); return resp2.code; } @@ -62,14 +98,16 @@ export class SmsService { }, }; - await post(`${this.smsbackendUrl}/verify`, data); + await post(`${this.smsbackendUrl}/api/v1/verify`, data); } async requestSMSOTP(address: string): Promise { const startData = { address, }; - const resp2 = await post<{ success?: boolean; code?: string }>(`${this.smsbackendUrl}/start`, startData); + const resp2 = await post<{ success?: boolean; code?: string }>(`${this.smsbackendUrl}/api/v1/start`, startData); + // eslint-disable-next-line no-console + console.log(resp2); return resp2.code; } @@ -79,19 +117,26 @@ export class SmsService { code, }; - const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/api/v1/verify`, verificationData); const { data } = response; return data ? new BN(data.factorKey, "hex") : undefined; } - async verifySMSOTPRemote(address: string, code: string): Promise { + async verifySMSOTPRemote(address: string, code: string): Promise { const verificationData = { address, code, }; - const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/api/v1/verify_remote`, verificationData); const { data } = response; - return data ? new BN(data.factorKey, "hex") : undefined; + + return { + tssShareIndex: this.tssIndex.toString(), + remoteClientUrl: this.smsbackendUrl, + remoteFactorPub: this.factorPub, + metadataShare: data.metadataShare, + remoteClientToken: data.signature, + }; } } diff --git a/src/interfaces.ts b/src/interfaces.ts index 8d065a35..0adcc752 100644 --- a/src/interfaces.ts +++ b/src/interfaces.ts @@ -120,7 +120,7 @@ export interface IdTokenLoginParams { export interface IRemoteClientState { remoteFactorPub: string; remoteClientUrl: string; - signature: string; + remoteClientToken: string; metadataShare: string; } diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 0f2f3b84..8c84669f 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -259,6 +259,8 @@ export class Web3AuthMPCCoreKit implements ICoreKit { nodePubKeys: nodeDetails.torusNodePub.map((i) => ({ x: i.X, y: i.Y })), }); + // eslint-disable-next-line no-console + console.log("nodeDetails", nodeDetails.torusNodeEndpoints); this.storageLayer = new TorusStorageLayer({ hostUrl: `${new URL(nodeDetails.torusNodeEndpoints[0]).origin}/metadata`, enableLogging: this.enableLogging, @@ -681,8 +683,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { factorPub, new BN(0), // not used in remoteClient this.signatures, - TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub), - this.state.remoteClient.remoteClientUrl + this.state.remoteClient ); } else { const stateFpp = Point.fromTkeyPoint(getPubKeyPoint(this.state.factorKey)); @@ -777,23 +778,23 @@ export class Web3AuthMPCCoreKit implements ICoreKit { remoteClientUrl: string; remoteFactorPub: string; metadataShare: string; - signature: string; + remoteClientToken: string; tssShareIndex: string; }): Promise> { - const { remoteClientUrl, remoteFactorPub, metadataShare, signature, tssShareIndex } = params; + const { remoteClientUrl, remoteFactorPub, metadataShare, remoteClientToken, tssShareIndex } = params; const remoteClient = { remoteClientUrl: remoteClientUrl.at(-1) === "/" ? remoteClientUrl.slice(0, -1) : remoteClientUrl, remoteFactorPub, metadataShare, - signature, + remoteClientToken, }; const sharestore = ShareStore.fromJSON(JSON.parse(metadataShare)); this.tkey.inputShareStoreSafe(sharestore); await this.tKey.reconstructKey(); log.info(metadataShare); - log.info(signature); + log.info(remoteClientToken); // setup Tkey const tssPubKey = Point.fromTkeyPoint(this.tKey.getTSSPub()).toBufferSEC1(false); @@ -1032,15 +1033,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { if (!this.state.remoteClient) { await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures); } else { - await addFactorAndRefresh( - this.tKey, - newFactorPub, - newFactorTSSIndex, - this.state.factorKey, - this.signatures, - TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub), - this.state.remoteClient.remoteClientUrl - ); + await addFactorAndRefresh(this.tKey, newFactorPub, newFactorTSSIndex, this.state.factorKey, this.signatures, this.state.remoteClient); } return; } @@ -1056,7 +1049,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { factorPub: newFactorPub, }; - userEnc = (await post(`${this.state.remoteClient.remoteClientUrl}/api/mpc/copy_tss_share`, { dataRequired })) as EncryptedMessage; + userEnc = (await post<{ data?: EncryptedMessage }>(`${this.state.remoteClient.remoteClientUrl}/api/mpc/copy_tss_share`, { dataRequired })).data; } else { const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); userEnc = await encrypt(Point.fromTkeyPoint(newFactorPub).toBufferSEC1(false), scalarBNToBufferSEC1(tssShare)); @@ -1240,9 +1233,12 @@ export class Web3AuthMPCCoreKit implements ICoreKit { msgHash: msgHash.toString("hex"), }; - const result = await post(`${this.state.remoteClient.remoteClientUrl}/api/mpc/sign`, data); - const { r, s, v } = result as { v: number; r: string; s: string }; - - return { v, r: Buffer.from(r, "hex"), s: Buffer.from(s, "hex") }; + const result = await post<{ data?: Record }>(`${this.state.remoteClient.remoteClientUrl}/api/mpc/sign`, data, { + headers: { + token: this.state.remoteClient.remoteClientToken, + }, + }); + const { r, s, v } = result.data as { v: string; r: string; s: string }; + return { v: parseInt(v), r: Buffer.from(r, "hex"), s: Buffer.from(s, "hex") }; } } diff --git a/src/utils.ts b/src/utils.ts index 0c030f6f..a97201f6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -7,7 +7,7 @@ import type { PointHex } from "@toruslabs/tss-client/dist/types/types"; import BN from "bn.js"; import { SCALAR_LEN, VALID_SHARE_INDICES as VALID_TSS_INDICES } from "./constants"; -import { UserInfo, Web3AuthState } from "./interfaces"; +import { IRemoteClientState, UserInfo, Web3AuthState } from "./interfaces"; export const generateFactorKey = (): { private: BN; pub: TkeyPoint } => { const factorKey = new BN(generatePrivate()); @@ -145,9 +145,8 @@ export async function remoteRefreshTssShares( tKey: ThresholdKey, factorPubs: TkeyPoint[], tssIndices: number[], - remoteFactorPub: TkeyPoint, signatures: string[], - remoteClientUrl: string, + remoteClient: IRemoteClientState, updateMetadata = false ) { // const { tssShare, tssIndex } = await tKey.getTSSShare(factorKeyForExistingTSSShare); @@ -169,7 +168,7 @@ export async function remoteRefreshTssShares( finalSelectedServers = nodeIndexes.slice(0, Math.min(serverEndpoints.length, nodeIndexes.length)); } - const factorEnc = tKey.getFactorEncs(remoteFactorPub); + const factorEnc = tKey.getFactorEncs(TkeyPoint.fromCompressedPub(remoteClient.remoteFactorPub)); const dataRequired = { factorEnc, @@ -189,7 +188,7 @@ export async function remoteRefreshTssShares( }, }; - const result = (await post(`${remoteClientUrl}/api/mpc/refresh_tss`, { dataRequired })) as refreshRemoteTssReturnType; + const result = (await post<{ data: refreshRemoteTssReturnType }>(`${remoteClient.remoteClientUrl}/api/mpc/refresh_tss`, { dataRequired })).data; tKey.metadata.addTSSData({ tssTag: result.tssTag, @@ -210,8 +209,7 @@ export async function addFactorAndRefresh( newFactorTSSIndex: number, factorKeyForExistingTSSShare: BN, signatures: string[], - remoteFactorPub?: TkeyPoint, - remoteRefreshUrl?: string + remoteClient?: IRemoteClientState ) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); @@ -229,10 +227,10 @@ export async function addFactorAndRefresh( const existingTSSIndexes = existingFactorPubs.map((fb) => tKey.getFactorEncs(fb).tssIndex); const updatedTSSIndexes = existingTSSIndexes.concat([newFactorTSSIndex]); - if (!remoteRefreshUrl) { + if (!remoteClient) { await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); } else { - await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, remoteFactorPub, signatures, remoteRefreshUrl); + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, signatures, remoteClient); } } @@ -241,8 +239,7 @@ export async function deleteFactorAndRefresh( factorPubToDelete: TkeyPoint, factorKeyForExistingTSSShare: BN, signatures: string[], - remoteFactorPub?: TkeyPoint, - remoteClientUrl?: string + remoteClient?: IRemoteClientState ) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); @@ -261,10 +258,10 @@ export async function deleteFactorAndRefresh( updatedFactorPubs.splice(factorIndex, 1); const updatedTSSIndexes = updatedFactorPubs.map((fb) => tKey.getFactorEncs(fb).tssIndex); - if (!remoteClientUrl) { + if (!remoteClient) { await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); } else { - await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, remoteFactorPub, signatures, remoteClientUrl); + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, signatures, remoteClient); } } From e1dd2e83416b074ea08472597953813620bb6644 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 2 Nov 2023 17:32:11 +0800 Subject: [PATCH 4/7] fix: authenticator remote setup --- .../authenticator/authenticatorService.ts | 53 ++++++++++++++++--- src/helper/authenticator/smsService.ts | 2 +- 2 files changed, 46 insertions(+), 9 deletions(-) diff --git a/src/helper/authenticator/authenticatorService.ts b/src/helper/authenticator/authenticatorService.ts index cc7f53de..d7fec014 100644 --- a/src/helper/authenticator/authenticatorService.ts +++ b/src/helper/authenticator/authenticatorService.ts @@ -1,23 +1,53 @@ import { generatePrivate } from "@toruslabs/eccrypto"; import { post } from "@toruslabs/http-helpers"; import { keccak256 } from "@toruslabs/metadata-helpers"; +import { log } from "@web3auth/base"; import BN from "bn.js"; import type { ec } from "elliptic"; import base32 from "hi-base32"; import { CURVE } from "../../constants"; +import { IRemoteClientState, Web3AuthMPCCoreKit } from "../../index"; export class AuthenticatorService { private authenticatorUrl: string; - // private remoteClient: boolean = false; + private coreKitInstance: Web3AuthMPCCoreKit; - constructor(params: { authenticatorUrl: string }) { + private authenticatorType: string = "authenticator"; + + private factorPub: string = ""; + + private tssIndex: number; + + constructor(params: { authenticatorUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { const { authenticatorUrl } = params; this.authenticatorUrl = authenticatorUrl; + this.authenticatorType = params.authenticatorType || "authenticator"; + this.coreKitInstance = params.coreKitInstance; // this.remoteClient = remoteClient || false; } + getDescriptionsAndUpdate() { + const arrayOfDescriptions = Object.entries(this.coreKitInstance.getKeyDetails().shareDescriptions).map(([key, value]) => { + const parsedDescription = (value || [])[0] ? JSON.parse(value[0]) : {}; + return { + key, + description: parsedDescription, + }; + }); + + const shareDescriptionsMobile = arrayOfDescriptions.find(({ description }) => description.authenticator === this.authenticatorType); + log.info("shareDescriptionsMobile", shareDescriptionsMobile); + + if (shareDescriptionsMobile) { + this.factorPub = shareDescriptionsMobile.key; + this.tssIndex = shareDescriptionsMobile.description.tssShareIndex; + } + + return shareDescriptionsMobile; + } + generateSecretKey(): string { const key = generatePrivate().subarray(0, 20); return base32.encode(key).toString().replace(/=/g, ""); @@ -44,7 +74,7 @@ export class AuthenticatorService { const resp = await post<{ success: boolean; message: string; - }>(`${this.authenticatorUrl}/register`, data); + }>(`${this.authenticatorUrl}/api/v1/register`, data); return resp; } @@ -64,7 +94,7 @@ export class AuthenticatorService { }, }; - await post(`${this.authenticatorUrl}/verify`, data); + await post(`${this.authenticatorUrl}/api/v1/verify`, data); } async verifyAuthenticatorRecovery(address: string, code: string): Promise { @@ -73,19 +103,26 @@ export class AuthenticatorService { code, }; - const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/api/v1/verify`, verificationData); const { data } = response; return data ? new BN(data.factorKey, "hex") : undefined; } - async verifyAuthenticatorRemoteSetup(address: string, code: string): Promise { + async verifyRemoteSetup(address: string, code: string): Promise { const verificationData = { address, code, }; - const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/api/v1/verify_remote`, verificationData); const { data } = response; - return data ? new BN(data.factorKey, "hex") : undefined; + + return { + tssShareIndex: this.tssIndex.toString(), + remoteClientUrl: this.authenticatorUrl, + remoteFactorPub: this.factorPub, + metadataShare: data.metadataShare, + remoteClientToken: data.signature, + }; } } diff --git a/src/helper/authenticator/smsService.ts b/src/helper/authenticator/smsService.ts index cf94ad85..ee32e401 100644 --- a/src/helper/authenticator/smsService.ts +++ b/src/helper/authenticator/smsService.ts @@ -122,7 +122,7 @@ export class SmsService { return data ? new BN(data.factorKey, "hex") : undefined; } - async verifySMSOTPRemote(address: string, code: string): Promise { + async verifyRemoteSetup(address: string, code: string): Promise { const verificationData = { address, code, From cf48efbbbf422c78156fed51a2b0328f98a6adae Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 2 Nov 2023 17:45:49 +0800 Subject: [PATCH 5/7] fix: use authorization header for token --- src/mpcCoreKit.ts | 16 ++++++++++++---- src/utils.ts | 12 +++++++++++- 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 8c84669f..d05caf9e 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -793,8 +793,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit { const sharestore = ShareStore.fromJSON(JSON.parse(metadataShare)); this.tkey.inputShareStoreSafe(sharestore); await this.tKey.reconstructKey(); - log.info(metadataShare); - log.info(remoteClientToken); // setup Tkey const tssPubKey = Point.fromTkeyPoint(this.tKey.getTSSPub()).toBufferSEC1(false); @@ -1049,7 +1047,17 @@ export class Web3AuthMPCCoreKit implements ICoreKit { factorPub: newFactorPub, }; - userEnc = (await post<{ data?: EncryptedMessage }>(`${this.state.remoteClient.remoteClientUrl}/api/mpc/copy_tss_share`, { dataRequired })).data; + userEnc = ( + await post<{ data?: EncryptedMessage }>( + `${this.state.remoteClient.remoteClientUrl}/api/mpc/copy_tss_share`, + { dataRequired }, + { + headers: { + Authorization: `Bearer ${this.state.remoteClient.remoteClientToken}`, + }, + } + ) + ).data; } else { const { tssShare } = await this.tKey.getTSSShare(this.state.factorKey); userEnc = await encrypt(Point.fromTkeyPoint(newFactorPub).toBufferSEC1(false), scalarBNToBufferSEC1(tssShare)); @@ -1235,7 +1243,7 @@ export class Web3AuthMPCCoreKit implements ICoreKit { const result = await post<{ data?: Record }>(`${this.state.remoteClient.remoteClientUrl}/api/mpc/sign`, data, { headers: { - token: this.state.remoteClient.remoteClientToken, + Authorization: `Bearer ${this.state.remoteClient.remoteClientToken}`, }, }); const { r, s, v } = result.data as { v: string; r: string; s: string }; diff --git a/src/utils.ts b/src/utils.ts index a97201f6..cb0329e6 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -188,7 +188,17 @@ export async function remoteRefreshTssShares( }, }; - const result = (await post<{ data: refreshRemoteTssReturnType }>(`${remoteClient.remoteClientUrl}/api/mpc/refresh_tss`, { dataRequired })).data; + const result = ( + await post<{ data: refreshRemoteTssReturnType }>( + `${remoteClient.remoteClientUrl}/api/mpc/refresh_tss`, + { dataRequired }, + { + headers: { + Authorization: `Bearer ${remoteClient.remoteClientToken}`, + }, + } + ) + ).data; tKey.metadata.addTSSData({ tssTag: result.tssTag, From 266146e696051e403439ddf41a371d0bfc75b494 Mon Sep 17 00:00:00 2001 From: ieow Date: Thu, 2 Nov 2023 17:56:08 +0800 Subject: [PATCH 6/7] chore: cleanup --- .../authenticator/authenticatorService.ts | 18 +++++++------- src/helper/authenticator/smsService.ts | 24 +++++++++---------- src/mpcCoreKit.ts | 2 -- src/utils.ts | 2 -- 4 files changed, 20 insertions(+), 26 deletions(-) diff --git a/src/helper/authenticator/authenticatorService.ts b/src/helper/authenticator/authenticatorService.ts index d7fec014..67273fff 100644 --- a/src/helper/authenticator/authenticatorService.ts +++ b/src/helper/authenticator/authenticatorService.ts @@ -10,7 +10,7 @@ import { CURVE } from "../../constants"; import { IRemoteClientState, Web3AuthMPCCoreKit } from "../../index"; export class AuthenticatorService { - private authenticatorUrl: string; + private backendUrl: string; private coreKitInstance: Web3AuthMPCCoreKit; @@ -20,9 +20,9 @@ export class AuthenticatorService { private tssIndex: number; - constructor(params: { authenticatorUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { - const { authenticatorUrl } = params; - this.authenticatorUrl = authenticatorUrl; + constructor(params: { backendUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { + const { backendUrl } = params; + this.backendUrl = backendUrl; this.authenticatorType = params.authenticatorType || "authenticator"; this.coreKitInstance = params.coreKitInstance; // this.remoteClient = remoteClient || false; @@ -74,7 +74,7 @@ export class AuthenticatorService { const resp = await post<{ success: boolean; message: string; - }>(`${this.authenticatorUrl}/api/v1/register`, data); + }>(`${this.backendUrl}/api/v1/register`, data); return resp; } @@ -94,7 +94,7 @@ export class AuthenticatorService { }, }; - await post(`${this.authenticatorUrl}/api/v1/verify`, data); + await post(`${this.backendUrl}/api/v1/verify`, data); } async verifyAuthenticatorRecovery(address: string, code: string): Promise { @@ -103,7 +103,7 @@ export class AuthenticatorService { code, }; - const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/api/v1/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify`, verificationData); const { data } = response; return data ? new BN(data.factorKey, "hex") : undefined; } @@ -114,12 +114,12 @@ export class AuthenticatorService { code, }; - const response = await post<{ data?: Record }>(`${this.authenticatorUrl}/api/v1/verify_remote`, verificationData); + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify_remote`, verificationData); const { data } = response; return { tssShareIndex: this.tssIndex.toString(), - remoteClientUrl: this.authenticatorUrl, + remoteClientUrl: this.backendUrl, remoteFactorPub: this.factorPub, metadataShare: data.metadataShare, remoteClientToken: data.signature, diff --git a/src/helper/authenticator/smsService.ts b/src/helper/authenticator/smsService.ts index ee32e401..cab0e6a1 100644 --- a/src/helper/authenticator/smsService.ts +++ b/src/helper/authenticator/smsService.ts @@ -9,7 +9,7 @@ import { IRemoteClientState } from "../../interfaces"; import { Web3AuthMPCCoreKit } from "../../mpcCoreKit"; export class SmsService { - private smsbackendUrl: string; + private backendUrl: string; private coreKitInstance: Web3AuthMPCCoreKit; @@ -19,9 +19,9 @@ export class SmsService { private tssIndex: number; - constructor(params: { smsbackendUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { - const { smsbackendUrl } = params; - this.smsbackendUrl = smsbackendUrl; + constructor(params: { backendUrl: string; coreKitInstance: Web3AuthMPCCoreKit; authenticatorType?: string }) { + const { backendUrl } = params; + this.backendUrl = backendUrl; this.authenticatorType = params.authenticatorType || "sms"; this.coreKitInstance = params.coreKitInstance; this.getDescriptionsAndUpdate(); @@ -65,13 +65,11 @@ export class SmsService { number, }; - // eslint-disable-next-line no-console - console.log(data); await post<{ success: boolean; id_token?: string; message: string; - }>(`${this.smsbackendUrl}/api/v1/register`, data); + }>(`${this.backendUrl}/api/v1/register`, data); // this is to send sms to the user instantly after registration. const startData = { @@ -79,7 +77,7 @@ export class SmsService { }; // Sends the user sms. - const resp2 = await post<{ success: boolean; code?: string }>(`${this.smsbackendUrl}/api/v1/start`, startData); + const resp2 = await post<{ success: boolean; code?: string }>(`${this.backendUrl}/api/v1/start`, startData); // if (resp2.status !== 200) throw new Error("Error sending sms"); return resp2.code; } @@ -98,14 +96,14 @@ export class SmsService { }, }; - await post(`${this.smsbackendUrl}/api/v1/verify`, data); + await post(`${this.backendUrl}/api/v1/verify`, data); } async requestSMSOTP(address: string): Promise { const startData = { address, }; - const resp2 = await post<{ success?: boolean; code?: string }>(`${this.smsbackendUrl}/api/v1/start`, startData); + const resp2 = await post<{ success?: boolean; code?: string }>(`${this.backendUrl}/api/v1/start`, startData); // eslint-disable-next-line no-console console.log(resp2); return resp2.code; @@ -117,7 +115,7 @@ export class SmsService { code, }; - const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/api/v1/verify`, verificationData); + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify`, verificationData); const { data } = response; return data ? new BN(data.factorKey, "hex") : undefined; } @@ -128,12 +126,12 @@ export class SmsService { code, }; - const response = await post<{ data?: Record }>(`${this.smsbackendUrl}/api/v1/verify_remote`, verificationData); + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify_remote`, verificationData); const { data } = response; return { tssShareIndex: this.tssIndex.toString(), - remoteClientUrl: this.smsbackendUrl, + remoteClientUrl: this.backendUrl, remoteFactorPub: this.factorPub, metadataShare: data.metadataShare, remoteClientToken: data.signature, diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index d05caf9e..488f3df5 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -259,8 +259,6 @@ export class Web3AuthMPCCoreKit implements ICoreKit { nodePubKeys: nodeDetails.torusNodePub.map((i) => ({ x: i.X, y: i.Y })), }); - // eslint-disable-next-line no-console - console.log("nodeDetails", nodeDetails.torusNodeEndpoints); this.storageLayer = new TorusStorageLayer({ hostUrl: `${new URL(nodeDetails.torusNodeEndpoints[0]).origin}/metadata`, enableLogging: this.enableLogging, diff --git a/src/utils.ts b/src/utils.ts index cb0329e6..0c18d05c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -296,8 +296,6 @@ export function Web3AuthStateFromJSON(result: StringifiedType): Web3AuthState { if (!result.factorKey) throw new Error("factorKey not found in JSON"); if (!result.tssShareIndex) throw new Error("tssShareIndex not found in JSON"); - // eslint-disable-next-line no-console - console.log(result.tssPubKey); const factorKey = new BN(result.factorKey as string, "hex"); const tssPubKey = Buffer.from(result.tssPubKey as Buffer); return { From f6845f3333ba27cfdeb8d828058a246b69f50e47 Mon Sep 17 00:00:00 2001 From: ieow Date: Tue, 7 Nov 2023 15:59:03 +0800 Subject: [PATCH 7/7] fix: rehydration --- src/mpcCoreKit.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/mpcCoreKit.ts b/src/mpcCoreKit.ts index 488f3df5..ac24d564 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -911,17 +911,24 @@ export class Web3AuthMPCCoreKit implements ICoreKit { if (!this.sessionManager.sessionId) return {}; const result = await this.sessionManager.authorizeSession(); - const factorKey = new BN(result.factorKey, "hex"); - if (!factorKey) { - throw new Error("Invalid factor key"); + if (!result.factorKey && !result.remoteClient) throw new Error("factorKey not present"); + let metadataShare; + + if (result.factorKey) { + const factorKey = new BN(result.factorKey, "hex"); + if (!factorKey) { + throw new Error("Invalid factor key"); + } + metadataShare = await this.getFactorKeyMetadata(factorKey); + } else { + metadataShare = ShareStore.fromJSON(JSON.parse(result.remoteClient.metadataShare)); } this.torusSp.postboxKey = new BN(result.oAuthKey, "hex"); this.torusSp.verifierName = result.userInfo.aggregateVerifier || result.userInfo.verifier; this.torusSp.verifierId = result.userInfo.verifierId; this.torusSp.verifierType = result.userInfo.aggregateVerifier ? "aggregate" : "normal"; - const factorKeyMetadata = await this.getFactorKeyMetadata(factorKey); await this.tKey.initialize({ neverInitializeNewKey: true }); - await this.tKey.inputShareStoreSafe(factorKeyMetadata, true); + await this.tKey.inputShareStoreSafe(metadataShare, true); await this.tKey.reconstructKey(); this.updateState({