diff --git a/packages/neuron-ui/src/components/WalletWizard/createWallet.tsx b/packages/neuron-ui/src/components/WalletWizard/createWallet.tsx index eb73b34c23..5f8cd4b720 100644 --- a/packages/neuron-ui/src/components/WalletWizard/createWallet.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/createWallet.tsx @@ -56,8 +56,7 @@ export default (props: React.PropsWithoutRef // temp logic for simulate creation props.dispatch( actionCreators.createWallet({ - name: settings.name, - mnemonic: '', + walletName: settings.name, password: '', }), ) diff --git a/packages/neuron-ui/src/components/WalletWizard/importWallet.tsx b/packages/neuron-ui/src/components/WalletWizard/importWallet.tsx index 702da19cfa..e27955bdff 100644 --- a/packages/neuron-ui/src/components/WalletWizard/importWallet.tsx +++ b/packages/neuron-ui/src/components/WalletWizard/importWallet.tsx @@ -55,9 +55,10 @@ export default (props: React.PropsWithoutRef // temp logic for simulate creation props.dispatch( actionCreators.importWallet({ - name: settings.name, + walletName: settings.name, mnemonic: settings.seeds, password: '', + keystore: '', }), ) }} diff --git a/packages/neuron-ui/src/containers/MainContent/actionCreators/wallet.ts b/packages/neuron-ui/src/containers/MainContent/actionCreators/wallet.ts index 8cfd749581..99ba9c049b 100644 --- a/packages/neuron-ui/src/containers/MainContent/actionCreators/wallet.ts +++ b/packages/neuron-ui/src/containers/MainContent/actionCreators/wallet.ts @@ -2,7 +2,7 @@ import { initState, MainActions } from '../reducer' import { createWallet, importWallet, exportWallet } from '../../../services/UILayer' export default { - createWallet: (wallet: typeof initState.tempWallet) => { + createWallet: (wallet: typeof initState.createWallet) => { createWallet(wallet) return { type: MainActions.CreateWallet, diff --git a/packages/neuron-ui/src/containers/MainContent/state.ts b/packages/neuron-ui/src/containers/MainContent/state.ts index ac4f394c13..675911f52b 100644 --- a/packages/neuron-ui/src/containers/MainContent/state.ts +++ b/packages/neuron-ui/src/containers/MainContent/state.ts @@ -2,9 +2,14 @@ import { CapacityUnit } from '../../utils/const' export const initState = { tempWallet: { - name: '', + walletName: '', password: '', mnemonic: '', + keystore: '', + }, + createWallet: { + walletName: '', + password: '', }, transfer: { items: [ diff --git a/packages/neuron-ui/src/services/UILayer.ts b/packages/neuron-ui/src/services/UILayer.ts index ea7ee50125..f7fc83fd42 100644 --- a/packages/neuron-ui/src/services/UILayer.ts +++ b/packages/neuron-ui/src/services/UILayer.ts @@ -47,7 +47,7 @@ export const getWallets = () => { UILayer.send(Channel.GetWallets) } -export const createWallet = (wallet: { name: string; mnemonic: any; password: string }) => +export const createWallet = (wallet: { walletName: string; password: string }) => UILayer.send(Channel.CreateWallet, wallet) export const deleteWallet = (walletID: string, password: string, handleResult: any) => { @@ -85,8 +85,9 @@ export const editWallet = ( }) } -export const importWallet = (wallet: { name: string; mnemonic: any; password: string }) => +export const importWallet = (wallet: { walletName: string; password: string; mnemonic: string; keystore: string }) => UILayer.send(Channel.ImportWallet, wallet) + export const exportWallet = () => UILayer.send(Channel.ExportWallet) export const getLiveCell = (outpoint: any) => UILayer.send('getLiveCell', outpoint) export const getCellsByTypeHash = (typeHash: string) => { diff --git a/packages/neuron-wallet/src/channel/index.ts b/packages/neuron-wallet/src/channel/index.ts index 93fad33052..0197c8db5c 100644 --- a/packages/neuron-wallet/src/channel/index.ts +++ b/packages/neuron-wallet/src/channel/index.ts @@ -4,6 +4,8 @@ import { Channel } from '../utils/const' import { transactions, transactionCount, wallets, Wallet, updateWallets, validatePassword } from '../mock' import asw from '../wallets/asw' import ckbCore from '../core' +import Key from '../keys/key' +import WalletStore from '../store/WalletStore' enum ResponseStatus { Fail, @@ -82,16 +84,17 @@ export class Listeners { * @description channel to create wallet */ static createWallet = () => { - return ipcMain.on(Channel.CreateWallet, (e: Electron.Event, wallet: Wallet) => { - e.sender.send(Channel.CreateWallet, { - status: ResponseStatus.Success, - result: { - name: wallet.name, - address: 'wallet address', - publicKey: 'public key', - }, - }) - }) + return ipcMain.on( + Channel.CreateWallet, + (e: Electron.Event, { walletName, password }: { walletName: string; password: string }) => { + const walletStore = new WalletStore() + const walletID = walletStore.saveWallet(walletName, Key.generateKey(password).getKeystore()) + e.sender.send(Channel.CreateWallet, { + status: ResponseStatus.Success, + result: walletID, + }) + }, + ) } /** @@ -165,12 +168,47 @@ export class Listeners { * @description channel to import a wallet */ static importWallet = () => { - return ipcMain.on(Channel.ImportWallet, (e: Electron.Event) => { - e.sender.send(Channel.ImportWallet, { - status: ResponseStatus.Success, - result: `wallet imported`, - }) - }) + return ipcMain.on( + Channel.ImportWallet, + ( + e: Electron.Event, + { + walletName, + password, + mnemonic, + keystore, + }: { walletName: string; password: string; mnemonic: string; keystore: string }, + ) => { + try { + const walletStore = new WalletStore() + let storedKeystore + if (mnemonic) { + storedKeystore = Key.fromMnemonic(mnemonic, true, password).getKeystore() + } else if (keystore) { + storedKeystore = Key.fromKeystoreString(keystore, password).getKeystore() + } + if (storedKeystore) { + walletStore.saveWallet(walletName, storedKeystore) + e.sender.send(Channel.ImportWallet, { + status: ResponseStatus.Success, + result: true, + }) + } else { + e.sender.send(Channel.ImportWallet, { + status: ResponseStatus.Success, + result: false, + msg: 'Error', + }) + } + } catch (error) { + e.sender.send(Channel.ImportWallet, { + status: ResponseStatus.Success, + result: false, + msg: error.message, + }) + } + }, + ) } /** diff --git a/packages/neuron-wallet/src/keys/key.ts b/packages/neuron-wallet/src/keys/key.ts index 30f73b7fe0..242d033b0c 100644 --- a/packages/neuron-wallet/src/keys/key.ts +++ b/packages/neuron-wallet/src/keys/key.ts @@ -13,12 +13,19 @@ export default class Key { this.mnemonic = mnemonic } - public static fromKeystore = (keystore: Keystore) => { + public static fromKeystore = (keystore: Keystore, password: string) => { + if (!Key.checkPassword(keystore, password)) { + throw new Error('Wrong password') + } return new Key(keystore, '') } - public static fromKeystoreString = (json: string) => { - return new Key(JSON.parse(json), '') + public static fromKeystoreString = (json: string, password: string) => { + return Key.fromKeystore(JSON.parse(json), password) + } + + public static checkPassword(keystore: Keystore, password: string) { + return keystore.password === password } getKeystore = () => this.keystore @@ -27,12 +34,15 @@ export default class Key { getMnemonic = () => this.mnemonic - public static generateKey = () => { + public static generateKey = (password: string) => { const mnemonic = bip39.generateMnemonic() - return Key.fromMnemonic(mnemonic, false) + return Key.fromMnemonic(mnemonic, false, password) } - public static fromMnemonic = (mnemonic: string, derive: boolean) => { + public static fromMnemonic = (mnemonic: string, derive: boolean, password: string) => { + if (!bip39.validateMnemonic(mnemonic)) { + throw new Error('Wrong Mnemonic') + } const seed = bip39.mnemonicToSeed(mnemonic) const root = bip32.fromSeed(seed) const master = { @@ -41,6 +51,7 @@ export default class Key { } const keystore: Keystore = { master, + password, } if (derive) { keystore.children = Tool.searchUsedChildKeys(root) diff --git a/packages/neuron-wallet/src/keys/keystore.ts b/packages/neuron-wallet/src/keys/keystore.ts index e71c9c1a09..a8f8609cb4 100644 --- a/packages/neuron-wallet/src/keys/keystore.ts +++ b/packages/neuron-wallet/src/keys/keystore.ts @@ -12,4 +12,5 @@ export interface Child { export interface Keystore { master: Master children?: Child[] + password: string } diff --git a/packages/neuron-wallet/tests/key.test.ts b/packages/neuron-wallet/tests/key.test.ts index 0ebdd09664..8211005325 100644 --- a/packages/neuron-wallet/tests/key.test.ts +++ b/packages/neuron-wallet/tests/key.test.ts @@ -3,10 +3,10 @@ import Key from '../src/keys/key' describe('Key tests', () => { const mnemonic = 'mechanic oppose oyster normal bunker trim step nasty birth naive panel soldier' const keystoreJson = - '{"master":{"privateKey":"4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488","chainCode":"769382d9761bef8ed409ce4f9d5aeae5b5260f6f60e50f791826c27ae7afc495"}}' + '{"master":{"privateKey":"4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488","chainCode":"769382d9761bef8ed409ce4f9d5aeae5b5260f6f60e50f791826c27ae7afc495"},"password":"1qaz.2wsx"}' it('import key from mnemonic without children', async () => { - const key = Key.fromMnemonic(mnemonic, false) + const key = Key.fromMnemonic(mnemonic, false, '1qaz.2wsx') expect(key.getMnemonic()).toBe('mechanic oppose oyster normal bunker trim step nasty birth naive panel soldier') expect(key.getKeystoreString()).toBe(keystoreJson) expect(key.getKeystore().master.privateKey).toBe('4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488') @@ -14,20 +14,20 @@ describe('Key tests', () => { }) it('import key from keystore json without children', async () => { - const key = Key.fromKeystoreString(keystoreJson) + const key = Key.fromKeystoreString(keystoreJson, '1qaz.2wsx') expect(key.getKeystore().master.privateKey).toBe('4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488') expect(key.getKeystore().master.chainCode).toBe('769382d9761bef8ed409ce4f9d5aeae5b5260f6f60e50f791826c27ae7afc495') }) it('generate key', async () => { - const key = Key.generateKey() + const key = Key.generateKey('1qaz.2wsx') expect(key.getMnemonic()).not.toEqual(null) expect(key.getKeystore()).not.toEqual(null) expect(key.getKeystore().master).not.toEqual(null) }) it('import key from mnemonic with children', async () => { - const key = Key.fromMnemonic(mnemonic, true) + const key = Key.fromMnemonic(mnemonic, true, '1qaz.2wsx') expect(key.getMnemonic()).toBe('mechanic oppose oyster normal bunker trim step nasty birth naive panel soldier') expect(key.getKeystore().master.privateKey).toBe('4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488') expect(key.getKeystore().master.chainCode).toBe('769382d9761bef8ed409ce4f9d5aeae5b5260f6f60e50f791826c27ae7afc495') @@ -36,8 +36,8 @@ describe('Key tests', () => { }) it('import key from keystore json with children', async () => { - const keystore = Key.fromMnemonic(mnemonic, true).getKeystoreString() - const key = Key.fromKeystoreString(keystore) + const keystore = Key.fromMnemonic(mnemonic, true, '1qaz.2wsx').getKeystoreString() + const key = Key.fromKeystoreString(keystore, '1qaz.2wsx') expect(key.getKeystore().master.privateKey).toBe('4e91f531d3351fd561506538ec0a68ba05d3d3444197e81d615ab76bbd200488') expect(key.getKeystore().master.chainCode).toBe('769382d9761bef8ed409ce4f9d5aeae5b5260f6f60e50f791826c27ae7afc495') expect(key.getKeystore().children!.length > 0).toEqual(true)