Skip to content

Commit

Permalink
feat: enable manualSync, commit MFA changes in batches (#2600)
Browse files Browse the repository at this point in the history
Co-authored-by: Usame Algan <[email protected]>
  • Loading branch information
schmanu and usame-algan authored Oct 9, 2023
1 parent e682af6 commit 5ab369e
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 71 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
"@web3-onboard/ledger": "2.3.2",
"@web3-onboard/trezor": "^2.4.2",
"@web3-onboard/walletconnect": "^2.4.7",
"@web3auth/mpc-core-kit": "^1.0.2",
"@web3auth/mpc-core-kit": "^1.1.0",
"blo": "^1.1.1",
"bn.js": "^5.2.1",
"classnames": "^2.3.1",
Expand Down
32 changes: 7 additions & 25 deletions src/components/settings/SignerAccountMFA/PasswordForm.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,33 @@
import { DeviceShareRecovery } from '@/hooks/wallets/mpc/recovery/DeviceShareRecovery'
import { SecurityQuestionRecovery } from '@/hooks/wallets/mpc/recovery/SecurityQuestionRecovery'
import { Typography, TextField, FormControlLabel, Checkbox, Button, Box } from '@mui/material'
import { Typography, TextField, Button, Box } from '@mui/material'
import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
import { useState, useMemo } from 'react'
import { Controller, useForm } from 'react-hook-form'
import { useForm } from 'react-hook-form'
import { enableMFA } from './helper'

enum PasswordFieldNames {
oldPassword = 'oldPassword',
newPassword = 'newPassword',
confirmPassword = 'confirmPassword',
storeDeviceShare = 'storeDeviceShare',
}

type PasswordFormData = {
[PasswordFieldNames.oldPassword]: string | undefined
[PasswordFieldNames.newPassword]: string
[PasswordFieldNames.confirmPassword]: string
[PasswordFieldNames.storeDeviceShare]: boolean
}

export const PasswordForm = ({ mpcCoreKit }: { mpcCoreKit: Web3AuthMPCCoreKit }) => {
const formMethods = useForm<PasswordFormData>({
mode: 'all',
defaultValues: async () => {
const isDeviceShareStored = await new DeviceShareRecovery(mpcCoreKit).isEnabled()
return {
[PasswordFieldNames.confirmPassword]: '',
[PasswordFieldNames.oldPassword]: undefined,
[PasswordFieldNames.newPassword]: '',
[PasswordFieldNames.storeDeviceShare]: isDeviceShareStored,
}
defaultValues: {
[PasswordFieldNames.confirmPassword]: '',
[PasswordFieldNames.oldPassword]: undefined,
[PasswordFieldNames.newPassword]: '',
},
})

const { register, formState, getValues, control, handleSubmit } = formMethods
const { register, formState, getValues, handleSubmit } = formMethods

const [enablingMFA, setEnablingMFA] = useState(false)

Expand Down Expand Up @@ -100,17 +93,6 @@ export const PasswordForm = ({ mpcCoreKit }: { mpcCoreKit: Web3AuthMPCCoreKit })
})}
/>

<Controller
control={control}
name={PasswordFieldNames.storeDeviceShare}
render={({ field: { value, ...field } }) => (
<FormControlLabel
control={<Checkbox checked={value ?? false} {...field} />}
label="Do not ask for second factor on this device"
/>
)}
/>

<Button
sx={{ justifySelf: 'flex-start' }}
disabled={!formMethods.formState.isValid || enablingMFA}
Expand Down
25 changes: 2 additions & 23 deletions src/components/settings/SignerAccountMFA/helper.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,8 @@
import { DeviceShareRecovery } from '@/hooks/wallets/mpc/recovery/DeviceShareRecovery'
import { SecurityQuestionRecovery } from '@/hooks/wallets/mpc/recovery/SecurityQuestionRecovery'
import { logError } from '@/services/exceptions'
import ErrorCodes from '@/services/exceptions/ErrorCodes'
import { asError } from '@/services/exceptions/utils'
import { getPubKeyPoint } from '@tkey-mpc/common-types'
import { type Web3AuthMPCCoreKit } from '@web3auth/mpc-core-kit'
import BN from 'bn.js'

