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 54e0b80a..4e24a43d 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,8 @@ "@toruslabs/eccrypto": "4.0.0", "@toruslabs/fetch-node-details": "^13.0.1", "@toruslabs/fnd-base": "^13.0.1", - "@toruslabs/metadata-helpers": "^5.x", + "@toruslabs/http-helpers": "^5.0.0", + "@toruslabs/metadata-helpers": "^4.x", "@toruslabs/openlogin-session-manager": "^3.0.0", "@toruslabs/torus.js": "^11.0.6", "@toruslabs/tss-client": "^1.7.1", @@ -57,18 +58,19 @@ "@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": "^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/helper/authenticator/authenticatorService.ts b/src/helper/authenticator/authenticatorService.ts new file mode 100644 index 00000000..67273fff --- /dev/null +++ b/src/helper/authenticator/authenticatorService.ts @@ -0,0 +1,128 @@ +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 backendUrl: string; + + private coreKitInstance: Web3AuthMPCCoreKit; + + private authenticatorType: string = "authenticator"; + + private factorPub: string = ""; + + private tssIndex: number; + + 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; + } + + 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, ""); + } + + 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.backendUrl}/api/v1/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.backendUrl}/api/v1/verify`, data); + } + + async verifyAuthenticatorRecovery(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } + + async verifyRemoteSetup(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify_remote`, verificationData); + const { data } = response; + + return { + tssShareIndex: this.tssIndex.toString(), + 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 new file mode 100644 index 00000000..cab0e6a1 --- /dev/null +++ b/src/helper/authenticator/smsService.ts @@ -0,0 +1,140 @@ +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 backendUrl: string; + + private coreKitInstance: Web3AuthMPCCoreKit; + + private authenticatorType: string = "sms"; + + private factorPub: string = ""; + + private tssIndex: number; + + 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(); + } + + 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 { + 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.backendUrl}/api/v1/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.backendUrl}/api/v1/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.backendUrl}/api/v1/verify`, data); + } + + async requestSMSOTP(address: string): Promise { + const startData = { + address, + }; + 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; + } + + async verifySMSOTPRecovery(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify`, verificationData); + const { data } = response; + return data ? new BN(data.factorKey, "hex") : undefined; + } + + async verifyRemoteSetup(address: string, code: string): Promise { + const verificationData = { + address, + code, + }; + + const response = await post<{ data?: Record }>(`${this.backendUrl}/api/v1/verify_remote`, verificationData); + const { data } = response; + + return { + tssShareIndex: this.tssIndex.toString(), + remoteClientUrl: this.backendUrl, + remoteFactorPub: this.factorPub, + metadataShare: data.metadataShare, + remoteClientToken: data.signature, + }; + } +} 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..0adcc752 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; + remoteClientToken: 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 4844e4f4..ac24d564 100644 --- a/src/mpcCoreKit.ts +++ b/src/mpcCoreKit.ts @@ -1,12 +1,22 @@ /* 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"; 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"; @@ -59,7 +69,6 @@ import { getHashedPrivateKey, parseToken, scalarBNToBufferSEC1, - Web3AuthStateFromJSON, } from "./utils"; export class Web3AuthMPCCoreKit implements ICoreKit { @@ -173,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; @@ -285,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 } @@ -430,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 @@ -452,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 { @@ -516,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")); }; @@ -566,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({ @@ -647,17 +665,32 @@ 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, + this.state.remoteClient + ); + } 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); const factorPubHex = fpp.toBufferSEC1(true).toString("hex"); const allDesc = this.tKey.metadata.getShareDescription(); const keyDesc = allDesc[factorPubHex]; @@ -717,7 +750,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() @@ -739,6 +772,36 @@ export class Web3AuthMPCCoreKit implements ICoreKit { this.tKey.manualSync = manualSync; } + public async setupRemoteClient(params: { + remoteClientUrl: string; + remoteFactorPub: string; + metadataShare: string; + remoteClientToken: string; + tssShareIndex: string; + }): Promise> { + const { remoteClientUrl, remoteFactorPub, metadataShare, remoteClientToken, tssShareIndex } = params; + + const remoteClient = { + remoteClientUrl: remoteClientUrl.at(-1) === "/" ? remoteClientUrl.slice(0, -1) : remoteClientUrl, + remoteFactorPub, + metadataShare, + remoteClientToken, + }; + + const sharestore = ShareStore.fromJSON(JSON.parse(metadataShare)); + this.tkey.inputShareStoreSafe(sharestore); + await this.tKey.reconstructKey(); + + // 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 { @@ -749,6 +812,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"); @@ -768,6 +832,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"); } @@ -843,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({ @@ -863,6 +938,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); @@ -878,11 +954,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, @@ -891,6 +970,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); @@ -941,7 +1021,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) { @@ -952,28 +1032,49 @@ 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); - - // 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, this.state.remoteClient); + } 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<{ 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)); + } - 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({ @@ -982,7 +1083,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 { @@ -1061,42 +1162,96 @@ 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; + // 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.updateState({ - oAuthKey, - userInfo: { verifier, verifierId } as UserInfo, - signatures, + // PreSetup + const { torusNodeTSSEndpoints } = await this.nodeDetailManager.getNodeDetails({ + verifier: "test-verifier", + verifierId: "test@example.com", }); - await this.setupTkey(importTssKey); - } - public async serverSetupRehydrate({ state, tkeyJson }: { state: StringifiedType; tkeyJson: StringifiedType }) { - this.state = Web3AuthStateFromJSON(state); + const tssCommits = this.tKey.getTSSCommits(); - const metadata = Metadata.fromJSON(tkeyJson.metadata); - this.tKey.metadata = metadata; + const tssNonce = this.getTssNonce() || 0; - 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; - } + 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] + ); + + if (parties - 1 > nodeIndexes.length) { + throw new Error(`Not enough nodes to perform TSS - parties :${parties}, nodeIndexes:${nodeIndexes.length}`); } - this.tkey.privKey = new BN(tkeyJson.privKey, "hex"); + const { endpoints, tssWSEndpoints, partyIndexes } = generateTSSEndpoints(torusNodeTSSEndpoints, parties, clientIndex, nodeIndexes); + + const factor = TkeyPoint.fromCompressedPub(this.state.remoteClient.remoteFactorPub); + const factorEnc = this.tKey.getFactorEncs(factor); - (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; + const data = { + dataRequired: { + factorEnc, + sessionId, + tssNonce, + nodeIndexes: nodeIndexes.slice(0, parties - 1), + tssCommits: tssCommits.map((commit) => commit.toJSON()), + signatures: this.signatures, + serverEndpoints: { endpoints, tssWSEndpoints, partyIndexes }, + }, + msgHash: msgHash.toString("hex"), + }; + + const result = await post<{ data?: Record }>(`${this.state.remoteClient.remoteClientUrl}/api/mpc/sign`, data, { + headers: { + Authorization: `Bearer ${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 30a90d2d..0c18d05c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -1,11 +1,13 @@ -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 { IRemoteClientState, UserInfo, Web3AuthState } from "./interfaces"; export const generateFactorKey = (): { private: BN; pub: TkeyPoint } => { const factorKey = new BN(generatePrivate()); @@ -72,9 +74,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 +101,125 @@ 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 remoteFactorPub - Factor Pub for remote share. + * @param signatures - Signatures for authentication against RSS servers. + */ +export async function remoteRefreshTssShares( + tKey: ThresholdKey, + factorPubs: TkeyPoint[], + tssIndices: number[], + signatures: string[], + remoteClient: IRemoteClientState, + 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)); + } + + const factorEnc = tKey.getFactorEncs(TkeyPoint.fromCompressedPub(remoteClient.remoteFactorPub)); + + const dataRequired = { + factorEnc, + 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<{ data: refreshRemoteTssReturnType }>( + `${remoteClient.remoteClientUrl}/api/mpc/refresh_tss`, + { dataRequired }, + { + headers: { + Authorization: `Bearer ${remoteClient.remoteClientToken}`, + }, + } + ) + ).data; + + 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[], + remoteClient?: IRemoteClientState ) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); @@ -122,10 +237,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 (!remoteClient) { + await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + } else { + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, signatures, remoteClient); + } } -export async function deleteFactorAndRefresh(tKey: ThresholdKey, factorPubToDelete: Point, factorKeyForExistingTSSShare: BN, signatures: string[]) { +export async function deleteFactorAndRefresh( + tKey: ThresholdKey, + factorPubToDelete: TkeyPoint, + factorKeyForExistingTSSShare: BN, + signatures: string[], + remoteClient?: IRemoteClientState +) { if (!tKey) { throw new Error("tkey does not exist, cannot add factor pub"); } @@ -143,7 +268,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 (!remoteClient) { + await refreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, factorKeyForExistingTSSShare, signatures); + } else { + await remoteRefreshTssShares(tKey, updatedFactorPubs, updatedTSSIndexes, signatures, remoteClient); + } } export const getHashedPrivateKey = (postboxKey: string, clientId: string): BN => { @@ -167,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 {