From 353303114e907ad01a36a4c8a86c848a3d8e8b8d Mon Sep 17 00:00:00 2001 From: Brian Faust Date: Thu, 3 Jun 2021 06:39:29 +0300 Subject: [PATCH] refactor(profiles): replace `fromMnemonicWithEncryption` with a `password` argument for `fromMnemonicWithBIP39` (#1691) --- .../src/contracts/wallets/wallet.factory.ts | 22 +----------- .../memory/wallets/wallet.factory.test.ts | 36 +++++++++---------- .../drivers/memory/wallets/wallet.factory.ts | 36 ++++++++----------- 3 files changed, 34 insertions(+), 60 deletions(-) diff --git a/packages/platform-sdk-profiles/src/contracts/wallets/wallet.factory.ts b/packages/platform-sdk-profiles/src/contracts/wallets/wallet.factory.ts index 7bd5d04926..e58084f458 100644 --- a/packages/platform-sdk-profiles/src/contracts/wallets/wallet.factory.ts +++ b/packages/platform-sdk-profiles/src/contracts/wallets/wallet.factory.ts @@ -20,6 +20,7 @@ export interface IMnemonicOptions { coin: string; network: string; mnemonic: string; + password?: string; } /** @@ -67,18 +68,6 @@ export interface IAddressWithDerivationPathOptions { path: string; } -/** - * Defines the options for an import with a mnemonic and password. - * - * @interface IMnemonicWithEncryptionOptions - */ -export interface IMnemonicWithEncryptionOptions { - coin: string; - network: string; - mnemonic: string; - password: string; -} - /** * Defines the options for an import with a WIF. * @@ -190,15 +179,6 @@ export interface IWalletFactory { */ fromAddressWithDerivationPath(options: IAddressWithDerivationPathOptions): Promise; - /** - * Imports a wallet from a mnemonic with a password. - * - * @param {IMnemonicWithEncryptionOptions} options - * @return {Promise} - * @memberof IWalletFactory - */ - fromMnemonicWithEncryption(options: IMnemonicWithEncryptionOptions): Promise; - /** * Imports a wallet from a WIF. * diff --git a/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.test.ts b/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.test.ts index f1b45a982a..09e3dbebd9 100644 --- a/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.test.ts +++ b/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.test.ts @@ -76,6 +76,24 @@ describe("#fromMnemonicWithBIP39", () => { }), ).rejects.toThrow("The configured network uses extended public keys with BIP44 for derivation."); }); + + it("should create a wallet using BIP39 with encryption", async () => { + const wallet = await subject.fromMnemonicWithBIP39({ + coin: "ARK", + network: "ark.devnet", + mnemonic: "this is a top secret passphrase", + password: "password", + }); + + expect(wallet.address()).toBe("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"); + expect(wallet.publicKey()).toBe("034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192"); + expect(wallet.data().get(WalletData.Bip38EncryptedKey)).toBeString(); + + // @ts-ignore + expect(decrypt(wallet.data().get(WalletData.Bip38EncryptedKey)!, "password").privateKey.toString("hex")).toBe( + "d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712", + ); + }); }); describe("#fromMnemonicWithBIP44", () => { @@ -160,24 +178,6 @@ test("#fromAddressWithDerivationPath", async () => { expect(wallet.publicKey()).toBe("034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192"); }); -test("#fromMnemonicWithEncryption", async () => { - const wallet = await subject.fromMnemonicWithEncryption({ - coin: "ARK", - network: "ark.devnet", - mnemonic: "this is a top secret passphrase", - password: "password", - }); - - expect(wallet.address()).toBe("D61mfSggzbvQgTUe6JhYKH2doHaqJ3Dyib"); - expect(wallet.publicKey()).toBe("034151a3ec46b5670a682b0a63394f863587d1bc97483b1b6c70eb58e7f0aed192"); - expect(wallet.data().get(WalletData.Bip38EncryptedKey)).toBeString(); - - // @ts-ignore - expect(decrypt(wallet.data().get(WalletData.Bip38EncryptedKey)!, "password").privateKey.toString("hex")).toBe( - "d8839c2432bfd0a67ef10a804ba991eabba19f154a3d707917681d45822a5712", - ); -}); - test("#fromWIF", async () => { const wallet = await subject.fromWIF({ coin: "ARK", diff --git a/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.ts b/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.ts index 4c2ae3d964..ab4eb08b09 100644 --- a/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.ts +++ b/packages/platform-sdk-profiles/src/drivers/memory/wallets/wallet.factory.ts @@ -10,7 +10,6 @@ import { IAddressWithDerivationPathOptions, IGenerateOptions, IMnemonicOptions, - IMnemonicWithEncryptionOptions, IPrivateKeyOptions, IProfile, IPublicKeyOptions, @@ -43,7 +42,7 @@ export class WalletFactory implements IWalletFactory { } /** {@inheritDoc IWalletFactory.fromMnemonicWithBIP39} */ - public async fromMnemonicWithBIP39({ coin, network, mnemonic }: IMnemonicOptions): Promise { + public async fromMnemonicWithBIP39({ coin, network, mnemonic, password }: IMnemonicOptions): Promise { const wallet: IReadWriteWallet = new Wallet(uuidv4(), {}, this.#profile); wallet.data().set(WalletData.ImportMethod, WalletImportMethod.MnemonicBIP39); @@ -60,6 +59,14 @@ export class WalletFactory implements IWalletFactory { await wallet.mutator().identity(mnemonic); + if (password) { + await this.#encryptWallet( + wallet, + password, + async () => await wallet.coin().identity().wif().fromMnemonic(mnemonic), + ); + } + return wallet; } @@ -153,8 +160,6 @@ export class WalletFactory implements IWalletFactory { address, path, }: IAddressWithDerivationPathOptions): Promise { - // @TODO: eventually handle the whole process from slip44 path to public key to address - const wallet: IReadWriteWallet = await this.fromAddress({ coin, network, address }); wallet.data().set(WalletData.ImportMethod, WalletImportMethod.AddressWithDerivationPath); @@ -163,23 +168,6 @@ export class WalletFactory implements IWalletFactory { return wallet; } - /** {@inheritDoc IWalletFactory.fromMnemonicWithEncryption} */ - public async fromMnemonicWithEncryption({ - coin, - network, - mnemonic, - password, - }: IMnemonicWithEncryptionOptions): Promise { - const wallet: IReadWriteWallet = await this.fromMnemonicWithBIP39({ coin, network, mnemonic }); - wallet.data().set(WalletData.ImportMethod, WalletImportMethod.MnemonicWithEncryption); - - const { compressed, privateKey } = decode((await wallet.coin().identity().wif().fromMnemonic(mnemonic)).wif); - - wallet.data().set(WalletData.Bip38EncryptedKey, encrypt(privateKey, compressed, password)); - - return wallet; - } - /** {@inheritDoc IWalletFactory.fromWIF} */ public async fromWIF({ coin, network, wif }: IWifOptions): Promise { const wallet: IReadWriteWallet = new Wallet(uuidv4(), {}, this.#profile); @@ -233,4 +221,10 @@ export class WalletFactory implements IWalletFactory { /* istanbul ignore next */ return wallet.gate().allows(Coins.FeatureFlag.IdentityAddressMnemonicBip84); } + + async #encryptWallet(wallet: IReadWriteWallet, password: string, derive: Function): Promise { + const { compressed, privateKey } = decode((await derive()).wif); + + wallet.data().set(WalletData.Bip38EncryptedKey, encrypt(privateKey, compressed, password)); + } }