export const isMFAEnabled = (mpcCoreKit: Web3AuthMPCCoreKit) => {
if (!mpcCoreKit) {
Expand All @@ -20,18 +17,15 @@ export const enableMFA = async (
{
newPassword,
oldPassword,
storeDeviceShare,
}: {
newPassword: string
oldPassword: string | undefined
storeDeviceShare: boolean
},
) => {
if (!mpcCoreKit) {
return
}
const securityQuestions = new SecurityQuestionRecovery(mpcCoreKit)
const deviceShareRecovery = new DeviceShareRecovery(mpcCoreKit)
try {
// 1. setup device factor with password recovery
await securityQuestions.upsertPassword(newPassword, oldPassword)
Expand All @@ -42,25 +36,10 @@ export const enableMFA = async (

if (!isMFAEnabled(mpcCoreKit)) {
// 2. enable MFA in mpcCoreKit
const recoveryFactor = await mpcCoreKit.enableMFA({})

// 3. remove the recovery factor the mpcCoreKit creates
const recoverKey = new BN(recoveryFactor, 'hex')
const recoverPubKey = getPubKeyPoint(recoverKey)
await mpcCoreKit.deleteFactor(recoverPubKey, recoverKey)
await mpcCoreKit.enableMFA({}, false)
}

const hasDeviceShare = await deviceShareRecovery.isEnabled()

if (!hasDeviceShare && storeDeviceShare) {
await deviceShareRecovery.createAndStoreDeviceFactor()
}

if (hasDeviceShare && !storeDeviceShare) {
// Switch to password recovery factor such that we can delete the device factor
await mpcCoreKit.inputFactorKey(new BN(securityQuestionFactor, 'hex'))
await deviceShareRecovery.removeDeviceFactor()
}
await mpcCoreKit.commitChanges()
} catch (e) {
const error = asError(e)
logError(ErrorCodes._304, error.message)
Expand Down
7 changes: 5 additions & 2 deletions src/hooks/wallets/mpc/__tests__/useMPCWallet.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ class MockMPCCoreKit {
Promise.reject()
}
}

commitChanges() {
return Promise.resolve()
}
}

describe('useMPCWallet', () => {
Expand Down Expand Up @@ -190,8 +194,7 @@ describe('useMPCWallet', () => {
} as unknown as UserInfo) as unknown as Web3AuthMPCCoreKit,
)

// TODO: remove unnecessary cast if mpc core sdk gets updated
jest.spyOn(mpcCoreKit, 'getWebBrowserFactor').mockReturnValue(Promise.resolve(undefined as unknown as string))
jest.spyOn(mpcCoreKit, 'getWebBrowserFactor').mockReturnValue(Promise.resolve(undefined))
jest.spyOn(mpcCoreKit, 'TssSecurityQuestion').mockReturnValue({
getQuestion: () => 'SOME RANDOM QUESTION',
} as unknown as TssSecurityQuestion)
Expand Down
12 changes: 10 additions & 2 deletions src/hooks/wallets/mpc/recovery/DeviceShareRecovery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,19 @@ export class DeviceShareRecovery {

async removeDeviceFactor() {
const deviceFactor = await getWebBrowserFactor(this.mpcCoreKit)
if (!deviceFactor) {
// No device factor exists. Nothing to do
return
}
// Delete factor
const key = new BN(deviceFactor, 'hex')
const pubKey = getPubKeyPoint(key)
const pubKeyX = pubKey.x.toString('hex', 64)
await this.mpcCoreKit.deleteFactor(pubKey)

// Remove from local storage
const metadata = this.mpcCoreKit.tKey.getMetadata()
const tkeyPubX = metadata.pubKey.x.toString(16, 64)
const currentStorage = BrowserStorage.getInstance('mpc_corekit_store')
currentStorage.set(pubKeyX, undefined)
currentStorage.remove(tkeyPubX)
}
}
1 change: 1 addition & 0 deletions src/hooks/wallets/mpc/useMPC.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ export const useInitMPC = () => {
uxMode: 'popup',
enableLogging: true,
chainConfig,
manualSync: true,
})

web3AuthCoreKit
Expand Down
3 changes: 3 additions & 0 deletions src/hooks/wallets/mpc/useMPCWallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,10 @@ export const useMPCWallet = (): MPCWalletHook => {
if (!mpcCoreKit || !onboard) {
return
}

if (mpcCoreKit.status === COREKIT_STATUS.LOGGED_IN) {
await mpcCoreKit.commitChanges()

await connectWallet(onboard, {
autoSelect: {
label: ONBOARD_MPC_MODULE_LABEL,
Expand Down
36 changes: 18 additions & 18 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5672,22 +5672,22 @@
json-stable-stringify "^1.0.2"
loglevel "^1.8.1"

"@toruslabs/tss-client@^1.6.1-alpha.0":
version "1.6.1-alpha.0"
resolved "https://registry.yarnpkg.com/@toruslabs/tss-client/-/tss-client-1.6.1-alpha.0.tgz#876cdc3c1cae0889a29ad3ed7bf6460bf5055ee2"
integrity sha512-48nYPc/8v2LkbtgBJw3GRLM0Eb08ASFyK5i3nEDmLg1np7rDn/9TMovPckIKZNsqAb4Rwnsb6FmTNszg3UxYfw==
"@toruslabs/tss-client@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@toruslabs/tss-client/-/tss-client-1.7.1.tgz#018511a75a1ee6094fbe74d2b7be968b92255e97"
integrity sha512-gaVjXy/eJKv59zdWW2lnAhjumw8DMMGlGHXEOipVywCylKqS8VvQVwwo+UyevR2VXUQsNkBr9deD5TGFH0OQHQ==
dependencies:
"@toruslabs/eccrypto" "^2.1.1"
"@toruslabs/tss-lib" "^1.6.0-alpha.0"
"@toruslabs/eccrypto" "^4.0.0"
"@toruslabs/tss-lib" "^1.7.1"
bn.js "^5.2.1"
elliptic "^6.5.4"
keccak256 "^1.0.6"
socket.io-client "^4.5.1"
socket.io-client "^4.7.2"

"@toruslabs/tss-lib@^1.6.0-alpha.0":
version "1.6.0-alpha.0"
resolved "https://registry.yarnpkg.com/@toruslabs/tss-lib/-/tss-lib-1.6.0-alpha.0.tgz#3c896c3cd7cec04bc66f4bb240f65c5f4ffe4400"
integrity sha512-sCkAFRZYMDYDWDkMEo73fyz1NnPdXZTRiQWaUCywmtV8fWQBFgneq3bVZGIMAhUNYY62PD0BubW3XaV6mqMYTg==
"@toruslabs/tss-lib@^1.7.1":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@toruslabs/tss-lib/-/tss-lib-1.7.1.tgz#758c62b72b41450de5df90acb42d6c2ba5df0482"
integrity sha512-kdjBO95cPq4i7RaRMkjUJFH0aiSHrMZV/A4I42oUr0FkBd7e/RYyn1e1QH1pAAyidCIKbMkwqTxgPg4nuHEcDg==

"@trezor/[email protected]":
version "1.0.2"
Expand Down Expand Up @@ -7071,10 +7071,10 @@
loglevel "^1.8.1"
ts-custom-error "^3.3.1"

"@web3auth/mpc-core-kit@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@web3auth/mpc-core-kit/-/mpc-core-kit-1.0.2.tgz#0d6ee19df4c30449d8e283532c1c4d8c8a034f5f"
integrity sha512-68qp8vwydpsZa9c7YCOSbFJ/HulgauSTMymJiNFQ0q/gssAK+rzUMi7GJq/1gWlY8DOozO9C+u5MJnt9XG3JDw==
"@web3auth/mpc-core-kit@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@web3auth/mpc-core-kit/-/mpc-core-kit-1.1.0.tgz#b122a1ad2644e19f563679ee33c8cb6a9948d1a0"
integrity sha512-T7I9BB9hrZbpY9fwYXe7l0qNbKbbLlMvU4Gl1aPAyWXrnIP+bma9qqq0pVZaAx0DFehz023Yf5zgiwt6GR2F/g==
dependencies:
"@tkey-mpc/chrome-storage" "^8.2.2"
"@tkey-mpc/common-types" "^8.2.2"
Expand All @@ -7091,8 +7091,8 @@
"@toruslabs/metadata-helpers" "^5.x"
"@toruslabs/openlogin-session-manager" "^3.0.0"
"@toruslabs/torus.js" "^11.0.5"
"@toruslabs/tss-client" "^1.6.1-alpha.0"
"@toruslabs/tss-lib" "^1.6.0-alpha.0"
"@toruslabs/tss-client" "^1.7.1"
"@toruslabs/tss-lib" "^1.7.1"
"@web3auth-mpc/ethereum-provider" "^2.3.0"
"@web3auth/base" "^7.0.1"
"@web3auth/base-provider" "^7.0.1"
Expand Down Expand Up @@ -15691,7 +15691,7 @@ smart-buffer@^4.2.0:
resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae"
integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==

socket.io-client@^4.5.1, socket.io-client@^4.6.1, socket.io-client@^4.7.2:
socket.io-client@^4.6.1, socket.io-client@^4.7.2:
version "4.7.2"
resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-4.7.2.tgz#f2f13f68058bd4e40f94f2a1541f275157ff2c08"
integrity sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==
Expand Down

0 comments on commit 5ab369e

Please sign in to comment.