From 53241142d5d47924cfabcca788039de14d5fcc71 Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Wed, 11 Jul 2018 16:23:24 -0400 Subject: [PATCH 1/5] removeAccount, forgetDevice, getFirstPage added --- index.js | 33 ++++++++++++++++++++++++++++++--- package.json | 2 +- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/index.js b/index.js index 1c3d18ef98dc..5df630fa2fed 100644 --- a/index.js +++ b/index.js @@ -43,9 +43,13 @@ class TrezorKeyring extends EventEmitter { return Promise.resolve() } + isUnlocked () { + return !!this.hdk.publicKey + } + unlock () { - if (this.hdk.publicKey) return Promise.resolve('already unlocked') + if (this.isUnlocked()) return Promise.resolve('already unlocked') return new Promise((resolve, reject) => { TrezorConnect.getXPubKey( @@ -90,6 +94,11 @@ class TrezorKeyring extends EventEmitter { }) } + getFirstPage () { + this.page = 0 + return this.__getPage(1) + } + getNextPage () { return this.__getPage(1) } @@ -102,11 +111,13 @@ class TrezorKeyring extends EventEmitter { this.page += increment + if (this.page <= 0) { this.page = 1 } + return new Promise((resolve, reject) => { this.unlock() .then(_ => { - const from = this.page === 0 ? 0 : (this.page - 1) * this.perPage + const from = (this.page - 1) * this.perPage const to = from + this.perPage const accounts = [] @@ -115,7 +126,7 @@ class TrezorKeyring extends EventEmitter { const address = this._addressFromIndex(pathBase, i) accounts.push({ address: address, - balance: 0, + balance: null, index: i, }) this.paths[ethUtil.toChecksumAddress(address)] = i @@ -133,6 +144,13 @@ class TrezorKeyring extends EventEmitter { return Promise.resolve(this.accounts.slice()) } + removeAccount (address) { + if (!this.accounts.map(a => a.toLowerCase()).includes(address.toLowerCase())) { + throw new Error(`Address ${address} not found in this keyring`) + } + this.accounts = this.accounts.filter(a => a.toLowerCase() !== address.toLowerCase()) + } + // tx is an instance of the ethereumjs-transaction class. signTransaction (address, tx) { @@ -224,6 +242,15 @@ class TrezorKeyring extends EventEmitter { throw new Error('Not supported on this device') } + forgetDevice () { + this.accounts = [] + this.hdk = new HDKey() + this.page = 0 + this.perPage = 5 + this.unlockedAccount = 0 + this.paths = {} + } + /* PRIVATE METHODS */ _padLeftEven (hex) { diff --git a/package.json b/package.json index 8e41ed9d76c1..35614761b909 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "scripts": { "test": "mocha", "lint": "./node_modules/.bin/eslint . --ext .js", - "lint::fix": "./node_modules/.bin/eslint --fix . --ext .js" + "lint:fix": "./node_modules/.bin/eslint --fix . --ext .js" }, "repository": { "type": "git", From 69d0e951837c4bc90b5ff3df814e1220c4280f0b Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Wed, 11 Jul 2018 17:27:18 -0400 Subject: [PATCH 2/5] added more tests --- index.js | 3 +- test/test-eth-trezor-keyring.js | 67 +++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 5df630fa2fed..46bdd9e62b34 100644 --- a/index.js +++ b/index.js @@ -44,7 +44,7 @@ class TrezorKeyring extends EventEmitter { } isUnlocked () { - return !!this.hdk.publicKey + return !!(this.hdk && this.hdk.publicKey) } unlock () { @@ -246,7 +246,6 @@ class TrezorKeyring extends EventEmitter { this.accounts = [] this.hdk = new HDKey() this.page = 0 - this.perPage = 5 this.unlockedAccount = 0 this.paths = {} } diff --git a/test/test-eth-trezor-keyring.js b/test/test-eth-trezor-keyring.js index 4490993535d0..3e3793ad8a6a 100644 --- a/test/test-eth-trezor-keyring.js +++ b/test/test-eth-trezor-keyring.js @@ -109,6 +109,13 @@ describe('TrezorKeyring', function () { }) }) + + describe('isUnlocked', function () { + it('should return true if we have a public key', function () { + assert.equal(keyring.isUnlocked(), true) + }) + }) + describe('unlock', function () { it('should resolve if we have a public key', function (done) { keyring.unlock().then(_ => { @@ -173,6 +180,50 @@ describe('TrezorKeyring', function () { }) }) + describe('removeAccount', function () { + describe('if the account exists', function () { + it('should remove that account', function (done) { + keyring.setAccountToUnlock(0) + keyring.addAccounts() + .then(async (accounts) => { + assert.equal(accounts.length, 1) + keyring.removeAccount(fakeAccounts[0]) + const accountsAfterRemoval = await keyring.getAccounts() + assert.equal(accountsAfterRemoval.length, 0) + done() + }) + }) + }) + + describe('if the account does not exist', function () { + it('should throw an error', function () { + const unexistingAccount = '0x0000000000000000000000000000000000000000' + expect(_ => { + keyring.removeAccount(unexistingAccount) + }).to.throw(`Address ${unexistingAccount} not found in this keyring`) + }) + }) + }) + + describe('getFirstPage', function () { + it('should set the currentPage to 1', async function () { + await keyring.getFirstPage() + assert.equal(keyring.page, 1) + }) + + it('should return the list of accounts for current page', async function () { + + const accounts = await keyring.getFirstPage() + + expect(accounts.length, keyring.perPage) + expect(accounts[0].address, fakeAccounts[0]) + expect(accounts[1].address, fakeAccounts[1]) + expect(accounts[2].address, fakeAccounts[2]) + expect(accounts[3].address, fakeAccounts[3]) + expect(accounts[4].address, fakeAccounts[4]) + }) + }) + describe('getNextPage', function () { it('should return the list of accounts for current page', async function () { @@ -300,4 +351,20 @@ describe('TrezorKeyring', function () { }) }) + describe('forgetDevice', function () { + it('should clear the content of the keyring', async function () { + // Add an account + keyring.setAccountToUnlock(0) + await keyring.addAccounts() + + // Wipe the keyring + keyring.forgetDevice() + + const accounts = await keyring.getAccounts() + + assert.equal(keyring.isUnlocked(), false) + assert.equal(accounts.length, 0) + }) + }) + }) From 1b9d7e5c15b185b5a0783bf3d515c655acee5e4f Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Wed, 11 Jul 2018 17:34:18 -0400 Subject: [PATCH 3/5] update readme --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 8cdea50a6452..8bdc8a2ba506 100644 --- a/README.md +++ b/README.md @@ -21,14 +21,21 @@ Using In addition to all the known methods from the [Keyring class protocol](https://github.com/MetaMask/eth-simple-keyring#the-keyring-class-protocol), there are a few others: + +- **isUnlocked** : Returns true if we have the public key in memory, which allows to generate the list of accounts at any time + - **unlock** : Connects to the TREZOR device and exports the extended public key, which is later used to read the available ethereum addresses inside the trezor account. - **setAccountToUnlock** : the index of the account that you want to unlock in order to use with the signTransaction and signPersonalMessage methods +- **getFirstPage** : returns the first ordered set of accounts from the TREZOR account + - **getNextPage** : returns the next ordered set of accounts from the TREZOR account based on the current page - **getPreviousPage** : returns the previous ordered set of accounts from the TREZOR account based on the current page +- **forgetDevice** : removes all the device info from memory so the next interaction with the keyring will prompt the user to connect the TREZOR device and export the account information + Testing ------- Run the following command: From da4f121a0164838e30ebf3c518f988096d71483d Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Wed, 11 Jul 2018 17:38:02 -0400 Subject: [PATCH 4/5] update circleci badge --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8bdc8a2ba506..f9abd0449d81 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -eth-trezor-keyring [![CircleCI](https://circleci.com/gh/brunobar79/eth-trezor-keyring.svg?style=svg)](https://circleci.com/gh/brunobar79/eth-trezor-keyring) +eth-trezor-keyring [![CircleCI](https://circleci.com/gh/MetaMask/eth-trezor-keyring.svg?style=svg)](https://circleci.com/gh/MetaMask/eth-trezor-keyring) ================== An implementation of MetaMask's [Keyring interface](https://github.com/MetaMask/eth-simple-keyring#the-keyring-class-protocol), that uses a TREZOR hardware From 7e5874ae1069a7f289e4996b79a3dac2ea40538d Mon Sep 17 00:00:00 2001 From: brunobar79 Date: Wed, 11 Jul 2018 17:41:23 -0400 Subject: [PATCH 5/5] bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 35614761b909..a4893c723889 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "eth-trezor-keyring", - "version": "0.0.1", + "version": "0.1.0", "description": "A MetaMask compatible keyring, for trezor hardware wallets", "main": "index.js", "scripts": {