From 80803db8592d83f10cbe1e770c0fd688f3f62f74 Mon Sep 17 00:00:00 2001 From: heisenberg Date: Fri, 20 Dec 2024 10:05:37 +0800 Subject: [PATCH] feat: store unencryptedKeyringData --- apps/mobile/package.json | 12 +-- .../Settings/sheetModals/DevWalletLock.tsx | 10 +++ .../service-keyring/src/keyringService.ts | 85 ++++++++++++++----- yarn.lock | 20 ++++- 4 files changed, 100 insertions(+), 27 deletions(-) diff --git a/apps/mobile/package.json b/apps/mobile/package.json index 0f47ffede..0e5202cfb 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -8,6 +8,7 @@ }, "scripts": { "android": "react-native run-android", + "android:buildversion": "react-native-version --never-amend --target android --increment-build", "build-inpage": "sh ./scripts/postinstall.sh", "build:deps": "yarn ../../ build", "devtools": "react-devtools", @@ -20,11 +21,10 @@ "lint:commit:fix": "eslint ./src --quiet --fix --ext .js,.jsx,.ts,.tsx --max-warnings=-1", "lint:fix": "eslint ./src --fix --ext .js,.jsx,.ts,.tsx", "restart": "yarn start --reset-cache", + "rnversion": "yarn syncrnversion && yarn android:buildversion", "start": "yarn ensure-git-hooks && yarn build:deps && yarn build-inpage && react-native start", "sync:data": "node ./scripts/sync.js", "syncrnversion": "./node_modules/.bin/react-native-version --never-amend --never-increment-build", - "rnversion": "yarn syncrnversion && yarn android:buildversion", - "android:buildversion": "react-native-version --never-amend --target android --increment-build", "test": "jest", "postversion": "react-native-version --never-amend" }, @@ -33,11 +33,11 @@ "*": "prettier --write --ignore-unknown" }, "resolutions": { + "@ledgerhq/react-native-hw-transport-ble/react-native-ble-plx": "3.1.2", + "@onekeyfe/hd-transport-react-native/@onekeyfe/react-native-ble-plx": "npm:react-native-ble-plx@3.1.2", "eth-rpc-errors": "^4.0.3", "json-rpc-engine/eth-rpc-errors": "^4.0.3", - "readable-stream": "3.6.2", - "@ledgerhq/react-native-hw-transport-ble/react-native-ble-plx": "3.1.2", - "@onekeyfe/hd-transport-react-native/@onekeyfe/react-native-ble-plx": "npm:react-native-ble-plx@3.1.2" + "readable-stream": "3.6.2" }, "dependencies": { "@babel/plugin-transform-export-namespace-from": "^7.23.4", @@ -60,7 +60,7 @@ "@rabby-wallet/eth-keyring-ledger": "workspace:^", "@rabby-wallet/eth-keyring-onekey": "workspace:^", "@rabby-wallet/eth-keyring-watch": "*", - "@rabby-wallet/eth-simple-keyring": "^5.0.1", + "@rabby-wallet/eth-simple-keyring": "5.1.0-beta.0", "@rabby-wallet/gnosis-sdk": "1.3.8", "@rabby-wallet/object-multiplex": "workspace:^", "@rabby-wallet/persist-store": "workspace:^", diff --git a/apps/mobile/src/screens/Settings/sheetModals/DevWalletLock.tsx b/apps/mobile/src/screens/Settings/sheetModals/DevWalletLock.tsx index 0e5ab2e01..1d7e991d7 100644 --- a/apps/mobile/src/screens/Settings/sheetModals/DevWalletLock.tsx +++ b/apps/mobile/src/screens/Settings/sheetModals/DevWalletLock.tsx @@ -22,6 +22,7 @@ import { LastUnlockTimeLabel } from '../components/LockAbout'; import { APP_FEATURE_SWITCH } from '@/constant'; import { apisKeychain, apisLock } from '@/core/apis'; import { RABBY_MOBILE_KR_PWD } from '@/constant/encryptor'; +import { keyringService } from '@/core/services'; const walletLockTestItemModalVisibleAtom = atom(false); export function useWalletLockTestItemModalVisible() { @@ -102,6 +103,15 @@ export default function WalletLockTestItemModal({ ), }, + { + label: 'Check unencryptedKeyringData', + icon: , + onPress: async () => { + const keyringData = + await keyringService.DEV_GET_UNENCRYPTED_KEYRING_DATA(); + Alert.alert('Unencrypted Keyring Data', JSON.stringify(keyringData)); + }, + }, ]; return list.filter(item => item.visible !== false); diff --git a/packages/service-keyring/src/keyringService.ts b/packages/service-keyring/src/keyringService.ts index 16184d466..fd1a34fe3 100644 --- a/packages/service-keyring/src/keyringService.ts +++ b/packages/service-keyring/src/keyringService.ts @@ -28,9 +28,19 @@ import { normalizeAddress } from './utils/address'; import type { EncryptorAdapter } from './utils/encryptor'; import { nodeEncryptor } from './utils/encryptor'; +/** + * need password to decrypt the field in keyring + */ +// partial KeyringTypeName +const PROTECTED_KEYRING_FIELD: Partial> = { + [KEYRING_TYPE.SimpleKeyring]: ['privateKeys'], + [KEYRING_TYPE.HdKeyring]: ['mnemonic', 'passphrase'], +}; + type KeyringState = { booted?: string; vault?: string; + unencryptedKeyringData?: KeyringSerializedData[]; }; type MemStoreState = { @@ -80,9 +90,12 @@ export class KeyringService extends RNEventEmitter { #password: string | null = null; private readonly encryptor: EncryptorAdapter; + private readonly contactService?: ContactBookService; - private onSetAddressAlias?: OnSetAddressAlias; - private onCreateKeyring?: OnCreateKeyring; + + private readonly onSetAddressAlias?: OnSetAddressAlias; + + private readonly onCreateKeyring?: OnCreateKeyring; constructor( options?: KeyringServiceOptions & { @@ -119,6 +132,28 @@ export class KeyringService extends RNEventEmitter { this.store = new ObservableStore({ booted: initState.booted || undefined, vault: initState.vault || undefined, + unencryptedKeyringData: initState.unencryptedKeyringData || undefined, + }); + + if (initState.unencryptedKeyringData) { + this.#restoreUnencryptedKeyringData(initState.unencryptedKeyringData); + } + } + + #restoreUnencryptedKeyringData( + unencryptedKeyringData?: KeyringSerializedData[], + ) { + if (!unencryptedKeyringData) { + return; + } + + // eslint-disable-next-line no-void + void Promise.all( + unencryptedKeyringData.map(data => { + return this.restoreKeyring(data); + }), + ).then((result: KeyringInstance[]) => { + this.keyrings = result; }); } @@ -166,7 +201,6 @@ export class KeyringService extends RNEventEmitter { /** * @description on no keyrings stored, force reset password - * * @param newPassword */ async resetPassword(newPassword: string) { @@ -709,7 +743,7 @@ export class KeyringService extends RNEventEmitter { ); } - return Promise.all( + const serializedKeyrings = await Promise.all( this.keyrings.map(async keyring => { return Promise.all([keyring.type, keyring.serialize()]).then( serializedKeyringArray => { @@ -717,21 +751,31 @@ export class KeyringService extends RNEventEmitter { return { type: serializedKeyringArray[0], data: serializedKeyringArray[1], - }; + } as KeyringSerializedData; }, ); }), - ) - .then(serializedKeyrings => { - return this.encryptor.encrypt( - this.#password as string, - serializedKeyrings as unknown as Buffer, - ); - }) - .then(encryptedString => { - this.store.updateState({ vault: encryptedString }); - return true; - }); + ); + + const unencryptedKeyringData = serializedKeyrings.map(({ type, data }) => { + const protectedFields = PROTECTED_KEYRING_FIELD[type]; + const newData = { ...data }; + if (protectedFields) { + protectedFields.forEach(field => { + delete newData[field]; + }); + } + return { type, data: newData }; + }); + + const encryptedString = await this.encryptor.encrypt( + this.#password as string, + serializedKeyrings as unknown as Buffer, + ); + + this.store.updateState({ vault: encryptedString, unencryptedKeyringData }); + + return true; } /** @@ -1023,10 +1067,7 @@ export class KeyringService extends RNEventEmitter { return bip39.generateMnemonic(wordlist); } - async generatePreMnemonic(options?: { - /** @default {true} */ - persist?: boolean; - }): Promise { + async generatePreMnemonic(): Promise { if (!this.#password) { throw new Error('background.error.unlock'); } @@ -1113,6 +1154,10 @@ export class KeyringService extends RNEventEmitter { keryings.length - 1, ) + 1; } + + DEV_GET_UNENCRYPTED_KEYRING_DATA() { + return this.store.getState().unencryptedKeyringData; + } } /* eslint-enable jsdoc/check-tag-names */ /* eslint-enable jsdoc/check-types */ diff --git a/yarn.lock b/yarn.lock index 136373cf8..e7681501c 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6278,6 +6278,24 @@ __metadata: languageName: unknown linkType: soft +"@rabby-wallet/eth-simple-keyring@npm:5.1.0-beta.0": + version: 5.1.0-beta.0 + resolution: "@rabby-wallet/eth-simple-keyring@npm:5.1.0-beta.0" + dependencies: + "@ethereumjs/util": ^9.0.0 + "@metamask/eth-sig-util": 5.1.0 + "@metamask/utils": ^8.1.0 + chai: ^4.3.4 + eth-sig-util: ^3.0.1 + ethereum-cryptography: ^2.1.2 + ethereumjs-tx: ^2.1.2 + ethereumjs-util: ^7.0.9 + ethereumjs-wallet: ^1.0.2 + randombytes: ^2.1.0 + checksum: 1987ab1e29f790cc8400418ac64a7d0e1c61bd803de524b8a6b60e888adc044de1841d42e340e35fc37e43caa84d6e7586406299c698ec87d64598f119e514e2 + languageName: node + linkType: hard + "@rabby-wallet/eth-simple-keyring@npm:^5.0.1": version: 5.0.1 resolution: "@rabby-wallet/eth-simple-keyring@npm:5.0.1" @@ -27485,7 +27503,7 @@ __metadata: "@rabby-wallet/eth-keyring-ledger": "workspace:^" "@rabby-wallet/eth-keyring-onekey": "workspace:^" "@rabby-wallet/eth-keyring-watch": "*" - "@rabby-wallet/eth-simple-keyring": ^5.0.1 + "@rabby-wallet/eth-simple-keyring": 5.1.0-beta.0 "@rabby-wallet/gnosis-sdk": 1.3.8 "@rabby-wallet/object-multiplex": "workspace:^" "@rabby-wallet/persist-store": "workspace:^"