From ea1a934c7defe7e1b077b675ae9125118f1f3d87 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 11 Oct 2016 15:09:22 -0700 Subject: Add initial KeyringController files --- app/scripts/keyring-controller.js | 42 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 app/scripts/keyring-controller.js (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js new file mode 100644 index 000000000..b61242973 --- /dev/null +++ b/app/scripts/keyring-controller.js @@ -0,0 +1,42 @@ +const scrypt = require('scrypt-async') +const bitcore = require('bitcore-lib') +const configManager = require('./lib/config-manager') + +module.exports = class KeyringController { + + constructor (opts) { + this.configManager = opts.configManager + this.keyChains = [] + } + + getKeyForPassword(password, callback) { + let salt = this.configManager.getSalt() + + if (!salt) { + salt = generateSalt(32) + configManager.setSalt(salt) + } + + var logN = 14 + var r = 8 + var dkLen = 32 + var interruptStep = 200 + + var cb = function(derKey) { + try { + var ui8arr = (new Uint8Array(derKey)) + this.pwDerivedKey = ui8arr + callback(null, ui8arr) + } catch (err) { + callback(err) + } + } + + scrypt(password, salt, logN, r, dkLen, interruptStep, cb, null) + } + +} + +function generateSalt (byteCount) { + return bitcore.crypto.Random.getRandomBuffer(byteCount || 32).toString('base64') +} -- cgit v1.2.3 From cd2c00a31873490c9129023abb35dd7983604b60 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 12 Oct 2016 16:43:48 -0700 Subject: Add minimal method signatures to new keyring controller --- app/scripts/keyring-controller.js | 62 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 61 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b61242973..d96b9c101 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,11 +1,14 @@ const scrypt = require('scrypt-async') const bitcore = require('bitcore-lib') const configManager = require('./lib/config-manager') +const EventEmitter = require('events').EventEmitter -module.exports = class KeyringController { +module.exports = class KeyringController extends EventEmitter { constructor (opts) { + super() this.configManager = opts.configManager + this.ethStore = opts.ethStore this.keyChains = [] } @@ -35,6 +38,63 @@ module.exports = class KeyringController { scrypt(password, salt, logN, r, dkLen, interruptStep, cb, null) } + getState() { + return {} + } + + setStore(ethStore) { + this.ethStore = ethStore + } + + createNewVault(password, entropy, cb) { + cb() + } + + submitPassword(password, cb) { + cb() + } + + setSelectedAddress(address, cb) { + this.selectedAddress = address + cb(null, address) + } + + approveTransaction(txId, cb) { + cb() + } + + cancelTransaction(txId, cb) { + if (cb && typeof cb === 'function') { + cb() + } + } + + signMessage(msgParams, cb) { + cb() + } + + cancelMessage(msgId, cb) { + if (cb && typeof cb === 'function') { + cb() + } + } + + setLocked(cb) { + cb() + } + + exportAccount(address, cb) { + cb(null, '0xPrivateKey') + } + + saveAccountLabel(account, label, cb) { + cb(/* null, label */) + } + + tryPassword(password, cb) { + cb() + } + } function generateSalt (byteCount) { -- cgit v1.2.3 From 1481a3ef8e3352eb74fa11c4f578d15d84c76de7 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Sat, 15 Oct 2016 10:48:12 -0700 Subject: Initial work on UI side --- app/scripts/keyring-controller.js | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index d96b9c101..5b527b0d9 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -12,6 +12,11 @@ module.exports = class KeyringController extends EventEmitter { this.keyChains = [] } + keyFromPassword(password, callback) { + deriveKeyFromPassword(password, callback); + } + + // Takes a pw and callback, returns a password-dervied key getKeyForPassword(password, callback) { let salt = this.configManager.getSalt() -- cgit v1.2.3 From 725d503f68f533e0d1dfc402c4316dcf677c0d89 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 19 Oct 2016 14:06:48 -0700 Subject: Remove unused crypto dependencies. --- app/scripts/keyring-controller.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 5b527b0d9..246a45484 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,5 +1,3 @@ -const scrypt = require('scrypt-async') -const bitcore = require('bitcore-lib') const configManager = require('./lib/config-manager') const EventEmitter = require('events').EventEmitter -- cgit v1.2.3 From ad3fa24a28c0ec45dca43a257005626a4027487a Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 19 Oct 2016 14:55:08 -0700 Subject: Intermediary commit. --- app/scripts/keyring-controller.js | 37 +++++++++++++++++++++++++++++++++---- 1 file changed, 33 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 246a45484..db7e5e61e 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,5 +1,7 @@ -const configManager = require('./lib/config-manager') const EventEmitter = require('events').EventEmitter +const encryptor = require('./lib/encryptor') +const messageManager = require('./lib/message-manager') + module.exports = class KeyringController extends EventEmitter { @@ -20,7 +22,7 @@ module.exports = class KeyringController extends EventEmitter { if (!salt) { salt = generateSalt(32) - configManager.setSalt(salt) + this.configManager.setSalt(salt) } var logN = 14 @@ -42,7 +44,21 @@ module.exports = class KeyringController extends EventEmitter { } getState() { - return {} + return { + isInitialized: !!this.key, + isUnlocked: !!this.key, + isConfirmed: true, // this.configManager.getConfirmed(), + isEthConfirmed: this.configManager.getShouldntShowWarning(), + unconfTxs: this.configManager.unconfirmedTxs(), + transactions: this.configManager.getTxList(), + unconfMsgs: messageManager.unconfirmedMsgs(), + messages: messageManager.getMsgList(), + selectedAddress: this.configManager.getSelectedAccount(), + shapeShiftTxList: this.configManager.getShapeShiftTxList(), + currentFiat: this.configManager.getCurrentFiat(), + conversionRate: this.configManager.getConversionRate(), + conversionDate: this.configManager.getConversionDate(), + } } setStore(ethStore) { @@ -50,9 +66,22 @@ module.exports = class KeyringController extends EventEmitter { } createNewVault(password, entropy, cb) { - cb() + encryptor.keyFromPassword(password) + .then((key) => { + this.key = key + return encryptor.encryptWithKey(key, {}) + }) + .then((encryptedString) => { + this.configManager.setVault(encryptedString) + cb(null, []) + }) + .catch((err) => { + cb(err) + }) } + + submitPassword(password, cb) { cb() } -- cgit v1.2.3 From 2132477797660a87fec20dbc0a3f839895b23309 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 10:28:45 -0700 Subject: Fix unlock logic --- app/scripts/keyring-controller.js | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index db7e5e61e..416d6093c 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -45,7 +45,7 @@ module.exports = class KeyringController extends EventEmitter { getState() { return { - isInitialized: !!this.key, + isInitialized: !!this.configManager.getVault(), isUnlocked: !!this.key, isConfirmed: true, // this.configManager.getConfirmed(), isEthConfirmed: this.configManager.getShouldntShowWarning(), @@ -66,9 +66,8 @@ module.exports = class KeyringController extends EventEmitter { } createNewVault(password, entropy, cb) { - encryptor.keyFromPassword(password) + this.loadKey(password) .then((key) => { - this.key = key return encryptor.encryptWithKey(key, {}) }) .then((encryptedString) => { @@ -80,10 +79,22 @@ module.exports = class KeyringController extends EventEmitter { }) } - - submitPassword(password, cb) { - cb() + this.loadKey(password) + .then((key) => { + cb(null, []) + }) + .catch((err) => { + cb(err) + }) + } + + loadKey(password) { + return encryptor.keyFromPassword(password) + .then((key) => { + this.key = key + return key + }) } setSelectedAddress(address, cb) { -- cgit v1.2.3 From e5c95d68f80eba3e3d4645f7ac1f6606d0dddd52 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 11:00:38 -0700 Subject: Fix state updating after vault creation and unlocking --- app/scripts/keyring-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 416d6093c..84601916f 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -72,7 +72,7 @@ module.exports = class KeyringController extends EventEmitter { }) .then((encryptedString) => { this.configManager.setVault(encryptedString) - cb(null, []) + cb(null, this.getState()) }) .catch((err) => { cb(err) @@ -82,7 +82,7 @@ module.exports = class KeyringController extends EventEmitter { submitPassword(password, cb) { this.loadKey(password) .then((key) => { - cb(null, []) + cb(null, this.getState()) }) .catch((err) => { cb(err) -- cgit v1.2.3 From 383f8ea7dc4a264613cfe92b257878eb78438ce7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 11:33:18 -0700 Subject: Linted & added salting to vault --- app/scripts/keyring-controller.js | 43 ++++++++------------------------------- 1 file changed, 9 insertions(+), 34 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 84601916f..f6b1e9358 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -12,37 +12,6 @@ module.exports = class KeyringController extends EventEmitter { this.keyChains = [] } - keyFromPassword(password, callback) { - deriveKeyFromPassword(password, callback); - } - - // Takes a pw and callback, returns a password-dervied key - getKeyForPassword(password, callback) { - let salt = this.configManager.getSalt() - - if (!salt) { - salt = generateSalt(32) - this.configManager.setSalt(salt) - } - - var logN = 14 - var r = 8 - var dkLen = 32 - var interruptStep = 200 - - var cb = function(derKey) { - try { - var ui8arr = (new Uint8Array(derKey)) - this.pwDerivedKey = ui8arr - callback(null, ui8arr) - } catch (err) { - callback(err) - } - } - - scrypt(password, salt, logN, r, dkLen, interruptStep, cb, null) - } - getState() { return { isInitialized: !!this.configManager.getVault(), @@ -66,11 +35,13 @@ module.exports = class KeyringController extends EventEmitter { } createNewVault(password, entropy, cb) { + const salt = generateNewSalt() + this.configManager.setSalt(salt) this.loadKey(password) .then((key) => { return encryptor.encryptWithKey(key, {}) }) - .then((encryptedString) => { + .then((encryptedString) => { this.configManager.setVault(encryptedString) cb(null, this.getState()) }) @@ -90,7 +61,8 @@ module.exports = class KeyringController extends EventEmitter { } loadKey(password) { - return encryptor.keyFromPassword(password) + const salt = this.configManager.getSalt() + return encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key return key @@ -141,5 +113,8 @@ module.exports = class KeyringController extends EventEmitter { } function generateSalt (byteCount) { - return bitcore.crypto.Random.getRandomBuffer(byteCount || 32).toString('base64') + var view = new Uint8Array(32) + global.crypto.getRandomValues(view) + var b64encoded = btoa(String.fromCharCode.apply(null, view)) + return b64encoded } -- cgit v1.2.3 From 0deed1775237bc8d48eb41e83b5a661b55e4b6be Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 12:07:53 -0700 Subject: Fix tests --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index f6b1e9358..d25dddba1 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -35,7 +35,7 @@ module.exports = class KeyringController extends EventEmitter { } createNewVault(password, entropy, cb) { - const salt = generateNewSalt() + const salt = generateSalt() this.configManager.setSalt(salt) this.loadKey(password) .then((key) => { -- cgit v1.2.3 From 55d56f77cf42a9c4e80768fd7e4a9bb6f0485606 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 16:44:31 -0700 Subject: Began adding first basic keyring --- app/scripts/keyring-controller.js | 111 +++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 8 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index d25dddba1..86d61b22b 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,7 +1,13 @@ const EventEmitter = require('events').EventEmitter const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') +const ethUtil = require('ethereumjs-util') +// Keyrings: +const SimpleKeyring = require('./keyrings/simple') +const keyringTypes = [ + SimpleKeyring, +] module.exports = class KeyringController extends EventEmitter { @@ -9,14 +15,15 @@ module.exports = class KeyringController extends EventEmitter { super() this.configManager = opts.configManager this.ethStore = opts.ethStore - this.keyChains = [] + this.keyrings = [] + this.identities = {} // Essentially a nickname hash } getState() { return { isInitialized: !!this.configManager.getVault(), isUnlocked: !!this.key, - isConfirmed: true, // this.configManager.getConfirmed(), + isConfirmed: true, // AUDIT this.configManager.getConfirmed(), isEthConfirmed: this.configManager.getShouldntShowWarning(), unconfTxs: this.configManager.unconfirmedTxs(), transactions: this.configManager.getTxList(), @@ -27,6 +34,8 @@ module.exports = class KeyringController extends EventEmitter { currentFiat: this.configManager.getCurrentFiat(), conversionRate: this.configManager.getConversionRate(), conversionDate: this.configManager.getConversionDate(), + keyringTypes: keyringTypes.map((krt) => krt.type()), + identities: this.identities, } } @@ -39,7 +48,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSalt(salt) this.loadKey(password) .then((key) => { - return encryptor.encryptWithKey(key, {}) + return encryptor.encryptWithKey(key, []) }) .then((encryptedString) => { this.configManager.setVault(encryptedString) @@ -53,6 +62,10 @@ module.exports = class KeyringController extends EventEmitter { submitPassword(password, cb) { this.loadKey(password) .then((key) => { + return this.unlockKeyrings(key) + }) + .then((keyrings) => { + this.keyrings = keyrings cb(null, this.getState()) }) .catch((err) => { @@ -69,8 +82,94 @@ module.exports = class KeyringController extends EventEmitter { }) } + addNewKeyring(type, opts, cb) { + const i = this.getAccounts().length + const Keyring = this.getKeyringClassForType(type) + const keyring = new Keyring(opts) + const accounts = keyring.addAccounts(1) + + accounts.forEach((account) => { + this.createBalanceAndNickname(account, i) + }) + + this.persistAllKeyrings() + .then(() => { + cb(this.getState()) + }) + .catch((reason) => { + cb(reason) + }) + } + + // Takes an account address and an iterator representing + // the current number of nicknamed accounts. + createBalanceAndNickname(account, i) { + this.ethStore.addAccount(ethUtil.addHexPrefix(account)) + const oldNickname = this.configManager.nicknameForWallet(account) + const nickname = oldNickname || `Account ${++i}` + this.identities[account] = { + address: account, + nickname, + } + this.saveAccountLabel(account, nickname) + } + + saveAccountLabel (account, label, cb) { + const configManager = this.configManager + configManager.setNicknameForWallet(account, label) + if (cb) { + cb(null, label) + } + } + + persistAllKeyrings() { + const serialized = this.keyrings.map(k => k.serialize()) + return encryptor.encryptWithKey(this.key, serialized) + .then((encryptedString) => { + this.configManager.setVault(encryptedString) + return true + }) + .catch((reason) => { + console.error('Failed to persist keyrings.', reason) + }) + } + + unlockKeyrings(key) { + const encryptedVault = this.configManager.getVault() + return encryptor.decryptWithKey(key, encryptedVault) + .then((vault) => { + this.keyrings = vault.map(this.restoreKeyring) + return this.keyrings + }) + } + + restoreKeyring(serialized) { + const { type } = serialized + const Keyring = this.getKeyringClassForType(type) + const keyring = new Keyring(serialized) + return keyring + } + + getKeyringClassForType(type) { + const Keyring = keyringTypes.reduce((res, kr) => { + if (kr.type() === type) { + return kr + } else { + return res + } + }) + return Keyring + } + + getAccounts() { + return this.keyrings.map(kr => kr.getAccounts()) + .reduce((res, arr) => { + return res.concat(arr) + }, []) + } + setSelectedAddress(address, cb) { - this.selectedAddress = address + this.configManager.setSelectedAccount(address) cb(null, address) } @@ -102,10 +201,6 @@ module.exports = class KeyringController extends EventEmitter { cb(null, '0xPrivateKey') } - saveAccountLabel(account, label, cb) { - cb(/* null, label */) - } - tryPassword(password, cb) { cb() } -- cgit v1.2.3 From 957b7a72b55be864320a346108673d02448caefd Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 17:24:03 -0700 Subject: Improved simple account generation --- app/scripts/keyring-controller.js | 61 ++++++++++++++++++++++++--------------- 1 file changed, 38 insertions(+), 23 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 86d61b22b..7179f756a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -16,7 +16,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager = opts.configManager this.ethStore = opts.ethStore this.keyrings = [] - this.identities = {} // Essentially a nickname hash + this.identities = {} // Essentially a name hash } getState() { @@ -64,8 +64,7 @@ module.exports = class KeyringController extends EventEmitter { .then((key) => { return this.unlockKeyrings(key) }) - .then((keyrings) => { - this.keyrings = keyrings + .then(() => { cb(null, this.getState()) }) .catch((err) => { @@ -74,7 +73,7 @@ module.exports = class KeyringController extends EventEmitter { } loadKey(password) { - const salt = this.configManager.getSalt() + const salt = this.configManager.getSalt() || generateSalt() return encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key @@ -89,9 +88,10 @@ module.exports = class KeyringController extends EventEmitter { const accounts = keyring.addAccounts(1) accounts.forEach((account) => { - this.createBalanceAndNickname(account, i) + this.loadBalanceAndNickname(account, i) }) + this.keyrings.push(keyring) this.persistAllKeyrings() .then(() => { cb(this.getState()) @@ -102,28 +102,36 @@ module.exports = class KeyringController extends EventEmitter { } // Takes an account address and an iterator representing - // the current number of nicknamed accounts. - createBalanceAndNickname(account, i) { - this.ethStore.addAccount(ethUtil.addHexPrefix(account)) - const oldNickname = this.configManager.nicknameForWallet(account) - const nickname = oldNickname || `Account ${++i}` - this.identities[account] = { - address: account, - nickname, + // the current number of named accounts. + loadBalanceAndNickname(account, i) { + const address = ethUtil.addHexPrefix(account) + this.ethStore.addAccount(address) + const oldNickname = this.configManager.nicknameForWallet(address) + const name = oldNickname || `Account ${++i}` + this.identities[address] = { + address, + name, } - this.saveAccountLabel(account, nickname) + this.saveAccountLabel(address, name) } saveAccountLabel (account, label, cb) { + const address = ethUtil.addHexPrefix(account) const configManager = this.configManager - configManager.setNicknameForWallet(account, label) + configManager.setNicknameForWallet(address, label) if (cb) { cb(null, label) } } persistAllKeyrings() { - const serialized = this.keyrings.map(k => k.serialize()) + const serialized = this.keyrings.map((k) => { + return { + type: k.type, + // keyring.serialize() must return a JSON-encodable object. + data: k.serialize(), + } + }) return encryptor.encryptWithKey(this.key, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) @@ -138,15 +146,21 @@ module.exports = class KeyringController extends EventEmitter { const encryptedVault = this.configManager.getVault() return encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { - this.keyrings = vault.map(this.restoreKeyring) + this.keyrings = vault.map(this.restoreKeyring.bind(this, 0)) return this.keyrings }) } - restoreKeyring(serialized) { - const { type } = serialized + restoreKeyring(serialized, i) { + const { type, data } = serialized const Keyring = this.getKeyringClassForType(type) - const keyring = new Keyring(serialized) + const keyring = new Keyring() + keyring.deserialize(data) + + keyring.getAccounts().forEach((account) => { + this.loadBalanceAndNickname(account, i) + }) + return keyring } @@ -162,7 +176,8 @@ module.exports = class KeyringController extends EventEmitter { } getAccounts() { - return this.keyrings.map(kr => kr.getAccounts()) + const keyrings = this.keyrings || [] + return keyrings.map(kr => kr.getAccounts()) .reduce((res, arr) => { return res.concat(arr) }, []) @@ -207,8 +222,8 @@ module.exports = class KeyringController extends EventEmitter { } -function generateSalt (byteCount) { - var view = new Uint8Array(32) +function generateSalt (byteCount = 32) { + var view = new Uint8Array(byteCount) global.crypto.getRandomValues(view) var b64encoded = btoa(String.fromCharCode.apply(null, view)) return b64encoded -- cgit v1.2.3 From 9560ae93ee66cd9466c95c98b6853c2062f21235 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 20 Oct 2016 19:01:04 -0700 Subject: Added tx and msg signing to keychain & controller --- app/scripts/keyring-controller.js | 56 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 55 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 7179f756a..7ebcc6b2c 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -2,6 +2,8 @@ const EventEmitter = require('events').EventEmitter const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') const ethUtil = require('ethereumjs-util') +const BN = ethUtil.BN +const Transaction = require('ethereumjs-tx') // Keyrings: const SimpleKeyring = require('./keyrings/simple') @@ -198,8 +200,60 @@ module.exports = class KeyringController extends EventEmitter { } } + signTransaction(txParams, cb) { + try { + const address = ethUtil.addHexPrefix(txParams.from.toLowercase()) + const keyring = this.getKeyringForAccount(address) + + // Handle gas pricing + var gasMultiplier = this.configManager.getGasMultiplier() || 1 + var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice), 16) + gasPrice = gasPrice.mul(new BN(gasMultiplier * 100, 10)).div(new BN(100, 10)) + txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber()) + + // normalize values + txParams.to = ethUtil.addHexPrefix(txParams.to.toLowerCase()) + txParams.from = ethUtil.addHexPrefix(txParams.from.toLowerCase()) + txParams.value = ethUtil.addHexPrefix(txParams.value) + txParams.data = ethUtil.addHexPrefix(txParams.data) + txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas) + txParams.nonce = ethUtil.addHexPrefix(txParams.nonce) + + let tx = new Transaction(txParams) + tx = keyring.signTransaction(address, tx) + + // Add the tx hash to the persisted meta-tx object + var txHash = ethUtil.bufferToHex(tx.hash()) + var metaTx = this.configManager.getTx(txParams.metamaskId) + metaTx.hash = txHash + this.configManager.updateTx(metaTx) + + // return raw serialized tx + var rawTx = ethUtil.bufferToHex(tx.serialize()) + cb(null, rawTx) + } catch (e) { + cb(e) + } + } + signMessage(msgParams, cb) { - cb() + try { + const keyring = this.getKeyringForAccount(msgParams.from) + const address = ethUtil.addHexPrefix(msgParams.from.toLowercase()) + const rawSig = keyring.signMessage(address, msgParams.data) + cb(null, rawSig) + } catch (e) { + cb(e) + } + } + + getKeyringForAccount(address) { + const hexed = ethUtil.addHexPrefix(address.toLowerCase()) + return this.keyrings.find((ring) => { + return ring.getAccounts() + .map(acct => ethUtil.addHexPrefix(acct.toLowerCase())) + .includes(hexed) + }) } cancelMessage(msgId, cb) { -- cgit v1.2.3 From c3e1c5c57f2062155626647e239c2a760f3e4b8a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 21 Oct 2016 11:10:36 -0700 Subject: Added SimpleKeyring tests --- app/scripts/keyring-controller.js | 2 ++ 1 file changed, 2 insertions(+) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 7ebcc6b2c..8192ed790 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -263,6 +263,8 @@ module.exports = class KeyringController extends EventEmitter { } setLocked(cb) { + this.key = null + this.keyrings = [] cb() } -- cgit v1.2.3 From 44aa1be2778a1647c9a607fd02c61bf93704d92d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 21 Oct 2016 12:11:54 -0700 Subject: Create basic keyring-controller unit test file --- app/scripts/keyring-controller.js | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 8192ed790..5cf2542cc 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -17,6 +17,7 @@ module.exports = class KeyringController extends EventEmitter { super() this.configManager = opts.configManager this.ethStore = opts.ethStore + this.encryptor = encryptor this.keyrings = [] this.identities = {} // Essentially a name hash } @@ -46,11 +47,11 @@ module.exports = class KeyringController extends EventEmitter { } createNewVault(password, entropy, cb) { - const salt = generateSalt() + const salt = this.encryptor.generateSalt() this.configManager.setSalt(salt) this.loadKey(password) .then((key) => { - return encryptor.encryptWithKey(key, []) + return this.encryptor.encryptWithKey(key, []) }) .then((encryptedString) => { this.configManager.setVault(encryptedString) @@ -75,8 +76,8 @@ module.exports = class KeyringController extends EventEmitter { } loadKey(password) { - const salt = this.configManager.getSalt() || generateSalt() - return encryptor.keyFromPassword(password + salt) + const salt = this.configManager.getSalt() || this.encryptor.generateSalt() + return this.encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key return key @@ -134,7 +135,7 @@ module.exports = class KeyringController extends EventEmitter { data: k.serialize(), } }) - return encryptor.encryptWithKey(this.key, serialized) + return this.encryptor.encryptWithKey(this.key, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) return true @@ -146,7 +147,7 @@ module.exports = class KeyringController extends EventEmitter { unlockKeyrings(key) { const encryptedVault = this.configManager.getVault() - return encryptor.decryptWithKey(key, encryptedVault) + return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { this.keyrings = vault.map(this.restoreKeyring.bind(this, 0)) return this.keyrings @@ -278,9 +279,3 @@ module.exports = class KeyringController extends EventEmitter { } -function generateSalt (byteCount = 32) { - var view = new Uint8Array(byteCount) - global.crypto.getRandomValues(view) - var b64encoded = btoa(String.fromCharCode.apply(null, view)) - return b64encoded -} -- cgit v1.2.3 From 626b52d24a3db05bf4f4e05df53f886615cc9538 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 21 Oct 2016 13:11:30 -0700 Subject: Fix bug in new KeyringController vault restoring logic. --- app/scripts/keyring-controller.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 5cf2542cc..807752a94 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -18,6 +18,8 @@ module.exports = class KeyringController extends EventEmitter { this.configManager = opts.configManager this.ethStore = opts.ethStore this.encryptor = encryptor + this.keyringTypes = keyringTypes + this.keyrings = [] this.identities = {} // Essentially a name hash } @@ -37,7 +39,7 @@ module.exports = class KeyringController extends EventEmitter { currentFiat: this.configManager.getCurrentFiat(), conversionRate: this.configManager.getConversionRate(), conversionDate: this.configManager.getConversionDate(), - keyringTypes: keyringTypes.map((krt) => krt.type()), + keyringTypes: this.keyringTypes.map((krt) => krt.type()), identities: this.identities, } } @@ -154,7 +156,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - restoreKeyring(serialized, i) { + restoreKeyring(i, serialized) { const { type, data } = serialized const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() @@ -168,7 +170,7 @@ module.exports = class KeyringController extends EventEmitter { } getKeyringClassForType(type) { - const Keyring = keyringTypes.reduce((res, kr) => { + const Keyring = this.keyringTypes.reduce((res, kr) => { if (kr.type() === type) { return kr } else { -- cgit v1.2.3 From 1ddb8b9aec02e5e38a6eed8eeea1733ee3cd99c0 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 21 Oct 2016 13:41:33 -0700 Subject: Added tx & msg managing functionality to new KeyringController --- app/scripts/keyring-controller.js | 148 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 807752a94..45deb40c8 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,9 +1,13 @@ +const async = require('async') const EventEmitter = require('events').EventEmitter const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') const ethUtil = require('ethereumjs-util') +const ethBinToOps = require('eth-bin-to-ops') +const EthQuery = require('eth-query') const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') +const createId = require('web3-provider-engine/util/random-id') // Keyrings: const SimpleKeyring = require('./keyrings/simple') @@ -15,6 +19,7 @@ module.exports = class KeyringController extends EventEmitter { constructor (opts) { super() + this.web3 = opts.web3 this.configManager = opts.configManager this.ethStore = opts.ethStore this.encryptor = encryptor @@ -22,6 +27,11 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings = [] this.identities = {} // Essentially a name hash + + this._unconfTxCbs = {} + this._unconfMsgCbs = {} + + this.network = 'loading' } getState() { @@ -41,6 +51,7 @@ module.exports = class KeyringController extends EventEmitter { conversionDate: this.configManager.getConversionDate(), keyringTypes: this.keyringTypes.map((krt) => krt.type()), identities: this.identities, + network: this.network, } } @@ -193,11 +204,121 @@ module.exports = class KeyringController extends EventEmitter { cb(null, address) } + addUnconfirmedTransaction(txParams, onTxDoneCb, cb) { + var self = this + const configManager = this.configManager + + // create txData obj with parameters and meta data + var time = (new Date()).getTime() + var txId = createId() + txParams.metamaskId = txId + txParams.metamaskNetworkId = this.network + var txData = { + id: txId, + txParams: txParams, + time: time, + status: 'unconfirmed', + gasMultiplier: configManager.getGasMultiplier() || 1, + } + + console.log('addUnconfirmedTransaction:', txData) + + // keep the onTxDoneCb around for after approval/denial (requires user interaction) + // This onTxDoneCb fires completion to the Dapp's write operation. + this._unconfTxCbs[txId] = onTxDoneCb + + var provider = this.ethStore._query.currentProvider + var query = new EthQuery(provider) + + // calculate metadata for tx + async.parallel([ + analyzeForDelegateCall, + estimateGas, + ], didComplete) + + // perform static analyis on the target contract code + function analyzeForDelegateCall(cb){ + if (txParams.to) { + query.getCode(txParams.to, function (err, result) { + if (err) return cb(err) + var code = ethUtil.toBuffer(result) + if (code !== '0x') { + var ops = ethBinToOps(code) + var containsDelegateCall = ops.some((op) => op.name === 'DELEGATECALL') + txData.containsDelegateCall = containsDelegateCall + cb() + } else { + cb() + } + }) + } else { + cb() + } + } + + function estimateGas(cb){ + query.estimateGas(txParams, function(err, result){ + if (err) return cb(err) + txData.estimatedGas = self.addGasBuffer(result) + cb() + }) + } + + function didComplete (err) { + if (err) return cb(err) + configManager.addTx(txData) + // signal update + self.emit('update') + // signal completion of add tx + cb(null, txData) + } + } + + addUnconfirmedMessage(msgParams, cb) { + // create txData obj with parameters and meta data + var time = (new Date()).getTime() + var msgId = createId() + var msgData = { + id: msgId, + msgParams: msgParams, + time: time, + status: 'unconfirmed', + } + messageManager.addMsg(msgData) + console.log('addUnconfirmedMessage:', msgData) + + // keep the cb around for after approval (requires user interaction) + // This cb fires completion to the Dapp's write operation. + this._unconfMsgCbs[msgId] = cb + + // signal update + this.emit('update') + return msgId + } + approveTransaction(txId, cb) { + const configManager = this.configManager + var approvalCb = this._unconfTxCbs[txId] || noop + + // accept tx cb() + approvalCb(null, true) + // clean up + configManager.confirmTx(txId) + delete this._unconfTxCbs[txId] + this.emit('update') } cancelTransaction(txId, cb) { + const configManager = this.configManager + var approvalCb = this._unconfTxCbs[txId] || noop + + // reject tx + approvalCb(null, false) + // clean up + configManager.rejectTx(txId) + delete this._unconfTxCbs[txId] + if (cb && typeof cb === 'function') { cb() } @@ -279,5 +400,32 @@ module.exports = class KeyringController extends EventEmitter { cb() } + getNetwork(err) { + if (err) { + this.network = 'loading' + this.emit('update') + } + + this.web3.version.getNetwork((err, network) => { + if (err) { + this.network = 'loading' + return this.emit('update') + } + if (global.METAMASK_DEBUG) { + console.log('web3.getNetwork returned ' + network) + } + this.network = network + this.emit('update') + }) + } + + addGasBuffer(gasHex) { + var gas = new BN(gasHex, 16) + var buffer = new BN('100000', 10) + var result = gas.add(buffer) + return ethUtil.addHexPrefix(result.toString(16)) + } + } +function noop () {} -- cgit v1.2.3 From 518ff399fbf17bc747d956bbb64ca76f6bbd4057 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 21 Oct 2016 14:11:04 -0700 Subject: Fix loading indication --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 45deb40c8..28c920d22 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -31,7 +31,7 @@ module.exports = class KeyringController extends EventEmitter { this._unconfTxCbs = {} this._unconfMsgCbs = {} - this.network = 'loading' + this.network = null } getState() { -- cgit v1.2.3 From 678301a20e6112d79a052c13f921bb75c451c613 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 25 Oct 2016 13:24:03 -0700 Subject: Phase out extra warning screen. --- app/scripts/keyring-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 28c920d22..5e7900b10 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -39,7 +39,6 @@ module.exports = class KeyringController extends EventEmitter { isInitialized: !!this.configManager.getVault(), isUnlocked: !!this.key, isConfirmed: true, // AUDIT this.configManager.getConfirmed(), - isEthConfirmed: this.configManager.getShouldntShowWarning(), unconfTxs: this.configManager.unconfirmedTxs(), transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), -- cgit v1.2.3 From 6ec471c6dcc52a9d2b599b849fa5017f3056fd43 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 28 Oct 2016 12:10:35 -0700 Subject: Configure BIP44 Keychain as default one --- app/scripts/keyring-controller.js | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 5e7900b10..3ac101ad8 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -11,8 +11,10 @@ const createId = require('web3-provider-engine/util/random-id') // Keyrings: const SimpleKeyring = require('./keyrings/simple') +const HdKeyring = require('./keyrings/hd') const keyringTypes = [ SimpleKeyring, + HdKeyring, ] module.exports = class KeyringController extends EventEmitter { @@ -67,7 +69,12 @@ module.exports = class KeyringController extends EventEmitter { }) .then((encryptedString) => { this.configManager.setVault(encryptedString) - cb(null, this.getState()) + + // TEMPORARY SINGLE-KEYRING CONFIG: + this.addNewKeyring('HD Key Tree', null, cb) + + // NORMAL BEHAVIOR: + // cb(null, this.getState()) }) .catch((err) => { cb(err) @@ -97,25 +104,35 @@ module.exports = class KeyringController extends EventEmitter { } addNewKeyring(type, opts, cb) { - const i = this.getAccounts().length const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) const accounts = keyring.addAccounts(1) - accounts.forEach((account) => { - this.loadBalanceAndNickname(account, i) - }) - + this.setupAccounts(accounts) this.keyrings.push(keyring) this.persistAllKeyrings() .then(() => { - cb(this.getState()) + cb(null, this.getState()) }) .catch((reason) => { cb(reason) }) } + addNewAccount(keyRingNum = 0, cb) { + const ring = this.keyrings[keyRingNum] + const accounts = ring.addAccounts(1) + this.setupAccounts(accounts) + cb(null, this.getState()) + } + + setupAccounts(accounts) { + const i = this.getAccounts().length + accounts.forEach((account) => { + this.loadBalanceAndNickname(account, i) + }) + } + // Takes an account address and an iterator representing // the current number of named accounts. loadBalanceAndNickname(account, i) { -- cgit v1.2.3 From 18e5173f061c2e21b5acb3e1b329343b5cffc558 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Sat, 29 Oct 2016 02:29:25 -0700 Subject: Now migrating old vaults to new DEN format --- app/scripts/keyring-controller.js | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3ac101ad8..b8066e303 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,6 +9,9 @@ const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') const createId = require('web3-provider-engine/util/random-id') +// TEMPORARY UNTIL FULL DEPRECATION: +const IdStoreMigrator = require('./lib/idStore-migrator') + // Keyrings: const SimpleKeyring = require('./keyrings/simple') const HdKeyring = require('./keyrings/hd') @@ -34,6 +37,11 @@ module.exports = class KeyringController extends EventEmitter { this._unconfMsgCbs = {} this.network = null + + // TEMPORARY UNTIL FULL DEPRECATION: + this.idStoreMigrator = new IdStoreMigrator({ + configManager: this.configManager, + }) } getState() { @@ -63,18 +71,32 @@ module.exports = class KeyringController extends EventEmitter { createNewVault(password, entropy, cb) { const salt = this.encryptor.generateSalt() this.configManager.setSalt(salt) - this.loadKey(password) + + let serialized + + this.idStoreMigrator.oldSeedForPassword(password) + .then((oldSerialized) => { + if (oldSerialized) { + serialized = oldSerialized + } + return this.loadKey(password) + }) .then((key) => { - return this.encryptor.encryptWithKey(key, []) + const first = serialized ? [serialized] : [] + return this.encryptor.encryptWithKey(key, first) }) .then((encryptedString) => { this.configManager.setVault(encryptedString) - // TEMPORARY SINGLE-KEYRING CONFIG: - this.addNewKeyring('HD Key Tree', null, cb) + if (!serialized) { + // TEMPORARY SINGLE-KEYRING CONFIG: + return this.addNewKeyring('HD Key Tree', null, cb) + } else { + return this.submitPassword(password, cb) + } // NORMAL BEHAVIOR: - // cb(null, this.getState()) + // return cb(null, this.getState()) }) .catch((err) => { cb(err) @@ -99,6 +121,7 @@ module.exports = class KeyringController extends EventEmitter { return this.encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key + this.configManager.setSalt(salt) return key }) } -- cgit v1.2.3 From 6fc498f8a030ea00bcef9b8b3400fc527fc4aeed Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 31 Oct 2016 09:47:20 -0700 Subject: Implement auto-fauceting --- app/scripts/keyring-controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b8066e303..e7b9612bf 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -8,6 +8,7 @@ const EthQuery = require('eth-query') const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') const createId = require('web3-provider-engine/util/random-id') +const autoFaucet = require('./lib/auto-faucet') // TEMPORARY UNTIL FULL DEPRECATION: const IdStoreMigrator = require('./lib/idStore-migrator') @@ -90,7 +91,11 @@ module.exports = class KeyringController extends EventEmitter { if (!serialized) { // TEMPORARY SINGLE-KEYRING CONFIG: - return this.addNewKeyring('HD Key Tree', null, cb) + return this.addNewKeyring('HD Key Tree', null, (err, newState) => { + const firstAccount = this.keyrings[0].getAccounts()[0] + autoFaucet(ethUtil.addHexPrefix(firstAccount)) + cb(err, newState) + }) } else { return this.submitPassword(password, cb) } -- cgit v1.2.3 From 96643c222a74552d98218fe1f9fc81e493a1960f Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 31 Oct 2016 11:35:09 -0700 Subject: Implement seed word confirmation page. Remove logs. Move HD render files to ui/app. --- app/scripts/keyring-controller.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index e7b9612bf..ee6445121 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -47,6 +47,7 @@ module.exports = class KeyringController extends EventEmitter { getState() { return { + seedWords: this.configManager.getSeedWords(), isInitialized: !!this.configManager.getVault(), isUnlocked: !!this.key, isConfirmed: true, // AUDIT this.configManager.getConfirmed(), @@ -90,10 +91,14 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setVault(encryptedString) if (!serialized) { - // TEMPORARY SINGLE-KEYRING CONFIG: - return this.addNewKeyring('HD Key Tree', null, (err, newState) => { - const firstAccount = this.keyrings[0].getAccounts()[0] - autoFaucet(ethUtil.addHexPrefix(firstAccount)) + this.addNewKeyring('HD Key Tree', null, (err, newState) => { + const firstKeyring = this.keyrings[0] + const firstAccount = firstKeyring.getAccounts()[0] + const hexAccount = ethUtil.addHexPrefix(firstAccount) + const seedWords = firstKeyring.serialize().mnemonic + this.configManager.setSelectedAccount(hexAccount) + this.configManager.setSeedWords(seedWords) + autoFaucet(hexAccount) cb(err, newState) }) } else { @@ -470,6 +475,11 @@ module.exports = class KeyringController extends EventEmitter { return ethUtil.addHexPrefix(result.toString(16)) } + clearSeedWordCache(cb) { + this.configManager.setSeedWords(null) + cb(null, this.configManager.getSelectedAccount()) + } + } function noop () {} -- cgit v1.2.3 From db356a181a3fde4ad528c699f6da517053171866 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 1 Nov 2016 11:25:38 -0700 Subject: Made progress on parity for MultiVault - Deleted some unused items - Renamed files and paths to match with new locations. - Modified keyring controller logic to separate concerns. - Fix account naming issues. - Enable creation of new vault with default HD keyring. - Formatting issues. --- app/scripts/keyring-controller.js | 65 ++++++++++++++++++++++++++------------- 1 file changed, 44 insertions(+), 21 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index ee6445121..f6e71b005 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -70,6 +70,23 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = ethStore } + createNewVaultAndKeychain(password, entropy, cb) { + this.createNewVault(password, entropy, (err, serialized) => { + if (err) return cb(err) + this.createFirstKeyTree(serialized, password, cb) + }) + } + + createNewVaultAndRestore(password, seed, cb) { + this.createNewVault(password, '', (err) => { + if (err) return cb(err) + this.addNewKeyring('HD Key Tree', { + mnemonic: seed, + n: 0, + }, cb) + }) + } + createNewVault(password, entropy, cb) { const salt = this.encryptor.generateSalt() this.configManager.setSalt(salt) @@ -89,22 +106,7 @@ module.exports = class KeyringController extends EventEmitter { }) .then((encryptedString) => { this.configManager.setVault(encryptedString) - - if (!serialized) { - this.addNewKeyring('HD Key Tree', null, (err, newState) => { - const firstKeyring = this.keyrings[0] - const firstAccount = firstKeyring.getAccounts()[0] - const hexAccount = ethUtil.addHexPrefix(firstAccount) - const seedWords = firstKeyring.serialize().mnemonic - this.configManager.setSelectedAccount(hexAccount) - this.configManager.setSeedWords(seedWords) - autoFaucet(hexAccount) - cb(err, newState) - }) - } else { - return this.submitPassword(password, cb) - } - + cb(null, serialized) // NORMAL BEHAVIOR: // return cb(null, this.getState()) }) @@ -113,6 +115,23 @@ module.exports = class KeyringController extends EventEmitter { }) } + createFirstKeyTree(serialized, password, cb) { + if (!serialized) { + this.addNewKeyring('HD Key Tree', {n: 1}, (err, newState) => { + const firstKeyring = this.keyrings[0] + const firstAccount = firstKeyring.getAccounts()[0] + const hexAccount = ethUtil.addHexPrefix(firstAccount) + const seedWords = firstKeyring.serialize().mnemonic + this.configManager.setSelectedAccount(hexAccount) + this.configManager.setSeedWords(seedWords) + autoFaucet(hexAccount) + cb(err, this.getState()) + }) + } else { + return this.submitPassword(password, cb) + } + } + submitPassword(password, cb) { this.loadKey(password) .then((key) => { @@ -139,10 +158,10 @@ module.exports = class KeyringController extends EventEmitter { addNewKeyring(type, opts, cb) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) - const accounts = keyring.addAccounts(1) + const accounts = keyring.getAccounts() - this.setupAccounts(accounts) this.keyrings.push(keyring) + this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { cb(null, this.getState()) @@ -160,17 +179,21 @@ module.exports = class KeyringController extends EventEmitter { } setupAccounts(accounts) { - const i = this.getAccounts().length accounts.forEach((account) => { - this.loadBalanceAndNickname(account, i) + this.loadBalanceAndNickname(account) }) } // Takes an account address and an iterator representing // the current number of named accounts. - loadBalanceAndNickname(account, i) { + loadBalanceAndNickname(account) { const address = ethUtil.addHexPrefix(account) this.ethStore.addAccount(address) + this.createNickname(address) + } + + createNickname(address) { + var i = Object.keys(this.identities).length const oldNickname = this.configManager.nicknameForWallet(address) const name = oldNickname || `Account ${++i}` this.identities[address] = { -- cgit v1.2.3 From 498b30bddcfa16f587a9f62b74a5d9fceb04cb07 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 1 Nov 2016 11:51:51 -0700 Subject: Fix seed phrase restore --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index f6e71b005..2681b3d48 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -82,7 +82,7 @@ module.exports = class KeyringController extends EventEmitter { if (err) return cb(err) this.addNewKeyring('HD Key Tree', { mnemonic: seed, - n: 0, + n: 1, }, cb) }) } -- cgit v1.2.3 From b5f6ef8c013f2f742546a04e148bac99fbc4691c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 1 Nov 2016 17:00:17 -0700 Subject: Fixed bugs related to clearing caches when restoring to a new vault --- app/scripts/keyring-controller.js | 51 ++++++++++++++++++++++++++++++++++----- 1 file changed, 45 insertions(+), 6 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 2681b3d48..b93d4a156 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,6 +9,7 @@ const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') const createId = require('web3-provider-engine/util/random-id') const autoFaucet = require('./lib/auto-faucet') +const bip39 = require('bip39') // TEMPORARY UNTIL FULL DEPRECATION: const IdStoreMigrator = require('./lib/idStore-migrator') @@ -46,6 +47,8 @@ module.exports = class KeyringController extends EventEmitter { } getState() { + let address = this.configManager.getSelectedAccount() + return { seedWords: this.configManager.getSeedWords(), isInitialized: !!this.configManager.getVault(), @@ -55,7 +58,8 @@ module.exports = class KeyringController extends EventEmitter { transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), - selectedAddress: this.configManager.getSelectedAccount(), + selectedAddress: address, + selectedAccount: address, shapeShiftTxList: this.configManager.getShapeShiftTxList(), currentFiat: this.configManager.getCurrentFiat(), conversionRate: this.configManager.getConversionRate(), @@ -78,12 +82,33 @@ module.exports = class KeyringController extends EventEmitter { } createNewVaultAndRestore(password, seed, cb) { + if (typeof password !== 'string') { + return cb('Password must be text.') + } + + if (!bip39.validateMnemonic(seed)) { + return cb('Seed phrase is invalid.') + } + + this.clearKeyrings() + this.createNewVault(password, '', (err) => { if (err) return cb(err) this.addNewKeyring('HD Key Tree', { mnemonic: seed, n: 1, - }, cb) + }, (err) => { + if (err) return cb(err) + const firstKeyring = this.keyrings[0] + const accounts = firstKeyring.getAccounts() + const firstAccount = accounts[0] + const hexAccount = ethUtil.addHexPrefix(firstAccount) + this.configManager.setSelectedAccount(hexAccount) + + this.setupAccounts(accounts) + this.emit('update') + cb(null, this.getState()) + }) }) } @@ -138,6 +163,7 @@ module.exports = class KeyringController extends EventEmitter { return this.unlockKeyrings(key) }) .then(() => { + this.emit('update') cb(null, this.getState()) }) .catch((err) => { @@ -175,6 +201,7 @@ module.exports = class KeyringController extends EventEmitter { const ring = this.keyrings[keyRingNum] const accounts = ring.addAccounts(1) this.setupAccounts(accounts) + this.persistAllKeyrings() cb(null, this.getState()) } @@ -468,10 +495,6 @@ module.exports = class KeyringController extends EventEmitter { cb(null, '0xPrivateKey') } - tryPassword(password, cb) { - cb() - } - getNetwork(err) { if (err) { this.network = 'loading' @@ -503,6 +526,22 @@ module.exports = class KeyringController extends EventEmitter { cb(null, this.configManager.getSelectedAccount()) } + clearKeyrings() { + let accounts + try { + accounts = Object.keys(this.ethStore._currentState.accounts) + } catch (e) { + accounts = [] + } + accounts.forEach((address) => { + this.ethStore.removeAccount(address) + }) + + this.keyrings = [] + this.identities = {} + this.configManager.setSelectedAccount() + } + } function noop () {} -- cgit v1.2.3 From 8f3db0dbc0bafdc604bd7359bd41370f594c792c Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 1 Nov 2016 22:19:04 -0700 Subject: Add reveal of seed words. --- app/scripts/keyring-controller.js | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b93d4a156..e6a7d95b2 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -132,8 +132,6 @@ module.exports = class KeyringController extends EventEmitter { .then((encryptedString) => { this.configManager.setVault(encryptedString) cb(null, serialized) - // NORMAL BEHAVIOR: - // return cb(null, this.getState()) }) .catch((err) => { cb(err) @@ -157,6 +155,14 @@ module.exports = class KeyringController extends EventEmitter { } } + placeSeedWords () { + const firstKeyring = this.keyrings[0] + const seedWords = firstKeyring.serialize().mnemonic + this.configManager.setSeedWords(seedWords) + } + + + submitPassword(password, cb) { this.loadKey(password) .then((key) => { -- cgit v1.2.3 From 4cf1b606e46fa735263b5e1fade5910b572335e3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 2 Nov 2016 15:04:50 -0700 Subject: Fix handling of migrating old vault style Now old vaults are recognized as an "Initialized" MetaMask instance. Upon logging in, when fetching the initial password-derived key, if there is no new-style vault, but there is an old style vault, it is migrated to the new format before proceeding through the usual unlocking steps. --- app/scripts/keyring-controller.js | 102 +++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 39 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index e6a7d95b2..1b9739b9c 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -47,11 +47,14 @@ module.exports = class KeyringController extends EventEmitter { } getState() { - let address = this.configManager.getSelectedAccount() + const configManager = this.configManager + const address = configManager.getSelectedAccount() + const wallet = configManager.getWallet() // old style vault + const vault = configManager.getVault() // new style vault return { seedWords: this.configManager.getSeedWords(), - isInitialized: !!this.configManager.getVault(), + isInitialized: (!!wallet || !!vault), isUnlocked: !!this.key, isConfirmed: true, // AUDIT this.configManager.getConfirmed(), unconfTxs: this.configManager.unconfirmedTxs(), @@ -77,7 +80,7 @@ module.exports = class KeyringController extends EventEmitter { createNewVaultAndKeychain(password, entropy, cb) { this.createNewVault(password, entropy, (err, serialized) => { if (err) return cb(err) - this.createFirstKeyTree(serialized, password, cb) + this.createFirstKeyTree(password, cb) }) } @@ -112,25 +115,43 @@ module.exports = class KeyringController extends EventEmitter { }) } - createNewVault(password, entropy, cb) { - const salt = this.encryptor.generateSalt() - this.configManager.setSalt(salt) + migrateAndGetKey(password) { + let key + const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - let serialized - - this.idStoreMigrator.oldSeedForPassword(password) - .then((oldSerialized) => { - if (oldSerialized) { - serialized = oldSerialized + return this.loadKey(password) + .then((derivedKey) => { + key = derivedKey + return this.idStoreMigrator.oldSeedForPassword(password) + }) + .then((serialized) => { + if (serialized && shouldMigrate) { + const accountLength = this.getAccounts().length + const keyring = this.restoreKeyring(accountLength, serialized) + this.keyrings.push(keyring) + this.configManager.setSelectedAccount(keyring.getAccounts()[0]) + return this.persistAllKeyrings().then(() => { + return key + }) + } else { + return Promise.resolve(key) } - return this.loadKey(password) }) - .then((key) => { - const first = serialized ? [serialized] : [] - return this.encryptor.encryptWithKey(key, first) + } + + createNewVault(password, entropy, cb) { + const configManager = this.configManager + const salt = this.encryptor.generateSalt() + configManager.setSalt(salt) + + return new Promise((res, rej) => { + this.createFirstKeyTree(password, (err, state) => { + if (err) return rej(err) + res(configManager.getVault()) + }) }) .then((encryptedString) => { - this.configManager.setVault(encryptedString) + const serialized = this.keyrings[0].serialize() cb(null, serialized) }) .catch((err) => { @@ -138,21 +159,19 @@ module.exports = class KeyringController extends EventEmitter { }) } - createFirstKeyTree(serialized, password, cb) { - if (!serialized) { - this.addNewKeyring('HD Key Tree', {n: 1}, (err, newState) => { - const firstKeyring = this.keyrings[0] - const firstAccount = firstKeyring.getAccounts()[0] - const hexAccount = ethUtil.addHexPrefix(firstAccount) - const seedWords = firstKeyring.serialize().mnemonic - this.configManager.setSelectedAccount(hexAccount) - this.configManager.setSeedWords(seedWords) - autoFaucet(hexAccount) - cb(err, this.getState()) - }) - } else { - return this.submitPassword(password, cb) - } + createFirstKeyTree(password, cb) { + this.clearKeyrings() + this.addNewKeyring('HD Key Tree', {n: 1}, (err) => { + const firstKeyring = this.keyrings[0] + const firstAccount = firstKeyring.getAccounts()[0] + const hexAccount = ethUtil.addHexPrefix(firstAccount) + const seedWords = firstKeyring.serialize().mnemonic + this.configManager.setSelectedAccount(hexAccount) + this.configManager.setSeedWords(seedWords) + autoFaucet(hexAccount) + this.persistAllKeyrings() + cb(err, this.getState()) + }) } placeSeedWords () { @@ -161,10 +180,8 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSeedWords(seedWords) } - - submitPassword(password, cb) { - this.loadKey(password) + this.migrateAndGetKey(password) .then((key) => { return this.unlockKeyrings(key) }) @@ -173,6 +190,7 @@ module.exports = class KeyringController extends EventEmitter { cb(null, this.getState()) }) .catch((err) => { + console.error(err) cb(err) }) } @@ -208,7 +226,12 @@ module.exports = class KeyringController extends EventEmitter { const accounts = ring.addAccounts(1) this.setupAccounts(accounts) this.persistAllKeyrings() - cb(null, this.getState()) + .then(() => { + cb(null, this.getState()) + }) + .catch((reason) => { + cb(reason) + }) } setupAccounts(accounts) { @@ -258,9 +281,6 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setVault(encryptedString) return true }) - .catch((reason) => { - console.error('Failed to persist keyrings.', reason) - }) } unlockKeyrings(key) { @@ -268,6 +288,9 @@ module.exports = class KeyringController extends EventEmitter { return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { this.keyrings = vault.map(this.restoreKeyring.bind(this, 0)) + return this.persistAllKeyrings() + }) + .then(() => { return this.keyrings }) } @@ -282,6 +305,7 @@ module.exports = class KeyringController extends EventEmitter { this.loadBalanceAndNickname(account, i) }) + this.keyrings.push(keyring) return keyring } -- cgit v1.2.3 From ed1917d71a464c5cf12d3dc283fcc30976134db8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 2 Nov 2016 16:18:47 -0700 Subject: Fix initial vault creation --- app/scripts/keyring-controller.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1b9739b9c..f0fb0ad65 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -122,6 +122,7 @@ module.exports = class KeyringController extends EventEmitter { return this.loadKey(password) .then((derivedKey) => { key = derivedKey + this.key = key return this.idStoreMigrator.oldSeedForPassword(password) }) .then((serialized) => { @@ -144,10 +145,13 @@ module.exports = class KeyringController extends EventEmitter { const salt = this.encryptor.generateSalt() configManager.setSalt(salt) - return new Promise((res, rej) => { - this.createFirstKeyTree(password, (err, state) => { - if (err) return rej(err) - res(configManager.getVault()) + return this.migrateAndGetKey(password) + .then((key) => { + return new Promise((res, rej) => { + this.createFirstKeyTree(password, (err, state) => { + if (err) return rej(err) + res(configManager.getVault()) + }) }) }) .then((encryptedString) => { -- cgit v1.2.3 From 185396ff08786dc108cabb57d47925032a9e2d74 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 2 Nov 2016 16:35:46 -0700 Subject: Fix dual vault creation bug --- app/scripts/keyring-controller.js | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index f0fb0ad65..3b59c7890 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -131,12 +131,10 @@ module.exports = class KeyringController extends EventEmitter { const keyring = this.restoreKeyring(accountLength, serialized) this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) - return this.persistAllKeyrings().then(() => { - return key - }) - } else { - return Promise.resolve(key) } + return this.persistAllKeyrings().then(() => { + return key + }) }) } @@ -147,12 +145,7 @@ module.exports = class KeyringController extends EventEmitter { return this.migrateAndGetKey(password) .then((key) => { - return new Promise((res, rej) => { - this.createFirstKeyTree(password, (err, state) => { - if (err) return rej(err) - res(configManager.getVault()) - }) - }) + cb(null, configManager.getVault()) }) .then((encryptedString) => { const serialized = this.keyrings[0].serialize() -- cgit v1.2.3 From 9ca3c57339571c43106306a6b4fadcfad40d3c19 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 3 Nov 2016 11:34:57 -0700 Subject: Fix vault creation bug --- app/scripts/keyring-controller.js | 30 +++++++++++++----------------- 1 file changed, 13 insertions(+), 17 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3b59c7890..3bc9561e2 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -78,7 +78,7 @@ module.exports = class KeyringController extends EventEmitter { } createNewVaultAndKeychain(password, entropy, cb) { - this.createNewVault(password, entropy, (err, serialized) => { + this.createNewVault(password, entropy, (err) => { if (err) return cb(err) this.createFirstKeyTree(password, cb) }) @@ -107,8 +107,8 @@ module.exports = class KeyringController extends EventEmitter { const firstAccount = accounts[0] const hexAccount = ethUtil.addHexPrefix(firstAccount) this.configManager.setSelectedAccount(hexAccount) - this.setupAccounts(accounts) + this.emit('update') cb(null, this.getState()) }) @@ -127,8 +127,7 @@ module.exports = class KeyringController extends EventEmitter { }) .then((serialized) => { if (serialized && shouldMigrate) { - const accountLength = this.getAccounts().length - const keyring = this.restoreKeyring(accountLength, serialized) + const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) } @@ -144,12 +143,8 @@ module.exports = class KeyringController extends EventEmitter { configManager.setSalt(salt) return this.migrateAndGetKey(password) - .then((key) => { - cb(null, configManager.getVault()) - }) - .then((encryptedString) => { - const serialized = this.keyrings[0].serialize() - cb(null, serialized) + .then(() => { + cb(null) }) .catch((err) => { cb(err) @@ -160,12 +155,14 @@ module.exports = class KeyringController extends EventEmitter { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {n: 1}, (err) => { const firstKeyring = this.keyrings[0] - const firstAccount = firstKeyring.getAccounts()[0] + const accounts = firstKeyring.getAccounts() + const firstAccount = accounts[0] const hexAccount = ethUtil.addHexPrefix(firstAccount) const seedWords = firstKeyring.serialize().mnemonic - this.configManager.setSelectedAccount(hexAccount) + this.configManager.setSelectedAccount(firstAccount) this.configManager.setSeedWords(seedWords) autoFaucet(hexAccount) + this.setupAccounts(accounts) this.persistAllKeyrings() cb(err, this.getState()) }) @@ -284,7 +281,7 @@ module.exports = class KeyringController extends EventEmitter { const encryptedVault = this.configManager.getVault() return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { - this.keyrings = vault.map(this.restoreKeyring.bind(this, 0)) + this.keyrings = vault.map(this.restoreKeyring.bind(this)) return this.persistAllKeyrings() }) .then(() => { @@ -292,15 +289,14 @@ module.exports = class KeyringController extends EventEmitter { }) } - restoreKeyring(i, serialized) { + restoreKeyring(serialized) { const { type, data } = serialized const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() keyring.deserialize(data) - keyring.getAccounts().forEach((account) => { - this.loadBalanceAndNickname(account, i) - }) + const accounts = keyring.getAccounts() + this.setupAccounts(accounts) this.keyrings.push(keyring) return keyring -- cgit v1.2.3 From bd2a429a85d27fc82e76115ec136640cbfecf9e1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 3 Nov 2016 11:59:20 -0700 Subject: Fix account nicknaming bug When nicknaming, we weren't normalizing the input, and so we were retrieving with differently formatted addresses than we were persisting. --- app/scripts/keyring-controller.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3bc9561e2..06c1e2761 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -250,7 +250,7 @@ module.exports = class KeyringController extends EventEmitter { address, name, } - this.saveAccountLabel(address, name) + return this.saveAccountLabel(address, name) } saveAccountLabel (account, label, cb) { @@ -259,6 +259,8 @@ module.exports = class KeyringController extends EventEmitter { configManager.setNicknameForWallet(address, label) if (cb) { cb(null, label) + } else { + return label } } @@ -270,6 +272,7 @@ module.exports = class KeyringController extends EventEmitter { data: k.serialize(), } }) + return this.encryptor.encryptWithKey(this.key, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) -- cgit v1.2.3 From e0246975a7a40a72cc68fb3dbe5782c9c219fea2 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 3 Nov 2016 13:44:29 -0700 Subject: Finish fixing nicknaming bug --- app/scripts/keyring-controller.js | 67 +++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 28 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 06c1e2761..505414c88 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -105,7 +105,7 @@ module.exports = class KeyringController extends EventEmitter { const firstKeyring = this.keyrings[0] const accounts = firstKeyring.getAccounts() const firstAccount = accounts[0] - const hexAccount = ethUtil.addHexPrefix(firstAccount) + const hexAccount = normalize(firstAccount) this.configManager.setSelectedAccount(hexAccount) this.setupAccounts(accounts) @@ -157,14 +157,19 @@ module.exports = class KeyringController extends EventEmitter { const firstKeyring = this.keyrings[0] const accounts = firstKeyring.getAccounts() const firstAccount = accounts[0] - const hexAccount = ethUtil.addHexPrefix(firstAccount) + const hexAccount = normalize(firstAccount) const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSelectedAccount(firstAccount) this.configManager.setSeedWords(seedWords) autoFaucet(hexAccount) this.setupAccounts(accounts) this.persistAllKeyrings() - cb(err, this.getState()) + .then(() => { + cb(err, this.getState()) + }) + .catch((reason) => { + cb(reason) + }) }) } @@ -179,7 +184,9 @@ module.exports = class KeyringController extends EventEmitter { .then((key) => { return this.unlockKeyrings(key) }) - .then(() => { + .then((keyrings) => { + this.keyrings = keyrings + this.setupAccounts() this.emit('update') cb(null, this.getState()) }) @@ -229,7 +236,8 @@ module.exports = class KeyringController extends EventEmitter { } setupAccounts(accounts) { - accounts.forEach((account) => { + var arr = accounts || this.getAccounts() + arr.forEach((account) => { this.loadBalanceAndNickname(account) }) } @@ -237,26 +245,28 @@ module.exports = class KeyringController extends EventEmitter { // Takes an account address and an iterator representing // the current number of named accounts. loadBalanceAndNickname(account) { - const address = ethUtil.addHexPrefix(account) + const address = normalize(account) this.ethStore.addAccount(address) this.createNickname(address) } createNickname(address) { + const hexAddress = normalize(address) var i = Object.keys(this.identities).length const oldNickname = this.configManager.nicknameForWallet(address) const name = oldNickname || `Account ${++i}` - this.identities[address] = { - address, + this.identities[hexAddress] = { + address: hexAddress, name, } - return this.saveAccountLabel(address, name) + return this.saveAccountLabel(hexAddress, name) } saveAccountLabel (account, label, cb) { - const address = ethUtil.addHexPrefix(account) + const address = normalize(account) const configManager = this.configManager configManager.setNicknameForWallet(address, label) + this.identities[address].name = label if (cb) { cb(null, label) } else { @@ -268,7 +278,6 @@ module.exports = class KeyringController extends EventEmitter { const serialized = this.keyrings.map((k) => { return { type: k.type, - // keyring.serialize() must return a JSON-encodable object. data: k.serialize(), } }) @@ -284,10 +293,7 @@ module.exports = class KeyringController extends EventEmitter { const encryptedVault = this.configManager.getVault() return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { - this.keyrings = vault.map(this.restoreKeyring.bind(this)) - return this.persistAllKeyrings() - }) - .then(() => { + vault.forEach(this.restoreKeyring.bind(this)) return this.keyrings }) } @@ -325,8 +331,9 @@ module.exports = class KeyringController extends EventEmitter { } setSelectedAddress(address, cb) { - this.configManager.setSelectedAccount(address) - cb(null, address) + var addr = normalize(address) + this.configManager.setSelectedAccount(addr) + cb(null, addr) } addUnconfirmedTransaction(txParams, onTxDoneCb, cb) { @@ -451,7 +458,7 @@ module.exports = class KeyringController extends EventEmitter { signTransaction(txParams, cb) { try { - const address = ethUtil.addHexPrefix(txParams.from.toLowercase()) + const address = normalize(txParams.from) const keyring = this.getKeyringForAccount(address) // Handle gas pricing @@ -461,12 +468,12 @@ module.exports = class KeyringController extends EventEmitter { txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber()) // normalize values - txParams.to = ethUtil.addHexPrefix(txParams.to.toLowerCase()) - txParams.from = ethUtil.addHexPrefix(txParams.from.toLowerCase()) - txParams.value = ethUtil.addHexPrefix(txParams.value) - txParams.data = ethUtil.addHexPrefix(txParams.data) - txParams.gasLimit = ethUtil.addHexPrefix(txParams.gasLimit || txParams.gas) - txParams.nonce = ethUtil.addHexPrefix(txParams.nonce) + txParams.to = normalize(txParams.to) + txParams.from = normalize(txParams.from) + txParams.value = normalize(txParams.value) + txParams.data = normalize(txParams.data) + txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) + txParams.nonce = normalize(txParams.nonce) let tx = new Transaction(txParams) tx = keyring.signTransaction(address, tx) @@ -488,7 +495,7 @@ module.exports = class KeyringController extends EventEmitter { signMessage(msgParams, cb) { try { const keyring = this.getKeyringForAccount(msgParams.from) - const address = ethUtil.addHexPrefix(msgParams.from.toLowercase()) + const address = normalize(msgParams.from) const rawSig = keyring.signMessage(address, msgParams.data) cb(null, rawSig) } catch (e) { @@ -497,10 +504,10 @@ module.exports = class KeyringController extends EventEmitter { } getKeyringForAccount(address) { - const hexed = ethUtil.addHexPrefix(address.toLowerCase()) + const hexed = normalize(address) return this.keyrings.find((ring) => { return ring.getAccounts() - .map(acct => ethUtil.addHexPrefix(acct.toLowerCase())) + .map(normalize) .includes(hexed) }) } @@ -544,7 +551,7 @@ module.exports = class KeyringController extends EventEmitter { var gas = new BN(gasHex, 16) var buffer = new BN('100000', 10) var result = gas.add(buffer) - return ethUtil.addHexPrefix(result.toString(16)) + return normalize(result.toString(16)) } clearSeedWordCache(cb) { @@ -570,4 +577,8 @@ module.exports = class KeyringController extends EventEmitter { } +function normalize(address) { + return ethUtil.addHexPrefix(address.toLowerCase()) +} + function noop () {} -- cgit v1.2.3 From 2afc06287dfd1a87bd247234c9a04b92a8394cac Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Thu, 3 Nov 2016 15:40:23 -0700 Subject: Implement private key exporting. --- app/scripts/keyring-controller.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 505414c88..aa303c43c 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -353,7 +353,6 @@ module.exports = class KeyringController extends EventEmitter { gasMultiplier: configManager.getGasMultiplier() || 1, } - console.log('addUnconfirmedTransaction:', txData) // keep the onTxDoneCb around for after approval/denial (requires user interaction) // This onTxDoneCb fires completion to the Dapp's write operation. @@ -525,7 +524,13 @@ module.exports = class KeyringController extends EventEmitter { } exportAccount(address, cb) { - cb(null, '0xPrivateKey') + try { + const keyring = this.getKeyringForAccount(address) + const privateKey = keyring.exportAccount(normalize(address)) + cb(null, privateKey) + } catch (e) { + cb(e) + } } getNetwork(err) { -- cgit v1.2.3 From ba7d6b437f2e03a9e2bb46dcda846cee1f816ce1 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 3 Nov 2016 16:06:57 -0700 Subject: Fix password validation and persistence issue Was wiping the vault on each successful password attempt... :P --- app/scripts/keyring-controller.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index aa303c43c..81a05e133 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -131,9 +131,7 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) } - return this.persistAllKeyrings().then(() => { - return key - }) + return key }) } @@ -143,6 +141,9 @@ module.exports = class KeyringController extends EventEmitter { configManager.setSalt(salt) return this.migrateAndGetKey(password) + .then(() => { + return this.persistAllKeyrings() + }) .then(() => { cb(null) }) @@ -173,7 +174,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - placeSeedWords () { + placeSeedWords (cb) { const firstKeyring = this.keyrings[0] const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSeedWords(seedWords) -- cgit v1.2.3 From abebe51f69ea3ae02ac8d94f7fe739d754eedf7a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 3 Nov 2016 16:34:55 -0700 Subject: Add tolerance to normalize method --- app/scripts/keyring-controller.js | 1 + 1 file changed, 1 insertion(+) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 81a05e133..1ca34e0f2 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -584,6 +584,7 @@ module.exports = class KeyringController extends EventEmitter { } function normalize(address) { + if (!address) return return ethUtil.addHexPrefix(address.toLowerCase()) } -- cgit v1.2.3 From fc26a0a8991759a54409096d0c7896da86cea4b7 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 4 Nov 2016 12:11:00 -0700 Subject: Fix network checking --- app/scripts/keyring-controller.js | 22 +--------------------- 1 file changed, 1 insertion(+), 21 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1ca34e0f2..fb3091143 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -38,7 +38,7 @@ module.exports = class KeyringController extends EventEmitter { this._unconfTxCbs = {} this._unconfMsgCbs = {} - this.network = null + this.network = opts.network // TEMPORARY UNTIL FULL DEPRECATION: this.idStoreMigrator = new IdStoreMigrator({ @@ -69,7 +69,6 @@ module.exports = class KeyringController extends EventEmitter { conversionDate: this.configManager.getConversionDate(), keyringTypes: this.keyringTypes.map((krt) => krt.type()), identities: this.identities, - network: this.network, } } @@ -534,25 +533,6 @@ module.exports = class KeyringController extends EventEmitter { } } - getNetwork(err) { - if (err) { - this.network = 'loading' - this.emit('update') - } - - this.web3.version.getNetwork((err, network) => { - if (err) { - this.network = 'loading' - return this.emit('update') - } - if (global.METAMASK_DEBUG) { - console.log('web3.getNetwork returned ' + network) - } - this.network = network - this.emit('update') - }) - } - addGasBuffer(gasHex) { var gas = new BN(gasHex, 16) var buffer = new BN('100000', 10) -- cgit v1.2.3 From 553a6da0117d94a6a3be3707266bdc09e67f9103 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 7 Nov 2016 12:00:14 -0800 Subject: Fix 787 gas buffer bug --- app/scripts/keyring-controller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index fb3091143..3ebf02c44 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -533,11 +533,11 @@ module.exports = class KeyringController extends EventEmitter { } } - addGasBuffer(gasHex) { - var gas = new BN(gasHex, 16) - var buffer = new BN('100000', 10) - var result = gas.add(buffer) - return normalize(result.toString(16)) + addGasBuffer(gas) { + const gasBuffer = new BN('100000', 10) + const bnGas = new BN(ethUtil.stripHexPrefix(gas), 16) + const correct = bnGas.add(gasBuffer) + return ethUtil.addHexPrefix(correct.toString(16)) } clearSeedWordCache(cb) { -- cgit v1.2.3 From 17aac2dbc54b733aeed5f16ef2e7bd8378060ca9 Mon Sep 17 00:00:00 2001 From: Frankie Date: Thu, 10 Nov 2016 19:07:12 -0800 Subject: fix tx data so it has the network id --- app/scripts/keyring-controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3ebf02c44..5d9dd51a4 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -38,7 +38,7 @@ module.exports = class KeyringController extends EventEmitter { this._unconfTxCbs = {} this._unconfMsgCbs = {} - this.network = opts.network + this.getNetwork = opts.getNetwork // TEMPORARY UNTIL FULL DEPRECATION: this.idStoreMigrator = new IdStoreMigrator({ @@ -344,13 +344,14 @@ module.exports = class KeyringController extends EventEmitter { var time = (new Date()).getTime() var txId = createId() txParams.metamaskId = txId - txParams.metamaskNetworkId = this.network + txParams.metamaskNetworkId = this.getNetwork() var txData = { id: txId, txParams: txParams, time: time, status: 'unconfirmed', gasMultiplier: configManager.getGasMultiplier() || 1, + metamaskNetworkId: this.getNetwork(), } -- cgit v1.2.3 From 23263bec7d5100accd61f7648fd9355fc95e2bb7 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 11 Nov 2016 10:26:12 -0800 Subject: Linting to the max. --- app/scripts/keyring-controller.js | 74 +++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 37 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 5d9dd51a4..b74d6cbfc 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -46,7 +46,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - getState() { + getState () { const configManager = this.configManager const address = configManager.getSelectedAccount() const wallet = configManager.getWallet() // old style vault @@ -72,18 +72,18 @@ module.exports = class KeyringController extends EventEmitter { } } - setStore(ethStore) { + setStore (ethStore) { this.ethStore = ethStore } - createNewVaultAndKeychain(password, entropy, cb) { + createNewVaultAndKeychain (password, entropy, cb) { this.createNewVault(password, entropy, (err) => { if (err) return cb(err) this.createFirstKeyTree(password, cb) }) } - createNewVaultAndRestore(password, seed, cb) { + createNewVaultAndRestore (password, seed, cb) { if (typeof password !== 'string') { return cb('Password must be text.') } @@ -114,7 +114,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - migrateAndGetKey(password) { + migrateAndGetKey (password) { let key const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() @@ -134,7 +134,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - createNewVault(password, entropy, cb) { + createNewVault (password, entropy, cb) { const configManager = this.configManager const salt = this.encryptor.generateSalt() configManager.setSalt(salt) @@ -151,7 +151,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - createFirstKeyTree(password, cb) { + createFirstKeyTree (password, cb) { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {n: 1}, (err) => { const firstKeyring = this.keyrings[0] @@ -179,7 +179,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSeedWords(seedWords) } - submitPassword(password, cb) { + submitPassword (password, cb) { this.migrateAndGetKey(password) .then((key) => { return this.unlockKeyrings(key) @@ -196,7 +196,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - loadKey(password) { + loadKey (password) { const salt = this.configManager.getSalt() || this.encryptor.generateSalt() return this.encryptor.keyFromPassword(password + salt) .then((key) => { @@ -206,7 +206,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - addNewKeyring(type, opts, cb) { + addNewKeyring (type, opts, cb) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) const accounts = keyring.getAccounts() @@ -222,7 +222,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - addNewAccount(keyRingNum = 0, cb) { + addNewAccount (keyRingNum = 0, cb) { const ring = this.keyrings[keyRingNum] const accounts = ring.addAccounts(1) this.setupAccounts(accounts) @@ -235,7 +235,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - setupAccounts(accounts) { + setupAccounts (accounts) { var arr = accounts || this.getAccounts() arr.forEach((account) => { this.loadBalanceAndNickname(account) @@ -244,13 +244,13 @@ module.exports = class KeyringController extends EventEmitter { // Takes an account address and an iterator representing // the current number of named accounts. - loadBalanceAndNickname(account) { + loadBalanceAndNickname (account) { const address = normalize(account) this.ethStore.addAccount(address) this.createNickname(address) } - createNickname(address) { + createNickname (address) { const hexAddress = normalize(address) var i = Object.keys(this.identities).length const oldNickname = this.configManager.nicknameForWallet(address) @@ -274,7 +274,7 @@ module.exports = class KeyringController extends EventEmitter { } } - persistAllKeyrings() { + persistAllKeyrings () { const serialized = this.keyrings.map((k) => { return { type: k.type, @@ -289,7 +289,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - unlockKeyrings(key) { + unlockKeyrings (key) { const encryptedVault = this.configManager.getVault() return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { @@ -298,7 +298,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - restoreKeyring(serialized) { + restoreKeyring (serialized) { const { type, data } = serialized const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() @@ -311,7 +311,7 @@ module.exports = class KeyringController extends EventEmitter { return keyring } - getKeyringClassForType(type) { + getKeyringClassForType (type) { const Keyring = this.keyringTypes.reduce((res, kr) => { if (kr.type() === type) { return kr @@ -322,7 +322,7 @@ module.exports = class KeyringController extends EventEmitter { return Keyring } - getAccounts() { + getAccounts () { const keyrings = this.keyrings || [] return keyrings.map(kr => kr.getAccounts()) .reduce((res, arr) => { @@ -330,13 +330,13 @@ module.exports = class KeyringController extends EventEmitter { }, []) } - setSelectedAddress(address, cb) { + setSelectedAddress (address, cb) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) cb(null, addr) } - addUnconfirmedTransaction(txParams, onTxDoneCb, cb) { + addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { var self = this const configManager = this.configManager @@ -369,7 +369,7 @@ module.exports = class KeyringController extends EventEmitter { ], didComplete) // perform static analyis on the target contract code - function analyzeForDelegateCall(cb){ + function analyzeForDelegateCall (cb) { if (txParams.to) { query.getCode(txParams.to, function (err, result) { if (err) return cb(err) @@ -388,8 +388,8 @@ module.exports = class KeyringController extends EventEmitter { } } - function estimateGas(cb){ - query.estimateGas(txParams, function(err, result){ + function estimateGas (cb) { + query.estimateGas(txParams, function (err, result) { if (err) return cb(err) txData.estimatedGas = self.addGasBuffer(result) cb() @@ -406,7 +406,7 @@ module.exports = class KeyringController extends EventEmitter { } } - addUnconfirmedMessage(msgParams, cb) { + addUnconfirmedMessage (msgParams, cb) { // create txData obj with parameters and meta data var time = (new Date()).getTime() var msgId = createId() @@ -428,7 +428,7 @@ module.exports = class KeyringController extends EventEmitter { return msgId } - approveTransaction(txId, cb) { + approveTransaction (txId, cb) { const configManager = this.configManager var approvalCb = this._unconfTxCbs[txId] || noop @@ -441,7 +441,7 @@ module.exports = class KeyringController extends EventEmitter { this.emit('update') } - cancelTransaction(txId, cb) { + cancelTransaction (txId, cb) { const configManager = this.configManager var approvalCb = this._unconfTxCbs[txId] || noop @@ -456,7 +456,7 @@ module.exports = class KeyringController extends EventEmitter { } } - signTransaction(txParams, cb) { + signTransaction (txParams, cb) { try { const address = normalize(txParams.from) const keyring = this.getKeyringForAccount(address) @@ -492,7 +492,7 @@ module.exports = class KeyringController extends EventEmitter { } } - signMessage(msgParams, cb) { + signMessage (msgParams, cb) { try { const keyring = this.getKeyringForAccount(msgParams.from) const address = normalize(msgParams.from) @@ -503,7 +503,7 @@ module.exports = class KeyringController extends EventEmitter { } } - getKeyringForAccount(address) { + getKeyringForAccount (address) { const hexed = normalize(address) return this.keyrings.find((ring) => { return ring.getAccounts() @@ -512,19 +512,19 @@ module.exports = class KeyringController extends EventEmitter { }) } - cancelMessage(msgId, cb) { + cancelMessage (msgId, cb) { if (cb && typeof cb === 'function') { cb() } } - setLocked(cb) { + setLocked (cb) { this.key = null this.keyrings = [] cb() } - exportAccount(address, cb) { + exportAccount (address, cb) { try { const keyring = this.getKeyringForAccount(address) const privateKey = keyring.exportAccount(normalize(address)) @@ -534,19 +534,19 @@ module.exports = class KeyringController extends EventEmitter { } } - addGasBuffer(gas) { + addGasBuffer (gas) { const gasBuffer = new BN('100000', 10) const bnGas = new BN(ethUtil.stripHexPrefix(gas), 16) const correct = bnGas.add(gasBuffer) return ethUtil.addHexPrefix(correct.toString(16)) } - clearSeedWordCache(cb) { + clearSeedWordCache (cb) { this.configManager.setSeedWords(null) cb(null, this.configManager.getSelectedAccount()) } - clearKeyrings() { + clearKeyrings () { let accounts try { accounts = Object.keys(this.ethStore._currentState.accounts) @@ -564,7 +564,7 @@ module.exports = class KeyringController extends EventEmitter { } -function normalize(address) { +function normalize (address) { if (!address) return return ethUtil.addHexPrefix(address.toLowerCase()) } -- cgit v1.2.3 From 20cea5b2f5429cc2574f755fcba0ce5bb12f1a13 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 11 Nov 2016 15:41:04 -0800 Subject: Various keyring changes - Rearrange the require statements. - Remove unused web3. - Simplify some callbacks and promises. - Clarify certain parameters. --- app/scripts/keyring-controller.js | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b74d6cbfc..bb1727d7a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,18 +1,18 @@ const async = require('async') -const EventEmitter = require('events').EventEmitter -const encryptor = require('./lib/encryptor') -const messageManager = require('./lib/message-manager') const ethUtil = require('ethereumjs-util') const ethBinToOps = require('eth-bin-to-ops') const EthQuery = require('eth-query') -const BN = ethUtil.BN +const bip39 = require('bip39') const Transaction = require('ethereumjs-tx') +const EventEmitter = require('events').EventEmitter + const createId = require('web3-provider-engine/util/random-id') +const normalize = require('./lib/sig-util').normalize +const encryptor = require('./lib/encryptor') +const messageManager = require('./lib/message-manager') const autoFaucet = require('./lib/auto-faucet') -const bip39 = require('bip39') - -// TEMPORARY UNTIL FULL DEPRECATION: const IdStoreMigrator = require('./lib/idStore-migrator') +const BN = ethUtil.BN // Keyrings: const SimpleKeyring = require('./keyrings/simple') @@ -26,7 +26,6 @@ module.exports = class KeyringController extends EventEmitter { constructor (opts) { super() - this.web3 = opts.web3 this.configManager = opts.configManager this.ethStore = opts.ethStore this.encryptor = encryptor @@ -98,7 +97,7 @@ module.exports = class KeyringController extends EventEmitter { if (err) return cb(err) this.addNewKeyring('HD Key Tree', { mnemonic: seed, - n: 1, + numberOfAccounts: 1, }, (err) => { if (err) return cb(err) const firstKeyring = this.keyrings[0] @@ -143,9 +142,7 @@ module.exports = class KeyringController extends EventEmitter { .then(() => { return this.persistAllKeyrings() }) - .then(() => { - cb(null) - }) + .then(cb) .catch((err) => { cb(err) }) @@ -153,7 +150,7 @@ module.exports = class KeyringController extends EventEmitter { createFirstKeyTree (password, cb) { this.clearKeyrings() - this.addNewKeyring('HD Key Tree', {n: 1}, (err) => { + this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { const firstKeyring = this.keyrings[0] const accounts = firstKeyring.getAccounts() const firstAccount = accounts[0] @@ -564,9 +561,4 @@ module.exports = class KeyringController extends EventEmitter { } -function normalize (address) { - if (!address) return - return ethUtil.addHexPrefix(address.toLowerCase()) -} - function noop () {} -- cgit v1.2.3 From 4826f7c0a095da8658bfae6a1d7e982cd81ffd3b Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 11 Nov 2016 17:06:07 -0800 Subject: Revert to previous anonymous function for promise. --- app/scripts/keyring-controller.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index bb1727d7a..c9f7e503e 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -142,7 +142,9 @@ module.exports = class KeyringController extends EventEmitter { .then(() => { return this.persistAllKeyrings() }) - .then(cb) + .then(() => { + cb() + }) .catch((err) => { cb(err) }) -- cgit v1.2.3 From 7de6b12aad4a674bdbb0749d2e61d9fd5f69c536 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 14 Nov 2016 16:49:16 -0800 Subject: Re-enable disclaimer screen. Rename variables to reflect role more clearly. --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c9f7e503e..c7e3c32a4 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -55,7 +55,7 @@ module.exports = class KeyringController extends EventEmitter { seedWords: this.configManager.getSeedWords(), isInitialized: (!!wallet || !!vault), isUnlocked: !!this.key, - isConfirmed: true, // AUDIT this.configManager.getConfirmed(), + isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), unconfTxs: this.configManager.unconfirmedTxs(), transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), -- cgit v1.2.3 From b1fee2a1d303c28ccedafc4e8c81e07ebf164b36 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 15 Nov 2016 11:07:15 -0800 Subject: Minimize repeated code. --- app/scripts/keyring-controller.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c7e3c32a4..4acaebba3 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -153,13 +153,12 @@ module.exports = class KeyringController extends EventEmitter { createFirstKeyTree (password, cb) { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { - const firstKeyring = this.keyrings[0] - const accounts = firstKeyring.getAccounts() + const accounts = this.keyrings[0].getAccounts() const firstAccount = accounts[0] const hexAccount = normalize(firstAccount) - const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSelectedAccount(firstAccount) - this.configManager.setSeedWords(seedWords) + + this.placeSeedWords() autoFaucet(hexAccount) this.setupAccounts(accounts) this.persistAllKeyrings() @@ -172,9 +171,11 @@ module.exports = class KeyringController extends EventEmitter { }) } - placeSeedWords (cb) { + placeSeedWords () { const firstKeyring = this.keyrings[0] + console.log(firstKeyring) const seedWords = firstKeyring.serialize().mnemonic + console.log(seedWords) this.configManager.setSeedWords(seedWords) } -- cgit v1.2.3 From a4666de0ce9eaa99242609fdbf518b6a37650ff2 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 15 Nov 2016 11:07:15 -0800 Subject: Minimize repeated code. --- app/scripts/keyring-controller.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c7e3c32a4..84327b15f 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -153,13 +153,12 @@ module.exports = class KeyringController extends EventEmitter { createFirstKeyTree (password, cb) { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { - const firstKeyring = this.keyrings[0] - const accounts = firstKeyring.getAccounts() + const accounts = this.keyrings[0].getAccounts() const firstAccount = accounts[0] const hexAccount = normalize(firstAccount) - const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSelectedAccount(firstAccount) - this.configManager.setSeedWords(seedWords) + + this.placeSeedWords() autoFaucet(hexAccount) this.setupAccounts(accounts) this.persistAllKeyrings() @@ -172,7 +171,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - placeSeedWords (cb) { + placeSeedWords () { const firstKeyring = this.keyrings[0] const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSeedWords(seedWords) @@ -237,13 +236,13 @@ module.exports = class KeyringController extends EventEmitter { setupAccounts (accounts) { var arr = accounts || this.getAccounts() arr.forEach((account) => { - this.loadBalanceAndNickname(account) + this.getBalanceAndNickname(account) }) } // Takes an account address and an iterator representing // the current number of named accounts. - loadBalanceAndNickname (account) { + getBalanceAndNickname (account) { const address = normalize(account) this.ethStore.addAccount(address) this.createNickname(address) -- cgit v1.2.3 From 5bfb700fa833a415a541a959736d6184d3c07753 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 15 Nov 2016 17:12:13 -0800 Subject: Minimize dispatches by using emitters and relying on state updates. --- app/scripts/keyring-controller.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index e635ad285..280b332a0 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -108,7 +108,7 @@ module.exports = class KeyringController extends EventEmitter { this.setupAccounts(accounts) this.emit('update') - cb(null, this.getState()) + cb() }) }) } @@ -163,7 +163,7 @@ module.exports = class KeyringController extends EventEmitter { this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { - cb(err, this.getState()) + cb(err) }) .catch((reason) => { cb(reason) @@ -173,9 +173,7 @@ module.exports = class KeyringController extends EventEmitter { placeSeedWords () { const firstKeyring = this.keyrings[0] - console.log(firstKeyring) const seedWords = firstKeyring.serialize().mnemonic - console.log(seedWords) this.configManager.setSeedWords(seedWords) } @@ -188,7 +186,7 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings = keyrings this.setupAccounts() this.emit('update') - cb(null, this.getState()) + cb() }) .catch((err) => { console.error(err) @@ -215,7 +213,7 @@ module.exports = class KeyringController extends EventEmitter { this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { - cb(null, this.getState()) + cb() }) .catch((reason) => { cb(reason) @@ -228,7 +226,7 @@ module.exports = class KeyringController extends EventEmitter { this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { - cb(null, this.getState()) + cb() }) .catch((reason) => { cb(reason) @@ -521,6 +519,7 @@ module.exports = class KeyringController extends EventEmitter { setLocked (cb) { this.key = null this.keyrings = [] + this.emit('update') cb() } -- cgit v1.2.3 From 592b64a19fd7001d965aa1a1c329b24f55d2ea90 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Tue, 15 Nov 2016 17:13:33 -0800 Subject: Revert one cb to previous state. --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 280b332a0..8ceb2b1ce 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -186,7 +186,7 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings = keyrings this.setupAccounts() this.emit('update') - cb() + cb(null, this.getState()) }) .catch((err) => { console.error(err) -- cgit v1.2.3 From f229d32442f34859be169e38a42ffecdfb8fc48a Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 17 Nov 2016 13:49:46 -0800 Subject: Replace old random-id code with incrementing id generator --- app/scripts/keyring-controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 3ebf02c44..5b06de690 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -7,7 +7,6 @@ const ethBinToOps = require('eth-bin-to-ops') const EthQuery = require('eth-query') const BN = ethUtil.BN const Transaction = require('ethereumjs-tx') -const createId = require('web3-provider-engine/util/random-id') const autoFaucet = require('./lib/auto-faucet') const bip39 = require('bip39') @@ -22,6 +21,8 @@ const keyringTypes = [ HdKeyring, ] +const createId = require('./lib/random-id') + module.exports = class KeyringController extends EventEmitter { constructor (opts) { -- cgit v1.2.3 From cd2442e3e77e50c935b5c84e6ccc8f3c7da45de0 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 18 Nov 2016 10:48:00 -0800 Subject: Persist keyrings from migration to storage. --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 10d686e23..9046108c0 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -117,7 +117,6 @@ module.exports = class KeyringController extends EventEmitter { migrateAndGetKey (password) { let key const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - return this.loadKey(password) .then((derivedKey) => { key = derivedKey @@ -128,6 +127,7 @@ module.exports = class KeyringController extends EventEmitter { if (serialized && shouldMigrate) { const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) + this.persistAllKeyrings() this.configManager.setSelectedAccount(keyring.getAccounts()[0]) } return key -- cgit v1.2.3 From bc6312e9e3d3a48b886f53279f13f176c71e4019 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Fri, 18 Nov 2016 15:58:49 -0800 Subject: Promisify persistence of keyrings before returning key Change single letter variables (shame) --- app/scripts/keyring-controller.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 9046108c0..cf761c88c 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -127,8 +127,9 @@ module.exports = class KeyringController extends EventEmitter { if (serialized && shouldMigrate) { const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) - this.persistAllKeyrings() this.configManager.setSelectedAccount(keyring.getAccounts()[0]) + return this.persistAllKeyrings() + .then(() => { return key }) } return key }) @@ -274,13 +275,12 @@ module.exports = class KeyringController extends EventEmitter { } persistAllKeyrings () { - const serialized = this.keyrings.map((k) => { + const serialized = this.keyrings.map((keyring) => { return { - type: k.type, - data: k.serialize(), + type: keyring.type, + data: keyring.serialize(), } }) - return this.encryptor.encryptWithKey(this.key, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) -- cgit v1.2.3 From 9123e70434fcd35dcb79a587e6d5c00734cb99e4 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 21 Nov 2016 15:49:03 -0800 Subject: Remove entropy from encryption and project. --- app/scripts/keyring-controller.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index cf761c88c..0d906eba1 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -76,8 +76,8 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = ethStore } - createNewVaultAndKeychain (password, entropy, cb) { - this.createNewVault(password, entropy, (err) => { + createNewVaultAndKeychain (password, cb) { + this.createNewVault(password, (err) => { if (err) return cb(err) this.createFirstKeyTree(password, cb) }) @@ -94,7 +94,7 @@ module.exports = class KeyringController extends EventEmitter { this.clearKeyrings() - this.createNewVault(password, '', (err) => { + this.createNewVault(password, (err) => { if (err) return cb(err) this.addNewKeyring('HD Key Tree', { mnemonic: seed, @@ -135,7 +135,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - createNewVault (password, entropy, cb) { + createNewVault (password, cb) { const configManager = this.configManager const salt = this.encryptor.generateSalt() configManager.setSalt(salt) -- cgit v1.2.3 From f5b0795ac5582dd53de728479cf47c43eabfe67c Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 21 Nov 2016 16:21:16 -0800 Subject: change all instances of selectedAddress to selectedAccount. --- app/scripts/keyring-controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 0d906eba1..b29150267 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -61,7 +61,6 @@ module.exports = class KeyringController extends EventEmitter { transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), - selectedAddress: address, selectedAccount: address, shapeShiftTxList: this.configManager.getShapeShiftTxList(), currentFiat: this.configManager.getCurrentFiat(), @@ -329,7 +328,7 @@ module.exports = class KeyringController extends EventEmitter { }, []) } - setSelectedAddress (address, cb) { + setSelectedAccount (address, cb) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) cb(null, addr) -- cgit v1.2.3 From 1cbab788ec21ba096d4375015c6cd3cd481de5b2 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 21 Nov 2016 16:46:26 -0800 Subject: Change fauceting to become a response of an emit. --- app/scripts/keyring-controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b29150267..31d144ca9 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,7 +9,6 @@ const EventEmitter = require('events').EventEmitter const normalize = require('./lib/sig-util').normalize const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') -const autoFaucet = require('./lib/auto-faucet') const IdStoreMigrator = require('./lib/idStore-migrator') const BN = ethUtil.BN @@ -160,7 +159,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSelectedAccount(firstAccount) this.placeSeedWords() - autoFaucet(hexAccount) + this.emit('newAccount', hexAccount) this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { -- cgit v1.2.3 From ced36eb20186b0f1bf0c744ac31a5b7804120065 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 21 Nov 2016 19:40:30 -0800 Subject: Improve Keyring organization Separated public & private methods. (Fixes #845) Made class method `type()` into a simple property. (Fixes #846) --- app/scripts/keyring-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index cf761c88c..fdef9d7b3 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -67,7 +67,7 @@ module.exports = class KeyringController extends EventEmitter { currentFiat: this.configManager.getCurrentFiat(), conversionRate: this.configManager.getConversionRate(), conversionDate: this.configManager.getConversionDate(), - keyringTypes: this.keyringTypes.map((krt) => krt.type()), + keyringTypes: this.keyringTypes.map(krt => krt.type), identities: this.identities, } } @@ -312,7 +312,7 @@ module.exports = class KeyringController extends EventEmitter { getKeyringClassForType (type) { const Keyring = this.keyringTypes.reduce((res, kr) => { - if (kr.type() === type) { + if (kr.type === type) { return kr } else { return res -- cgit v1.2.3 From 9fb96128e62294c88c6d3d2e177eb032543ffc50 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 21 Nov 2016 19:52:56 -0800 Subject: Rename idStoreMigrator method for clarity Fixes #841 --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index cf761c88c..27cc791f0 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -121,7 +121,7 @@ module.exports = class KeyringController extends EventEmitter { .then((derivedKey) => { key = derivedKey this.key = key - return this.idStoreMigrator.oldSeedForPassword(password) + return this.idStoreMigrator.migratedVaultForPassword(password) }) .then((serialized) => { if (serialized && shouldMigrate) { -- cgit v1.2.3 From ea56426b2355c1076c18256fb0b4e74f47ff4b39 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 21 Nov 2016 20:08:36 -0800 Subject: Use callback in placeSeedWord method. When displaying seed words, we were not using a callback, which had some race condition potential. This is simply a little cleaner and more correct. Fixes #842 --- app/scripts/keyring-controller.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index cf761c88c..49a41df66 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -173,10 +173,15 @@ module.exports = class KeyringController extends EventEmitter { }) } - placeSeedWords () { + placeSeedWords (cb) { const firstKeyring = this.keyrings[0] const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSeedWords(seedWords) + + if (cb && typeof cb === 'function') { + cb() + this.emit('update') + } } submitPassword (password, cb) { -- cgit v1.2.3 From 136296aad6058c4bea8c3083e8ae553b2afcab98 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 09:52:43 -0800 Subject: Began moving salt into encryptor --- app/scripts/keyring-controller.js | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index cf761c88c..e3705c113 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -55,7 +55,7 @@ module.exports = class KeyringController extends EventEmitter { return { seedWords: this.configManager.getSeedWords(), isInitialized: (!!wallet || !!vault), - isUnlocked: !!this.key, + isUnlocked: this.keyrings.length > 0, isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), unconfTxs: this.configManager.unconfirmedTxs(), transactions: this.configManager.getTxList(), @@ -137,7 +137,7 @@ module.exports = class KeyringController extends EventEmitter { createNewVault (password, entropy, cb) { const configManager = this.configManager - const salt = this.encryptor.generateSalt() + const salt = this.getSalt() configManager.setSalt(salt) return this.migrateAndGetKey(password) @@ -182,7 +182,7 @@ module.exports = class KeyringController extends EventEmitter { submitPassword (password, cb) { this.migrateAndGetKey(password) .then((key) => { - return this.unlockKeyrings(key) + return this.unlockKeyrings(password) }) .then((keyrings) => { this.keyrings = keyrings @@ -197,7 +197,7 @@ module.exports = class KeyringController extends EventEmitter { } loadKey (password) { - const salt = this.configManager.getSalt() || this.encryptor.generateSalt() + const salt = this.getSalt() return this.encryptor.keyFromPassword(password + salt) .then((key) => { this.key = key @@ -206,6 +206,11 @@ module.exports = class KeyringController extends EventEmitter { }) } + getSalt () { + const vault = this.configManager.getVault() + const salt = vault.salt || this.encryptor.generateSalt() + } + addNewKeyring (type, opts, cb) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) @@ -288,7 +293,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - unlockKeyrings (key) { + unlockKeyrings (password) { const encryptedVault = this.configManager.getVault() return this.encryptor.decryptWithKey(key, encryptedVault) .then((vault) => { -- cgit v1.2.3 From 606c0b761827df86ded4763a67f38a98738014e8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 12:57:15 -0800 Subject: Remove callback type check --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 51369eac8..224d6ba7a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -178,7 +178,7 @@ module.exports = class KeyringController extends EventEmitter { const seedWords = firstKeyring.serialize().mnemonic this.configManager.setSeedWords(seedWords) - if (cb && typeof cb === 'function') { + if (cb) { cb() this.emit('update') } -- cgit v1.2.3 From c4056a861a4a383b3bea18225e71435bdf75f6d0 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 13:13:10 -0800 Subject: Move state update outside of conditional callback block --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 224d6ba7a..cb92af388 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -180,8 +180,8 @@ module.exports = class KeyringController extends EventEmitter { if (cb) { cb() - this.emit('update') } + this.emit('update') } submitPassword (password, cb) { -- cgit v1.2.3 From bc39cd7b894ddf0f3724d4af3cfc30c2638e0939 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 22 Nov 2016 14:28:31 -0800 Subject: KeyringController - estimateGas->analyzeGasUsage fix gasLimit + detect OOG --- app/scripts/keyring-controller.js | 66 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 61 insertions(+), 5 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index bf6280016..5432322ac 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,4 +1,5 @@ const async = require('async') +const bind = require('ap').partial const ethUtil = require('ethereumjs-util') const ethBinToOps = require('eth-bin-to-ops') const EthQuery = require('eth-query') @@ -362,7 +363,7 @@ module.exports = class KeyringController extends EventEmitter { // calculate metadata for tx async.parallel([ analyzeForDelegateCall, - estimateGas, + analyzeGasUsage, ], didComplete) // perform static analyis on the target contract code @@ -385,14 +386,69 @@ module.exports = class KeyringController extends EventEmitter { } } - function estimateGas (cb) { - query.estimateGas(txParams, function (err, result) { + function analyzeGasUsage (cb) { + query.getBlockByNumber('latest', true, function (err, block) { if (err) return cb(err) - txData.estimatedGas = self.addGasBuffer(result) - cb() + async.waterfall([ + bind(estimateGas, txData, block.gasLimit), + bind(checkForGasError, txData), + bind(setTxGas, txData, block.gasLimit), + ], cb) }) } + function estimateGas(txData, blockGasLimitHex, cb) { + const txParams = txData.txParams + // check if gasLimit is already specified + txData.gasLimitSpecified = Boolean(txParams.gas) + // if not, fallback to block gasLimit + if (!txData.gasLimitSpecified) { + txParams.gas = blockGasLimitHex + } + // run tx, see if it will OOG + query.estimateGas(txParams, cb) + } + + function checkForGasError(txData, estimatedGasHex) { + txData.estimatedGas = estimatedGasHex + // all gas used - must be an error + if (estimatedGasHex === txData.txParams.gas) { + txData.simulationFails = true + } + cb() + } + + function setTxGas(txData, blockGasLimitHex) { + const txParams = txData.txParams + // if OOG, nothing more to do + if (txData.simulationFails) { + cb() + return + } + // if gasLimit was specified and doesnt OOG, + // use original specified amount + if (txData.gasLimitSpecified) { + txData.estimatedGas = txParams.gas + cb() + return + } + // if gasLimit not originally specified, + // try adding an additional gas buffer to our estimation for safety + const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) + const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) + const estimationWithBuffer = self.addGasBuffer(estimatedGasBn) + // added gas buffer is too high + if (estimationWithBuffer.gt(blockGasLimitBn)) { + txParams.gas = txData.estimatedGas + // added gas buffer is safe + } else { + const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer) + txParams.gas = gasWithBufferHex + } + cb() + return + } + function didComplete (err) { if (err) return cb(err) configManager.addTx(txData) -- cgit v1.2.3 From de8da9ddf67f36977e43d2168c4847fd9923c875 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 15:54:51 -0800 Subject: Simplify Encryptor API Surface At least, the portion of it that we use. Moved salting within the encryptor, so it does not need to be managed externally. KeyringController now caches the password instead of a passwordDerivedKey, since it is ignorant of the salt. Encryptor payload is now in a JSON format, so its portions are both base64 encoded *and* labeled appropriately. The format is `{ "data": "0x0", "iv": "0x0", "salt": "string" }`. Fixes #843 Fixes #859 --- app/scripts/keyring-controller.js | 50 ++++++++++----------------------------- 1 file changed, 13 insertions(+), 37 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 00c04ea9b..b24c4bac5 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -113,34 +113,25 @@ module.exports = class KeyringController extends EventEmitter { }) } - migrateAndGetKey (password) { - let key + migrateOldVaultIfAny (password) { const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - return this.loadKey(password) - .then((derivedKey) => { - key = derivedKey - this.key = key - return this.idStoreMigrator.migratedVaultForPassword(password) - }) + return this.idStoreMigrator.migratedVaultForPassword(password) .then((serialized) => { if (serialized && shouldMigrate) { const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) return this.persistAllKeyrings() - .then(() => { return key }) + .then(() => { return }) } - return key + return }) } createNewVault (password, cb) { - const configManager = this.configManager - const salt = this.getSalt() - configManager.setSalt(salt) - - return this.migrateAndGetKey(password) + return this.migrateOldVaultIfAny(password) .then(() => { + this.password = password return this.persistAllKeyrings() }) .then(() => { @@ -184,8 +175,8 @@ module.exports = class KeyringController extends EventEmitter { } submitPassword (password, cb) { - this.migrateAndGetKey(password) - .then((key) => { + this.migrateOldVaultIfAny(password) + .then(() => { return this.unlockKeyrings(password) }) .then((keyrings) => { @@ -200,21 +191,6 @@ module.exports = class KeyringController extends EventEmitter { }) } - loadKey (password) { - const salt = this.getSalt() - return this.encryptor.keyFromPassword(password + salt) - .then((key) => { - this.key = key - this.configManager.setSalt(salt) - return key - }) - } - - getSalt () { - const vault = this.configManager.getVault() - const salt = vault.salt || this.encryptor.generateSalt() - } - addNewKeyring (type, opts, cb) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) @@ -290,7 +266,7 @@ module.exports = class KeyringController extends EventEmitter { data: keyring.serialize(), } }) - return this.encryptor.encryptWithKey(this.key, serialized) + return this.encryptor.encrypt(this.password, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) return true @@ -299,7 +275,7 @@ module.exports = class KeyringController extends EventEmitter { unlockKeyrings (password) { const encryptedVault = this.configManager.getVault() - return this.encryptor.decryptWithKey(key, encryptedVault) + return this.encryptor.decrypt(this.password, encryptedVault) .then((vault) => { vault.forEach(this.restoreKeyring.bind(this)) return this.keyrings @@ -407,7 +383,7 @@ module.exports = class KeyringController extends EventEmitter { }) } - function estimateGas(txData, blockGasLimitHex, cb) { + function estimateGas (txData, blockGasLimitHex, cb) { const txParams = txData.txParams // check if gasLimit is already specified txData.gasLimitSpecified = Boolean(txParams.gas) @@ -419,7 +395,7 @@ module.exports = class KeyringController extends EventEmitter { query.estimateGas(txParams, cb) } - function checkForGasError(txData, estimatedGasHex) { + function checkForGasError (txData, estimatedGasHex) { txData.estimatedGas = estimatedGasHex // all gas used - must be an error if (estimatedGasHex === txData.txParams.gas) { @@ -428,7 +404,7 @@ module.exports = class KeyringController extends EventEmitter { cb() } - function setTxGas(txData, blockGasLimitHex) { + function setTxGas (txData, blockGasLimitHex) { const txParams = txData.txParams // if OOG, nothing more to do if (txData.simulationFails) { -- cgit v1.2.3 From 4b7b0a86d8e9688bd8a512342b99c76dc1810486 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 15:57:48 -0800 Subject: Refine isInitialized derivation method --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index b24c4bac5..c736fa1f6 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -55,7 +55,7 @@ module.exports = class KeyringController extends EventEmitter { return { seedWords: this.configManager.getSeedWords(), isInitialized: (!!wallet || !!vault), - isUnlocked: this.keyrings.length > 0, + isUnlocked: Boolean(this.password), isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), unconfTxs: this.configManager.unconfirmedTxs(), transactions: this.configManager.getTxList(), -- cgit v1.2.3 From 6ebdebc0a5287bce18947fff3e7812bcac43ce36 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 16:18:18 -0800 Subject: Remove line of cruft --- app/scripts/keyring-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c736fa1f6..4fa2b4ee8 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -122,7 +122,6 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) return this.persistAllKeyrings() - .then(() => { return }) } return }) -- cgit v1.2.3 From 822face7a3513a709277a197e27fd550b7b21954 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 16:29:46 -0800 Subject: Fix password reference --- app/scripts/keyring-controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 4fa2b4ee8..141a1281a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -274,8 +274,9 @@ module.exports = class KeyringController extends EventEmitter { unlockKeyrings (password) { const encryptedVault = this.configManager.getVault() - return this.encryptor.decrypt(this.password, encryptedVault) + return this.encryptor.decrypt(password, encryptedVault) .then((vault) => { + this.password = password vault.forEach(this.restoreKeyring.bind(this)) return this.keyrings }) -- cgit v1.2.3 From 05c8658ff343af61b1a40a5624ecba77adb2ef00 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 17:40:29 -0800 Subject: Fix new encryptor migration logic --- app/scripts/keyring-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 141a1281a..68cf62f7a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -118,6 +118,7 @@ module.exports = class KeyringController extends EventEmitter { return this.idStoreMigrator.migratedVaultForPassword(password) .then((serialized) => { if (serialized && shouldMigrate) { + this.password = password const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) this.configManager.setSelectedAccount(keyring.getAccounts()[0]) @@ -185,7 +186,6 @@ module.exports = class KeyringController extends EventEmitter { cb(null, this.getState()) }) .catch((err) => { - console.error(err) cb(err) }) } @@ -558,7 +558,7 @@ module.exports = class KeyringController extends EventEmitter { } setLocked (cb) { - this.key = null + this.password = null this.keyrings = [] this.emit('update') cb() -- cgit v1.2.3 From 2efab79f5bea899764c08dfb317ce70b5bebbb55 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 23:16:36 -0800 Subject: Asynced keyrings and started on controller --- app/scripts/keyring-controller.js | 44 ++++++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 15 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 68cf62f7a..1f58f3780 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -121,10 +121,13 @@ module.exports = class KeyringController extends EventEmitter { this.password = password const keyring = this.restoreKeyring(serialized) this.keyrings.push(keyring) - this.configManager.setSelectedAccount(keyring.getAccounts()[0]) - return this.persistAllKeyrings() + keyring.getAccounts() + .then((accounts) => { + this.configManager.setSelectedAccount(accounts[0]) + return this.persistAllKeyrings() + }) } - return + return Promise.resolve() }) } @@ -165,13 +168,18 @@ module.exports = class KeyringController extends EventEmitter { placeSeedWords (cb) { const firstKeyring = this.keyrings[0] - const seedWords = firstKeyring.serialize().mnemonic - this.configManager.setSeedWords(seedWords) + firstKeyring.serialize() + .then((serialized) => { - if (cb) { - cb() - } - this.emit('update') + const seedWords = serialized.mnemonic + this.configManager.setSeedWords(seedWords) + + if (cb) { + cb() + } + + this.emit('update') + }) } submitPassword (password, cb) { @@ -259,13 +267,19 @@ module.exports = class KeyringController extends EventEmitter { } persistAllKeyrings () { - const serialized = this.keyrings.map((keyring) => { - return { - type: keyring.type, - data: keyring.serialize(), - } + Promise.all(this.keyrings.map((keyring) => { + return Promise.all([keyring.type, keyring.serialize()]) + .then((serializedKeyringArray) => { + // Label the output values on each serialized Keyring: + return { + type: serializedKeyringArray[0], + data: serializedKeyringArray[1], + } + }) + })) + .then((serializedKeyrings) => { + return this.encryptor.encrypt(this.password, serializedKeyrings) }) - return this.encryptor.encrypt(this.password, serialized) .then((encryptedString) => { this.configManager.setVault(encryptedString) return true -- cgit v1.2.3 From c77d355e98d3c61699a3a85dfc2ed1f320a9eb03 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 22 Nov 2016 23:36:11 -0800 Subject: Complete first pass at asyncrhonizing keyring controller --- app/scripts/keyring-controller.js | 84 ++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 31 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1f58f3780..4cfe84b6b 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -117,17 +117,21 @@ module.exports = class KeyringController extends EventEmitter { const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() return this.idStoreMigrator.migratedVaultForPassword(password) .then((serialized) => { + this.password = password + if (serialized && shouldMigrate) { - this.password = password - const keyring = this.restoreKeyring(serialized) - this.keyrings.push(keyring) - keyring.getAccounts() + return this.restoreKeyring(serialized) + .then((keyring) => { + return keyring.getAccounts() + }) .then((accounts) => { this.configManager.setSelectedAccount(accounts[0]) return this.persistAllKeyrings() }) + + } else { + return Promise.resolve() } - return Promise.resolve() }) } @@ -216,9 +220,13 @@ module.exports = class KeyringController extends EventEmitter { addNewAccount (keyRingNum = 0, cb) { const ring = this.keyrings[keyRingNum] - const accounts = ring.addAccounts(1) - this.setupAccounts(accounts) - this.persistAllKeyrings() + return ring.addAccounts(1) + .then((accounts) => { + return this.setupAccounts(accounts) + }) + .then(() => { + return this.persistAllKeyrings() + }) .then(() => { cb() }) @@ -228,9 +236,13 @@ module.exports = class KeyringController extends EventEmitter { } setupAccounts (accounts) { - var arr = accounts || this.getAccounts() - arr.forEach((account) => { - this.getBalanceAndNickname(account) + return this.getAccounts() + .then((loadedAccounts) => { + var arr = accounts || loadedAccounts + + arr.forEach((account) => { + this.getBalanceAndNickname(account) + }) }) } @@ -301,12 +313,13 @@ module.exports = class KeyringController extends EventEmitter { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() keyring.deserialize(data) - - const accounts = keyring.getAccounts() - this.setupAccounts(accounts) - - this.keyrings.push(keyring) - return keyring + .then(() => { + return keyring.getAccounts() + }) + .then((accounts) => { + this.setupAccounts(accounts) + this.keyrings.push(keyring) + }) } getKeyringClassForType (type) { @@ -529,17 +542,19 @@ module.exports = class KeyringController extends EventEmitter { txParams.nonce = normalize(txParams.nonce) let tx = new Transaction(txParams) - tx = keyring.signTransaction(address, tx) - - // Add the tx hash to the persisted meta-tx object - var txHash = ethUtil.bufferToHex(tx.hash()) - var metaTx = this.configManager.getTx(txParams.metamaskId) - metaTx.hash = txHash - this.configManager.updateTx(metaTx) + keyring.signTransaction(address, tx) + .then((tx) => { + // Add the tx hash to the persisted meta-tx object + var txHash = ethUtil.bufferToHex(tx.hash()) + var metaTx = this.configManager.getTx(txParams.metamaskId) + metaTx.hash = txHash + this.configManager.updateTx(metaTx) + + // return raw serialized tx + var rawTx = ethUtil.bufferToHex(tx.serialize()) + cb(null, rawTx) + }) - // return raw serialized tx - var rawTx = ethUtil.bufferToHex(tx.serialize()) - cb(null, rawTx) } catch (e) { cb(e) } @@ -549,8 +564,11 @@ module.exports = class KeyringController extends EventEmitter { try { const keyring = this.getKeyringForAccount(msgParams.from) const address = normalize(msgParams.from) - const rawSig = keyring.signMessage(address, msgParams.data) - cb(null, rawSig) + return keyring.signMessage(address, msgParams.data) + .then((rawSig) => { + cb(null, rawSig) + return rawSig + }) } catch (e) { cb(e) } @@ -581,10 +599,14 @@ module.exports = class KeyringController extends EventEmitter { exportAccount (address, cb) { try { const keyring = this.getKeyringForAccount(address) - const privateKey = keyring.exportAccount(normalize(address)) - cb(null, privateKey) + return keyring.exportAccount(normalize(address)) + .then((privateKey) => { + cb(null, privateKey) + return privateKey + }) } catch (e) { cb(e) + return Promise.reject(e) } } -- cgit v1.2.3 From 600f5c31db47a06c0c9bb9a97c01476d77b0a0df Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 23 Nov 2016 00:23:41 -0800 Subject: Mostly got async keyringController tests passing --- app/scripts/keyring-controller.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 4cfe84b6b..a36f5b752 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -99,16 +99,17 @@ module.exports = class KeyringController extends EventEmitter { mnemonic: seed, numberOfAccounts: 1, }, (err) => { - if (err) return cb(err) const firstKeyring = this.keyrings[0] const accounts = firstKeyring.getAccounts() const firstAccount = accounts[0] const hexAccount = normalize(firstAccount) this.configManager.setSelectedAccount(hexAccount) this.setupAccounts(accounts) - - this.emit('update') - cb() + this.persistAllKeyrings() + .then(() => { + this.emit('update') + cb(err) + }) }) }) } @@ -152,6 +153,7 @@ module.exports = class KeyringController extends EventEmitter { createFirstKeyTree (password, cb) { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { + if (err) return cb(err) const accounts = this.keyrings[0].getAccounts() const firstAccount = accounts[0] const hexAccount = normalize(firstAccount) @@ -162,7 +164,7 @@ module.exports = class KeyringController extends EventEmitter { this.setupAccounts(accounts) this.persistAllKeyrings() .then(() => { - cb(err) + cb() }) .catch((reason) => { cb(reason) @@ -335,10 +337,10 @@ module.exports = class KeyringController extends EventEmitter { getAccounts () { const keyrings = this.keyrings || [] - return keyrings.map(kr => kr.getAccounts()) + return Promise.all(keyrings.map(kr => kr.getAccounts()) .reduce((res, arr) => { return res.concat(arr) - }, []) + }, [])) } setSelectedAccount (address, cb) { -- cgit v1.2.3 From 230a0ab876df82edc8147fd3c0ba18f10ffc4e3c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 23 Nov 2016 11:58:34 -0800 Subject: Fix more keyring asyncifying tests --- app/scripts/keyring-controller.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index a36f5b752..f93202523 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -281,7 +281,7 @@ module.exports = class KeyringController extends EventEmitter { } persistAllKeyrings () { - Promise.all(this.keyrings.map((keyring) => { + return Promise.all(this.keyrings.map((keyring) => { return Promise.all([keyring.type, keyring.serialize()]) .then((serializedKeyringArray) => { // Label the output values on each serialized Keyring: @@ -314,13 +314,14 @@ module.exports = class KeyringController extends EventEmitter { const { type, data } = serialized const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() - keyring.deserialize(data) + return keyring.deserialize(data) .then(() => { return keyring.getAccounts() }) .then((accounts) => { this.setupAccounts(accounts) this.keyrings.push(keyring) + return keyring }) } -- cgit v1.2.3 From d9dc2eac6305abda8da1113f16868bd362283582 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 23 Nov 2016 14:35:29 -0800 Subject: Fix more async usage of KeyringController --- app/scripts/keyring-controller.js | 57 ++++++++++++++++++++++----------------- 1 file changed, 32 insertions(+), 25 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index f93202523..4981c49df 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -98,9 +98,11 @@ module.exports = class KeyringController extends EventEmitter { this.addNewKeyring('HD Key Tree', { mnemonic: seed, numberOfAccounts: 1, - }, (err) => { + }).then(() => { const firstKeyring = this.keyrings[0] - const accounts = firstKeyring.getAccounts() + return firstKeyring.getAccounts() + }) + .then((accounts) => { const firstAccount = accounts[0] const hexAccount = normalize(firstAccount) this.configManager.setSelectedAccount(hexAccount) @@ -108,7 +110,7 @@ module.exports = class KeyringController extends EventEmitter { this.persistAllKeyrings() .then(() => { this.emit('update') - cb(err) + cb(err, this.getState()) }) }) }) @@ -129,7 +131,6 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSelectedAccount(accounts[0]) return this.persistAllKeyrings() }) - } else { return Promise.resolve() } @@ -154,15 +155,17 @@ module.exports = class KeyringController extends EventEmitter { this.clearKeyrings() this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { if (err) return cb(err) - const accounts = this.keyrings[0].getAccounts() - const firstAccount = accounts[0] - const hexAccount = normalize(firstAccount) - this.configManager.setSelectedAccount(firstAccount) + this.keyrings[0].getAccounts() + .then((accounts) => { + const firstAccount = accounts[0] + const hexAccount = normalize(firstAccount) + this.configManager.setSelectedAccount(firstAccount) - this.placeSeedWords() - this.emit('newAccount', hexAccount) - this.setupAccounts(accounts) - this.persistAllKeyrings() + this.placeSeedWords() + this.emit('newAccount', hexAccount) + this.setupAccounts(accounts) + return this.persistAllKeyrings() + }) .then(() => { cb() }) @@ -176,7 +179,6 @@ module.exports = class KeyringController extends EventEmitter { const firstKeyring = this.keyrings[0] firstKeyring.serialize() .then((serialized) => { - const seedWords = serialized.mnemonic this.configManager.setSeedWords(seedWords) @@ -207,16 +209,23 @@ module.exports = class KeyringController extends EventEmitter { addNewKeyring (type, opts, cb) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) - const accounts = keyring.getAccounts() - - this.keyrings.push(keyring) - this.setupAccounts(accounts) - this.persistAllKeyrings() - .then(() => { - cb() + return keyring.getAccounts() + .then((accounts) => { + this.keyrings.push(keyring) + return this.setupAccounts(accounts) + }).then(() => { + return this.persistAllKeyrings() + }).then(() => { + if (cb) { + cb(null, keyring) + } + return keyring }) .catch((reason) => { - cb(reason) + if (cb) { + cb(reason) + } + return reason }) } @@ -240,8 +249,7 @@ module.exports = class KeyringController extends EventEmitter { setupAccounts (accounts) { return this.getAccounts() .then((loadedAccounts) => { - var arr = accounts || loadedAccounts - + const arr = accounts || loadedAccounts arr.forEach((account) => { this.getBalanceAndNickname(account) }) @@ -544,7 +552,7 @@ module.exports = class KeyringController extends EventEmitter { txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) txParams.nonce = normalize(txParams.nonce) - let tx = new Transaction(txParams) + const tx = new Transaction(txParams) keyring.signTransaction(address, tx) .then((tx) => { // Add the tx hash to the persisted meta-tx object @@ -557,7 +565,6 @@ module.exports = class KeyringController extends EventEmitter { var rawTx = ethUtil.bufferToHex(tx.serialize()) cb(null, rawTx) }) - } catch (e) { cb(e) } -- cgit v1.2.3 From 80e76b45ee67900b5a60da1ddcd8b310f1e92413 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 28 Nov 2016 12:43:44 -0800 Subject: Denodeify most of KeyringController Mostly Fixes #893 A couple methods cache callbacks, and will require a larger refactor to fully denodeify. Specifically, our methods involving web3 requests to sign a tx, sign a message, and approve or cancel either of those. I think we should postpone those until the TxManager refactor, since it will likely handle this response caching itself. --- app/scripts/keyring-controller.js | 275 ++++++++++++++++++-------------------- 1 file changed, 127 insertions(+), 148 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 4981c49df..5e6b0acbb 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -75,45 +75,41 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = ethStore } - createNewVaultAndKeychain (password, cb) { - this.createNewVault(password, (err) => { - if (err) return cb(err) - this.createFirstKeyTree(password, cb) - }) + createNewVaultAndKeychain (password) { + return this.createNewVault(password) + .then(this.createFirstKeyTree.bind(this)) + .then(this.fullUpdate.bind(this)) } - createNewVaultAndRestore (password, seed, cb) { + createNewVaultAndRestore (password, seed) { if (typeof password !== 'string') { - return cb('Password must be text.') + return Promise.reject('Password must be text.') } if (!bip39.validateMnemonic(seed)) { - return cb('Seed phrase is invalid.') + return Promise.reject('Seed phrase is invalid.') } this.clearKeyrings() - this.createNewVault(password, (err) => { - if (err) return cb(err) - this.addNewKeyring('HD Key Tree', { + return this.createNewVault(password) + .then(() => { + return this.addNewKeyring('HD Key Tree', { mnemonic: seed, numberOfAccounts: 1, - }).then(() => { - const firstKeyring = this.keyrings[0] - return firstKeyring.getAccounts() - }) - .then((accounts) => { - const firstAccount = accounts[0] - const hexAccount = normalize(firstAccount) - this.configManager.setSelectedAccount(hexAccount) - this.setupAccounts(accounts) - this.persistAllKeyrings() - .then(() => { - this.emit('update') - cb(err, this.getState()) - }) }) + }).then(() => { + const firstKeyring = this.keyrings[0] + return firstKeyring.getAccounts() }) + .then((accounts) => { + const firstAccount = accounts[0] + const hexAccount = normalize(firstAccount) + this.configManager.setSelectedAccount(hexAccount) + return this.setupAccounts(accounts) + }) + .then(this.persistAllKeyrings.bind(this)) + .then(this.fullUpdate.bind(this)) } migrateOldVaultIfAny (password) { @@ -124,9 +120,7 @@ module.exports = class KeyringController extends EventEmitter { if (serialized && shouldMigrate) { return this.restoreKeyring(serialized) - .then((keyring) => { - return keyring.getAccounts() - }) + .then(keyring => keyring.getAccounts()) .then((accounts) => { this.configManager.setSelectedAccount(accounts[0]) return this.persistAllKeyrings() @@ -137,122 +131,91 @@ module.exports = class KeyringController extends EventEmitter { }) } - createNewVault (password, cb) { + createNewVault (password) { return this.migrateOldVaultIfAny(password) .then(() => { this.password = password return this.persistAllKeyrings() }) .then(() => { - cb() - }) - .catch((err) => { - cb(err) + return password }) } - createFirstKeyTree (password, cb) { + createFirstKeyTree (password) { this.clearKeyrings() - this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}, (err) => { - if (err) return cb(err) - this.keyrings[0].getAccounts() - .then((accounts) => { - const firstAccount = accounts[0] - const hexAccount = normalize(firstAccount) - this.configManager.setSelectedAccount(firstAccount) - - this.placeSeedWords() - this.emit('newAccount', hexAccount) - this.setupAccounts(accounts) - return this.persistAllKeyrings() - }) - .then(() => { - cb() - }) - .catch((reason) => { - cb(reason) - }) + return this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}) + .then(() => { + return this.keyrings[0].getAccounts() }) + .then((accounts) => { + const firstAccount = accounts[0] + const hexAccount = normalize(firstAccount) + this.configManager.setSelectedAccount(hexAccount) + this.emit('newAccount', hexAccount) + return this.setupAccounts(accounts) + }).then(() => { + return this.placeSeedWords() + }) + .then(this.persistAllKeyrings.bind(this)) } - placeSeedWords (cb) { + placeSeedWords () { const firstKeyring = this.keyrings[0] - firstKeyring.serialize() + return firstKeyring.serialize() .then((serialized) => { const seedWords = serialized.mnemonic this.configManager.setSeedWords(seedWords) - - if (cb) { - cb() - } - this.emit('update') + return }) } - submitPassword (password, cb) { - this.migrateOldVaultIfAny(password) + submitPassword (password) { + return this.migrateOldVaultIfAny(password) .then(() => { return this.unlockKeyrings(password) }) .then((keyrings) => { this.keyrings = keyrings - this.setupAccounts() - this.emit('update') - cb(null, this.getState()) - }) - .catch((err) => { - cb(err) + return this.setupAccounts() }) + .then(this.fullUpdate.bind(this)) + } + + fullUpdate() { + this.emit('update') + return Promise.resolve(this.getState()) } - addNewKeyring (type, opts, cb) { + addNewKeyring (type, opts) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) return keyring.getAccounts() .then((accounts) => { this.keyrings.push(keyring) return this.setupAccounts(accounts) - }).then(() => { - return this.persistAllKeyrings() - }).then(() => { - if (cb) { - cb(null, keyring) - } - return keyring }) - .catch((reason) => { - if (cb) { - cb(reason) - } - return reason + .then(this.persistAllKeyrings.bind(this)) + .then(() => { + return keyring }) } - addNewAccount (keyRingNum = 0, cb) { + addNewAccount (keyRingNum = 0) { const ring = this.keyrings[keyRingNum] return ring.addAccounts(1) - .then((accounts) => { - return this.setupAccounts(accounts) - }) - .then(() => { - return this.persistAllKeyrings() - }) - .then(() => { - cb() - }) - .catch((reason) => { - cb(reason) - }) + .then(this.setupAccounts.bind(this)) + .then(this.persistAllKeyrings.bind(this)) } setupAccounts (accounts) { return this.getAccounts() .then((loadedAccounts) => { const arr = accounts || loadedAccounts - arr.forEach((account) => { - this.getBalanceAndNickname(account) - }) + return Promise.all(arr.map((account) => { + return this.getBalanceAndNickname(account) + })) }) } @@ -261,7 +224,7 @@ module.exports = class KeyringController extends EventEmitter { getBalanceAndNickname (account) { const address = normalize(account) this.ethStore.addAccount(address) - this.createNickname(address) + return this.createNickname(address) } createNickname (address) { @@ -276,16 +239,12 @@ module.exports = class KeyringController extends EventEmitter { return this.saveAccountLabel(hexAddress, name) } - saveAccountLabel (account, label, cb) { + saveAccountLabel (account, label) { const address = normalize(account) const configManager = this.configManager configManager.setNicknameForWallet(address, label) this.identities[address].name = label - if (cb) { - cb(null, label) - } else { - return label - } + return Promise.resolve(label) } persistAllKeyrings () { @@ -327,7 +286,9 @@ module.exports = class KeyringController extends EventEmitter { return keyring.getAccounts() }) .then((accounts) => { - this.setupAccounts(accounts) + return this.setupAccounts(accounts) + }) + .then(() => { this.keyrings.push(keyring) return keyring }) @@ -346,16 +307,18 @@ module.exports = class KeyringController extends EventEmitter { getAccounts () { const keyrings = this.keyrings || [] - return Promise.all(keyrings.map(kr => kr.getAccounts()) - .reduce((res, arr) => { - return res.concat(arr) - }, [])) + return Promise.all(keyrings.map(kr => kr.getAccounts())) + .then((keyringArrays) => { + return keyringArrays.reduce((res, arr) => { + return res.concat(arr) + }, []) + }) } - setSelectedAccount (address, cb) { + setSelectedAccount (address) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) - cb(null, addr) + Promise.resolve(addr) } addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { @@ -536,24 +499,25 @@ module.exports = class KeyringController extends EventEmitter { signTransaction (txParams, cb) { try { const address = normalize(txParams.from) - const keyring = this.getKeyringForAccount(address) - - // Handle gas pricing - var gasMultiplier = this.configManager.getGasMultiplier() || 1 - var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice), 16) - gasPrice = gasPrice.mul(new BN(gasMultiplier * 100, 10)).div(new BN(100, 10)) - txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber()) - - // normalize values - txParams.to = normalize(txParams.to) - txParams.from = normalize(txParams.from) - txParams.value = normalize(txParams.value) - txParams.data = normalize(txParams.data) - txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) - txParams.nonce = normalize(txParams.nonce) - - const tx = new Transaction(txParams) - keyring.signTransaction(address, tx) + return this.getKeyringForAccount(address) + .then((keyring) => { + // Handle gas pricing + var gasMultiplier = this.configManager.getGasMultiplier() || 1 + var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice), 16) + gasPrice = gasPrice.mul(new BN(gasMultiplier * 100, 10)).div(new BN(100, 10)) + txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber()) + + // normalize values + txParams.to = normalize(txParams.to) + txParams.from = normalize(txParams.from) + txParams.value = normalize(txParams.value) + txParams.data = normalize(txParams.data) + txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) + txParams.nonce = normalize(txParams.nonce) + + const tx = new Transaction(txParams) + return keyring.signTransaction(address, tx) + }) .then((tx) => { // Add the tx hash to the persisted meta-tx object var txHash = ethUtil.bufferToHex(tx.hash()) @@ -572,10 +536,11 @@ module.exports = class KeyringController extends EventEmitter { signMessage (msgParams, cb) { try { - const keyring = this.getKeyringForAccount(msgParams.from) const address = normalize(msgParams.from) - return keyring.signMessage(address, msgParams.data) - .then((rawSig) => { + return this.getKeyringForAccount(address) + .then((keyring) => { + return keyring.signMessage(address, msgParams.data) + }).then((rawSig) => { cb(null, rawSig) return rawSig }) @@ -586,10 +551,28 @@ module.exports = class KeyringController extends EventEmitter { getKeyringForAccount (address) { const hexed = normalize(address) - return this.keyrings.find((ring) => { - return ring.getAccounts() - .map(normalize) - .includes(hexed) + return new Promise((resolve, reject) => { + + // Get all the keyrings, and associate them with their account list: + Promise.all(this.keyrings.map((keyring) => { + const accounts = keyring.getAccounts() + return Promise.all({ + keyring, + accounts, + }) + })) + + // Find the keyring with the matching account and return it: + .then((result) => { + const match = result.find((candidate) => { + return candidate.accounts.map(normalize).includes(hexed) + }) + if (match) { + resolve(match.keyring) + } else { + reject('No keyring found for the requested account.') + } + }) }) } @@ -599,23 +582,19 @@ module.exports = class KeyringController extends EventEmitter { } } - setLocked (cb) { + setLocked () { this.password = null this.keyrings = [] - this.emit('update') - cb() + return this.fullUpdate() } - exportAccount (address, cb) { + exportAccount (address) { try { - const keyring = this.getKeyringForAccount(address) - return keyring.exportAccount(normalize(address)) - .then((privateKey) => { - cb(null, privateKey) - return privateKey + return this.getKeyringForAccount(address) + .then((keyring) => { + return keyring.exportAccount(normalize(address)) }) } catch (e) { - cb(e) return Promise.reject(e) } } @@ -627,9 +606,9 @@ module.exports = class KeyringController extends EventEmitter { return ethUtil.addHexPrefix(correct.toString(16)) } - clearSeedWordCache (cb) { + clearSeedWordCache () { this.configManager.setSeedWords(null) - cb(null, this.configManager.getSelectedAccount()) + return Promise.resolve(this.configManager.getSelectedAccount()) } clearKeyrings () { -- cgit v1.2.3 From b81f00849d53ee780bf26d4d6f79aef4ebdba34c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 11:40:49 -0800 Subject: Annotated KeyringController --- app/scripts/keyring-controller.js | 715 ++++++++++++++++++++++++++------------ 1 file changed, 496 insertions(+), 219 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 5e6b0acbb..7d29fb5d8 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -25,6 +25,13 @@ const createId = require('./lib/random-id') module.exports = class KeyringController extends EventEmitter { + // PUBLIC METHODS + // + // THE FIRST SECTION OF METHODS ARE PUBLIC-FACING, + // MEANING THEY ARE USED BY CONSUMERS OF THIS CLASS. + // + // THEIR SURFACE AREA SHOULD BE CHANGED WITH GREAT CARE. + constructor (opts) { super() this.configManager = opts.configManager @@ -46,6 +53,46 @@ module.exports = class KeyringController extends EventEmitter { }) } + // Set Store + // + // Allows setting the ethStore after the constructor. + // This is currently required because of the initialization order + // of the ethStore and this class. + // + // Eventually would be nice to be able to add this in the constructor. + setStore (ethStore) { + this.ethStore = ethStore + } + + // Full Update + // returns Promise( @object state ) + // + // Emits the `update` event and + // returns a Promise that resolves to the current state. + // + // Frequently used to end asynchronous chains in this class, + // indicating consumers can often either listen for updates, + // or accept a state-resolving promise to consume their results. + // + // Not all methods end with this, that might be a nice refactor. + fullUpdate() { + this.emit('update') + return Promise.resolve(this.getState()) + } + + // Get State + // returns @object state + // + // This method returns a hash representing the current state + // that the keyringController manages. + // + // It is extended in the MetamaskController along with the EthStore + // state, and its own state, to create the metamask state branch + // that is passed to the UI. + // + // This is currently a rare example of a synchronously resolving method + // in this class, but will need to be Promisified when we move our + // persistence to an async model. getState () { const configManager = this.configManager const address = configManager.getSelectedAccount() @@ -71,16 +118,30 @@ module.exports = class KeyringController extends EventEmitter { } } - setStore (ethStore) { - this.ethStore = ethStore - } - + // Create New Vault And Keychain + // @string password - The password to encrypt the vault with + // + // returns Promise( @object state ) + // + // Destroys any old encrypted storage, + // creates a new encrypted store with the given password, + // randomly creates a new HD wallet with 1 account, + // faucets that account on the testnet. createNewVaultAndKeychain (password) { - return this.createNewVault(password) + return this.persistAllKeyrings(password) .then(this.createFirstKeyTree.bind(this)) .then(this.fullUpdate.bind(this)) } + // CreateNewVaultAndRestore + // @string password - The password to encrypt the vault with + // @string seed - The BIP44-compliant seed phrase. + // + // returns Promise( @object state ) + // + // Destroys any old encrypted storage, + // creates a new encrypted store with the given password, + // creates a new HD wallet from the given seed with 1 account. createNewVaultAndRestore (password, seed) { if (typeof password !== 'string') { return Promise.reject('Password must be text.') @@ -92,7 +153,7 @@ module.exports = class KeyringController extends EventEmitter { this.clearKeyrings() - return this.createNewVault(password) + return this.persistAllKeyrings(password) .then(() => { return this.addNewKeyring('HD Key Tree', { mnemonic: seed, @@ -112,65 +173,54 @@ module.exports = class KeyringController extends EventEmitter { .then(this.fullUpdate.bind(this)) } - migrateOldVaultIfAny (password) { - const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - return this.idStoreMigrator.migratedVaultForPassword(password) - .then((serialized) => { - this.password = password - - if (serialized && shouldMigrate) { - return this.restoreKeyring(serialized) - .then(keyring => keyring.getAccounts()) - .then((accounts) => { - this.configManager.setSelectedAccount(accounts[0]) - return this.persistAllKeyrings() - }) - } else { - return Promise.resolve() - } - }) - } - - createNewVault (password) { - return this.migrateOldVaultIfAny(password) - .then(() => { - this.password = password - return this.persistAllKeyrings() - }) - .then(() => { - return password - }) - } - - createFirstKeyTree (password) { - this.clearKeyrings() - return this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}) - .then(() => { - return this.keyrings[0].getAccounts() - }) - .then((accounts) => { - const firstAccount = accounts[0] - const hexAccount = normalize(firstAccount) - this.configManager.setSelectedAccount(hexAccount) - this.emit('newAccount', hexAccount) - return this.setupAccounts(accounts) - }).then(() => { - return this.placeSeedWords() - }) - .then(this.persistAllKeyrings.bind(this)) - } - + // PlaceSeedWords + // returns Promise( @object state ) + // + // Adds the current vault's seed words to the UI's state tree. + // + // Used when creating a first vault, to allow confirmation. + // Also used when revealing the seed words in the confirmation view. placeSeedWords () { const firstKeyring = this.keyrings[0] return firstKeyring.serialize() .then((serialized) => { const seedWords = serialized.mnemonic this.configManager.setSeedWords(seedWords) - this.emit('update') - return + return this.fullUpdate() }) } + // ClearSeedWordCache + // + // returns Promise( @string currentSelectedAccount ) + // + // Removes the current vault's seed words from the UI's state tree, + // ensuring they are only ever available in the background process. + clearSeedWordCache () { + this.configManager.setSeedWords(null) + return Promise.resolve(this.configManager.getSelectedAccount()) + } + + // Set Locked + // returns Promise( @object state ) + // + // This method deallocates all secrets, and effectively locks metamask. + setLocked () { + this.password = null + this.keyrings = [] + return this.fullUpdate() + } + + // Submit Password + // @string password + // + // returns Promise( @object state ) + // + // Attempts to decrypt the current vault and load its keyrings + // into memory. + // + // Temporarily also migrates any old-style vaults first, as well. + // (Pre MetaMask 3.0.0) submitPassword (password) { return this.migrateOldVaultIfAny(password) .then(() => { @@ -183,11 +233,17 @@ module.exports = class KeyringController extends EventEmitter { .then(this.fullUpdate.bind(this)) } - fullUpdate() { - this.emit('update') - return Promise.resolve(this.getState()) - } - + // Add New Keyring + // @string type + // @object opts + // + // returns Promise( @Keyring keyring ) + // + // Adds a new Keyring of the given `type` to the vault + // and the current decrypted Keyrings array. + // + // All Keyring classes implement a unique `type` string, + // and this is used to retrieve them from the keyringTypes array. addNewKeyring (type, opts) { const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring(opts) @@ -202,43 +258,42 @@ module.exports = class KeyringController extends EventEmitter { }) } + // Add New Account + // @number keyRingNum + // + // returns Promise( @object state ) + // + // Calls the `addAccounts` method on the Keyring + // in the kryings array at index `keyringNum`, + // and then saves those changes. addNewAccount (keyRingNum = 0) { const ring = this.keyrings[keyRingNum] return ring.addAccounts(1) .then(this.setupAccounts.bind(this)) .then(this.persistAllKeyrings.bind(this)) + .then(this.fullUpdate.bind(this)) } - setupAccounts (accounts) { - return this.getAccounts() - .then((loadedAccounts) => { - const arr = accounts || loadedAccounts - return Promise.all(arr.map((account) => { - return this.getBalanceAndNickname(account) - })) - }) - } - - // Takes an account address and an iterator representing - // the current number of named accounts. - getBalanceAndNickname (account) { - const address = normalize(account) - this.ethStore.addAccount(address) - return this.createNickname(address) - } - - createNickname (address) { - const hexAddress = normalize(address) - var i = Object.keys(this.identities).length - const oldNickname = this.configManager.nicknameForWallet(address) - const name = oldNickname || `Account ${++i}` - this.identities[hexAddress] = { - address: hexAddress, - name, - } - return this.saveAccountLabel(hexAddress, name) + // Set Selected Account + // @string address + // + // returns Promise( @string address ) + // + // Sets the state's `selectedAccount` value + // to the specified address. + setSelectedAccount (address) { + var addr = normalize(address) + this.configManager.setSelectedAccount(addr) + Promise.resolve(addr) } + // Save Account Label + // @string account + // @string label + // + // returns Promise( @string label ) + // + // Persists a nickname equal to `label` for the specified account. saveAccountLabel (account, label) { const address = normalize(account) const configManager = this.configManager @@ -247,80 +302,45 @@ module.exports = class KeyringController extends EventEmitter { return Promise.resolve(label) } - persistAllKeyrings () { - return Promise.all(this.keyrings.map((keyring) => { - return Promise.all([keyring.type, keyring.serialize()]) - .then((serializedKeyringArray) => { - // Label the output values on each serialized Keyring: - return { - type: serializedKeyringArray[0], - data: serializedKeyringArray[1], - } + // Export Account + // @string address + // + // returns Promise( @string privateKey ) + // + // Requests the private key from the keyring controlling + // the specified address. + // + // Returns a Promise that may resolve with the private key string. + exportAccount (address) { + try { + return this.getKeyringForAccount(address) + .then((keyring) => { + return keyring.exportAccount(normalize(address)) }) - })) - .then((serializedKeyrings) => { - return this.encryptor.encrypt(this.password, serializedKeyrings) - }) - .then((encryptedString) => { - this.configManager.setVault(encryptedString) - return true - }) - } - - unlockKeyrings (password) { - const encryptedVault = this.configManager.getVault() - return this.encryptor.decrypt(password, encryptedVault) - .then((vault) => { - this.password = password - vault.forEach(this.restoreKeyring.bind(this)) - return this.keyrings - }) - } - - restoreKeyring (serialized) { - const { type, data } = serialized - const Keyring = this.getKeyringClassForType(type) - const keyring = new Keyring() - return keyring.deserialize(data) - .then(() => { - return keyring.getAccounts() - }) - .then((accounts) => { - return this.setupAccounts(accounts) - }) - .then(() => { - this.keyrings.push(keyring) - return keyring - }) + } catch (e) { + return Promise.reject(e) + } } - getKeyringClassForType (type) { - const Keyring = this.keyringTypes.reduce((res, kr) => { - if (kr.type === type) { - return kr - } else { - return res - } - }) - return Keyring - } - getAccounts () { - const keyrings = this.keyrings || [] - return Promise.all(keyrings.map(kr => kr.getAccounts())) - .then((keyringArrays) => { - return keyringArrays.reduce((res, arr) => { - return res.concat(arr) - }, []) - }) - } + // SIGNING RELATED METHODS + // + // SIGN, SUBMIT TX, CANCEL, AND APPROVE. + // THIS SECTION INVOLVES THE REQUEST, STORING, AND SIGNING OF DATA + // WITH THE KEYS STORED IN THIS CONTROLLER. - setSelectedAccount (address) { - var addr = normalize(address) - this.configManager.setSelectedAccount(addr) - Promise.resolve(addr) - } + // Add Unconfirmed Transaction + // @object txParams + // @function onTxDoneCb + // @function cb + // + // Calls back `cb` with @object txData = { txParams } + // Calls back `onTxDoneCb` with `true` or an `error` depending on result. + // + // Prepares the given `txParams` for final confirmation and approval. + // Estimates gas and other preparatory steps. + // Caches the requesting Dapp's callback, `onTxDoneCb`, for resolution later. addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { var self = this const configManager = this.configManager @@ -446,28 +466,38 @@ module.exports = class KeyringController extends EventEmitter { } } - addUnconfirmedMessage (msgParams, cb) { - // create txData obj with parameters and meta data - var time = (new Date()).getTime() - var msgId = createId() - var msgData = { - id: msgId, - msgParams: msgParams, - time: time, - status: 'unconfirmed', - } - messageManager.addMsg(msgData) - console.log('addUnconfirmedMessage:', msgData) + // Cancel Transaction + // @string txId + // @function cb + // + // Calls back `cb` with no error if provided. + // + // Forgets any tx matching `txId`. + cancelTransaction (txId, cb) { + const configManager = this.configManager + var approvalCb = this._unconfTxCbs[txId] || noop - // keep the cb around for after approval (requires user interaction) - // This cb fires completion to the Dapp's write operation. - this._unconfMsgCbs[msgId] = cb + // reject tx + approvalCb(null, false) + // clean up + configManager.rejectTx(txId) + delete this._unconfTxCbs[txId] - // signal update - this.emit('update') - return msgId + if (cb && typeof cb === 'function') { + cb() + } } + // Approve Transaction + // @string txId + // @function cb + // + // Calls back `cb` with no error always. + // + // Attempts to sign a Transaction with `txId` + // and submit it to the blockchain. + // + // Calls back the cached Dapp's confirmation callback, also. approveTransaction (txId, cb) { const configManager = this.configManager var approvalCb = this._unconfTxCbs[txId] || noop @@ -480,22 +510,6 @@ module.exports = class KeyringController extends EventEmitter { delete this._unconfTxCbs[txId] this.emit('update') } - - cancelTransaction (txId, cb) { - const configManager = this.configManager - var approvalCb = this._unconfTxCbs[txId] || noop - - // reject tx - approvalCb(null, false) - // clean up - configManager.rejectTx(txId) - delete this._unconfTxCbs[txId] - - if (cb && typeof cb === 'function') { - cb() - } - } - signTransaction (txParams, cb) { try { const address = normalize(txParams.from) @@ -534,14 +548,77 @@ module.exports = class KeyringController extends EventEmitter { } } + // Add Unconfirmed Message + // @object msgParams + // @function cb + // + // Does not call back, only emits an `update` event. + // + // Adds the given `msgParams` and `cb` to a local cache, + // for displaying to a user for approval before signing or canceling. + addUnconfirmedMessage (msgParams, cb) { + // create txData obj with parameters and meta data + var time = (new Date()).getTime() + var msgId = createId() + var msgData = { + id: msgId, + msgParams: msgParams, + time: time, + status: 'unconfirmed', + } + messageManager.addMsg(msgData) + console.log('addUnconfirmedMessage:', msgData) + + // keep the cb around for after approval (requires user interaction) + // This cb fires completion to the Dapp's write operation. + this._unconfMsgCbs[msgId] = cb + + // signal update + this.emit('update') + return msgId + } + + // Cancel Message + // @string msgId + // @function cb (optional) + // + // Calls back to cached `unconfMsgCb`. + // Calls back to `cb` if provided. + // + // Forgets any messages matching `msgId`. + cancelMessage (msgId, cb) { + var approvalCb = this._unconfMsgCbs[msgId] || noop + + // reject tx + approvalCb(null, false) + // clean up + messageManager.rejectMsg(msgId) + delete this._unconfTxCbs[msgId] + + if (cb && typeof cb === 'function') { + cb() + } + } + + // Sign Message + // @object msgParams + // @function cb + // + // returns Promise(@buffer rawSig) + // calls back @function cb with @buffer rawSig + // calls back cached Dapp's @function unconfMsgCb. + // + // Attempts to sign the provided @object msgParams. signMessage (msgParams, cb) { try { + var approvalCb = this._unconfMsgCbs[msgId] || noop const address = normalize(msgParams.from) return this.getKeyringForAccount(address) .then((keyring) => { return keyring.signMessage(address, msgParams.data) }).then((rawSig) => { cb(null, rawSig) + approvalCb(null, true) return rawSig }) } catch (e) { @@ -549,6 +626,224 @@ module.exports = class KeyringController extends EventEmitter { } } + // PRIVATE METHODS + // + // THESE METHODS ARE ONLY USED INTERNALLY TO THE KEYRING-CONTROLLER + // AND SO MAY BE CHANGED MORE LIBERALLY THAN THE ABOVE METHODS. + + // Migrate Old Vault If Any + // @string password + // + // returns Promise() + // + // Temporary step used when logging in. + // Checks if old style (pre-3.0.0) Metamask Vault exists. + // If so, persists that vault in the new vault format + // with the provided password, so the other unlock steps + // may be completed without interruption. + migrateOldVaultIfAny (password) { + const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() + return this.idStoreMigrator.migratedVaultForPassword(password) + .then((serialized) => { + this.password = password + + if (serialized && shouldMigrate) { + return this.restoreKeyring(serialized) + .then(keyring => keyring.getAccounts()) + .then((accounts) => { + this.configManager.setSelectedAccount(accounts[0]) + return this.persistAllKeyrings() + }) + } else { + return Promise.resolve() + } + }) + } + + // Create First Key Tree + // returns @Promise + // + // Clears the vault, + // creates a new one, + // creates a random new HD Keyring with 1 account, + // makes that account the selected account, + // faucets that account on testnet, + // puts the current seed words into the state tree. + createFirstKeyTree () { + this.clearKeyrings() + return this.addNewKeyring('HD Key Tree', {numberOfAccounts: 1}) + .then(() => { + return this.keyrings[0].getAccounts() + }) + .then((accounts) => { + const firstAccount = accounts[0] + const hexAccount = normalize(firstAccount) + this.configManager.setSelectedAccount(hexAccount) + this.emit('newAccount', hexAccount) + return this.setupAccounts(accounts) + }).then(() => { + return this.placeSeedWords() + }) + .then(this.persistAllKeyrings.bind(this)) + } + + // Setup Accounts + // @array accounts + // + // returns @Promise(@object account) + // + // Initializes the provided account array + // Gives them numerically incremented nicknames, + // and adds them to the ethStore for regular balance checking. + setupAccounts (accounts) { + return this.getAccounts() + .then((loadedAccounts) => { + const arr = accounts || loadedAccounts + return Promise.all(arr.map((account) => { + return this.getBalanceAndNickname(account) + })) + }) + } + + // Get Balance And Nickname + // @string account + // + // returns Promise( @string label ) + // + // Takes an account address and an iterator representing + // the current number of named accounts. + getBalanceAndNickname (account) { + const address = normalize(account) + this.ethStore.addAccount(address) + return this.createNickname(address) + } + + // Create Nickname + // @string address + // + // returns Promise( @string label ) + // + // Takes an address, and assigns it an incremented nickname, persisting it. + createNickname (address) { + const hexAddress = normalize(address) + var i = Object.keys(this.identities).length + const oldNickname = this.configManager.nicknameForWallet(address) + const name = oldNickname || `Account ${++i}` + this.identities[hexAddress] = { + address: hexAddress, + name, + } + return this.saveAccountLabel(hexAddress, name) + } + + // Persist All Keyrings + // @password string + // + // returns Promise + // + // Iterates the current `keyrings` array, + // serializes each one into a serialized array, + // encrypts that array with the provided `password`, + // and persists that encrypted string to storage. + persistAllKeyrings (password = this.password) { + this.password = password + return Promise.all(this.keyrings.map((keyring) => { + return Promise.all([keyring.type, keyring.serialize()]) + .then((serializedKeyringArray) => { + // Label the output values on each serialized Keyring: + return { + type: serializedKeyringArray[0], + data: serializedKeyringArray[1], + } + }) + })) + .then((serializedKeyrings) => { + return this.encryptor.encrypt(this.password, serializedKeyrings) + }) + .then((encryptedString) => { + this.configManager.setVault(encryptedString) + return true + }) + } + + // Unlock Keyrings + // @string password + // + // returns Promise( @array keyrings ) + // + // Attempts to unlock the persisted encrypted storage, + // initializing the persisted keyrings to RAM. + unlockKeyrings (password) { + const encryptedVault = this.configManager.getVault() + return this.encryptor.decrypt(password, encryptedVault) + .then((vault) => { + this.password = password + vault.forEach(this.restoreKeyring.bind(this)) + return this.keyrings + }) + } + + // Restore Keyring + // @object serialized + // + // returns Promise( @Keyring deserialized ) + // + // Attempts to initialize a new keyring from the provided + // serialized payload. + // + // On success, returns the resulting @Keyring instance. + restoreKeyring (serialized) { + const { type, data } = serialized + const Keyring = this.getKeyringClassForType(type) + const keyring = new Keyring() + return keyring.deserialize(data) + .then(() => { + return keyring.getAccounts() + }) + .then((accounts) => { + return this.setupAccounts(accounts) + }) + .then(() => { + this.keyrings.push(keyring) + return keyring + }) + } + + // Get Keyring Class For Type + // @string type + // + // Returns @class Keyring + // + // Searches the current `keyringTypes` array + // for a Keyring class whose unique `type` property + // matches the provided `type`, + // returning it if it exists. + getKeyringClassForType (type) { + return this.keyringTypes.find(kr => kr.type === type) + } + + // Get Accounts + // returns Promise( @Array[ @string accounts ] ) + // + // Returns the public addresses of all current accounts + // managed by all currently unlocked keyrings. + getAccounts () { + const keyrings = this.keyrings || [] + return Promise.all(keyrings.map(kr => kr.getAccounts())) + .then((keyringArrays) => { + return keyringArrays.reduce((res, arr) => { + return res.concat(arr) + }, []) + }) + } + + // Get Keyring For Account + // @string address + // + // returns Promise(@Keyring keyring) + // + // Returns the currently initialized keyring that manages + // the specified `address` if one exists. getKeyringForAccount (address) { const hexed = normalize(address) return new Promise((resolve, reject) => { @@ -576,29 +871,12 @@ module.exports = class KeyringController extends EventEmitter { }) } - cancelMessage (msgId, cb) { - if (cb && typeof cb === 'function') { - cb() - } - } - - setLocked () { - this.password = null - this.keyrings = [] - return this.fullUpdate() - } - - exportAccount (address) { - try { - return this.getKeyringForAccount(address) - .then((keyring) => { - return keyring.exportAccount(normalize(address)) - }) - } catch (e) { - return Promise.reject(e) - } - } - + // Add Gas Buffer + // @string gas (as hexadecimal value) + // + // returns @string bufferedGas (as hexadecimal value) + // + // Adds a healthy buffer of gas to an initial gas estimate. addGasBuffer (gas) { const gasBuffer = new BN('100000', 10) const bnGas = new BN(ethUtil.stripHexPrefix(gas), 16) @@ -606,11 +884,10 @@ module.exports = class KeyringController extends EventEmitter { return ethUtil.addHexPrefix(correct.toString(16)) } - clearSeedWordCache () { - this.configManager.setSeedWords(null) - return Promise.resolve(this.configManager.getSelectedAccount()) - } - + // Clear Keyrings + // + // Deallocates all currently managed keyrings and accounts. + // Used before initializing a new vault. clearKeyrings () { let accounts try { -- cgit v1.2.3 From 4b6b1db4f0fddfe3a640656311a58429ed48753c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 11:41:13 -0800 Subject: Ordered keyringController methods the same in metamask-controller --- app/scripts/keyring-controller.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 7d29fb5d8..e6a69d9ed 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -611,7 +611,11 @@ module.exports = class KeyringController extends EventEmitter { // Attempts to sign the provided @object msgParams. signMessage (msgParams, cb) { try { - var approvalCb = this._unconfMsgCbs[msgId] || noop + + const msgId = msgParams.metamaskId + delete msgParams.metamaskId + const approvalCb = this._unconfMsgCbs[msgId] || noop + const address = normalize(msgParams.from) return this.getKeyringForAccount(address) .then((keyring) => { -- cgit v1.2.3 From 85d5b12f8dd4029bf93a7fb0b5f65b306cbaaa3c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 12:44:42 -0800 Subject: Fix tx adding code Broken in this commit: https://github.com/MetaMask/metamask-plugin/commit/bc39cd7b894ddf0f3724d4af3cfc30c2638e0939 Synchronous methods were added to an `async.waterfall` array. This commit also removes the delegate call checking, since we concluded it was misinformed. --- app/scripts/keyring-controller.js | 28 +++------------------------- 1 file changed, 3 insertions(+), 25 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index e6a69d9ed..0045890be 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,7 +1,6 @@ const async = require('async') const bind = require('ap').partial const ethUtil = require('ethereumjs-util') -const ethBinToOps = require('eth-bin-to-ops') const EthQuery = require('eth-query') const bip39 = require('bip39') const Transaction = require('ethereumjs-tx') @@ -369,30 +368,9 @@ module.exports = class KeyringController extends EventEmitter { // calculate metadata for tx async.parallel([ - analyzeForDelegateCall, analyzeGasUsage, ], didComplete) - // perform static analyis on the target contract code - function analyzeForDelegateCall (cb) { - if (txParams.to) { - query.getCode(txParams.to, function (err, result) { - if (err) return cb(err) - var code = ethUtil.toBuffer(result) - if (code !== '0x') { - var ops = ethBinToOps(code) - var containsDelegateCall = ops.some((op) => op.name === 'DELEGATECALL') - txData.containsDelegateCall = containsDelegateCall - cb() - } else { - cb() - } - }) - } else { - cb() - } - } - function analyzeGasUsage (cb) { query.getBlockByNumber('latest', true, function (err, block) { if (err) return cb(err) @@ -416,7 +394,7 @@ module.exports = class KeyringController extends EventEmitter { query.estimateGas(txParams, cb) } - function checkForGasError (txData, estimatedGasHex) { + function checkForGasError (txData, estimatedGasHex, cb) { txData.estimatedGas = estimatedGasHex // all gas used - must be an error if (estimatedGasHex === txData.txParams.gas) { @@ -425,7 +403,7 @@ module.exports = class KeyringController extends EventEmitter { cb() } - function setTxGas (txData, blockGasLimitHex) { + function setTxGas (txData, blockGasLimitHex, cb) { const txParams = txData.txParams // if OOG, nothing more to do if (txData.simulationFails) { @@ -443,7 +421,7 @@ module.exports = class KeyringController extends EventEmitter { // try adding an additional gas buffer to our estimation for safety const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) - const estimationWithBuffer = self.addGasBuffer(estimatedGasBn) + const estimationWithBuffer = new BN(self.addGasBuffer(estimatedGasBn), 16) // added gas buffer is too high if (estimationWithBuffer.gt(blockGasLimitBn)) { txParams.gas = txData.estimatedGas -- cgit v1.2.3 From ff3f6cc36adcc9a3c780d6cc0f2a05c3c45c3162 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 14:13:12 -0800 Subject: Bind ethQuery to estimateGas to allow it to be moved around. --- app/scripts/keyring-controller.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 0045890be..7976a9e3a 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -375,14 +375,14 @@ module.exports = class KeyringController extends EventEmitter { query.getBlockByNumber('latest', true, function (err, block) { if (err) return cb(err) async.waterfall([ - bind(estimateGas, txData, block.gasLimit), + bind(estimateGas, query, txData, block.gasLimit), bind(checkForGasError, txData), bind(setTxGas, txData, block.gasLimit), ], cb) }) } - function estimateGas (txData, blockGasLimitHex, cb) { + function estimateGas (query, txData, blockGasLimitHex, cb) { const txParams = txData.txParams // check if gasLimit is already specified txData.gasLimitSpecified = Boolean(txParams.gas) -- cgit v1.2.3 From 5bf1018d7540e0d89aa866e8d7f709e577bb99e3 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 14:56:02 -0800 Subject: Flattened addTx async methods --- app/scripts/keyring-controller.js | 171 ++++++++++++++++++-------------------- 1 file changed, 82 insertions(+), 89 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 7976a9e3a..900b3ca25 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,11 +1,10 @@ const async = require('async') -const bind = require('ap').partial const ethUtil = require('ethereumjs-util') const EthQuery = require('eth-query') const bip39 = require('bip39') const Transaction = require('ethereumjs-tx') const EventEmitter = require('events').EventEmitter - +const filter = require('promise-filter') const normalize = require('./lib/sig-util').normalize const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') @@ -341,7 +340,6 @@ module.exports = class KeyringController extends EventEmitter { // Estimates gas and other preparatory steps. // Caches the requesting Dapp's callback, `onTxDoneCb`, for resolution later. addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { - var self = this const configManager = this.configManager // create txData obj with parameters and meta data @@ -358,7 +356,6 @@ module.exports = class KeyringController extends EventEmitter { metamaskNetworkId: this.getNetwork(), } - // keep the onTxDoneCb around for after approval/denial (requires user interaction) // This onTxDoneCb fires completion to the Dapp's write operation. this._unconfTxCbs[txId] = onTxDoneCb @@ -367,81 +364,80 @@ module.exports = class KeyringController extends EventEmitter { var query = new EthQuery(provider) // calculate metadata for tx - async.parallel([ - analyzeGasUsage, - ], didComplete) - - function analyzeGasUsage (cb) { - query.getBlockByNumber('latest', true, function (err, block) { - if (err) return cb(err) - async.waterfall([ - bind(estimateGas, query, txData, block.gasLimit), - bind(checkForGasError, txData), - bind(setTxGas, txData, block.gasLimit), - ], cb) - }) + this.analyzeTxGasUsage(query, txData, this.txDidComplete.bind(this, txData, cb)) + } + + estimateTxGas (query, txData, blockGasLimitHex, cb) { + const txParams = txData.txParams + // check if gasLimit is already specified + txData.gasLimitSpecified = Boolean(txParams.gas) + // if not, fallback to block gasLimit + if (!txData.gasLimitSpecified) { + txParams.gas = blockGasLimitHex } + // run tx, see if it will OOG + query.estimateGas(txParams, cb) + } - function estimateGas (query, txData, blockGasLimitHex, cb) { - const txParams = txData.txParams - // check if gasLimit is already specified - txData.gasLimitSpecified = Boolean(txParams.gas) - // if not, fallback to block gasLimit - if (!txData.gasLimitSpecified) { - txParams.gas = blockGasLimitHex - } - // run tx, see if it will OOG - query.estimateGas(txParams, cb) + checkForTxGasError (txData, estimatedGasHex, cb) { + txData.estimatedGas = estimatedGasHex + // all gas used - must be an error + if (estimatedGasHex === txData.txParams.gas) { + txData.simulationFails = true } + cb() + } - function checkForGasError (txData, estimatedGasHex, cb) { - txData.estimatedGas = estimatedGasHex - // all gas used - must be an error - if (estimatedGasHex === txData.txParams.gas) { - txData.simulationFails = true - } + setTxGas (txData, blockGasLimitHex, cb) { + const txParams = txData.txParams + // if OOG, nothing more to do + if (txData.simulationFails) { cb() + return } - - function setTxGas (txData, blockGasLimitHex, cb) { - const txParams = txData.txParams - // if OOG, nothing more to do - if (txData.simulationFails) { - cb() - return - } - // if gasLimit was specified and doesnt OOG, - // use original specified amount - if (txData.gasLimitSpecified) { - txData.estimatedGas = txParams.gas - cb() - return - } - // if gasLimit not originally specified, - // try adding an additional gas buffer to our estimation for safety - const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) - const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) - const estimationWithBuffer = new BN(self.addGasBuffer(estimatedGasBn), 16) - // added gas buffer is too high - if (estimationWithBuffer.gt(blockGasLimitBn)) { - txParams.gas = txData.estimatedGas - // added gas buffer is safe - } else { - const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer) - txParams.gas = gasWithBufferHex - } + // if gasLimit was specified and doesnt OOG, + // use original specified amount + if (txData.gasLimitSpecified) { + txData.estimatedGas = txParams.gas cb() return } + // if gasLimit not originally specified, + // try adding an additional gas buffer to our estimation for safety + const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) + const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) + const estimationWithBuffer = new BN(this.addGasBuffer(estimatedGasBn), 16) + // added gas buffer is too high + if (estimationWithBuffer.gt(blockGasLimitBn)) { + txParams.gas = txData.estimatedGas + // added gas buffer is safe + } else { + const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer) + txParams.gas = gasWithBufferHex + } + cb() + return + } - function didComplete (err) { + txDidComplete (txData, cb, err) { + if (err) return cb(err) + const configManager = this.configManager + configManager.addTx(txData) + // signal update + this.emit('update') + // signal completion of add tx + cb(null, txData) + } + + analyzeTxGasUsage (query, txData, cb) { + query.getBlockByNumber('latest', true, (err, block) => { if (err) return cb(err) - configManager.addTx(txData) - // signal update - self.emit('update') - // signal completion of add tx - cb(null, txData) - } + async.waterfall([ + this.estimateTxGas.bind(this, query, txData, block.gasLimit), + this.checkForTxGasError.bind(this, txData), + this.setTxGas.bind(this, txData, block.gasLimit), + ], cb) + }) } // Cancel Transaction @@ -488,6 +484,7 @@ module.exports = class KeyringController extends EventEmitter { delete this._unconfTxCbs[txId] this.emit('update') } + signTransaction (txParams, cb) { try { const address = normalize(txParams.from) @@ -828,28 +825,23 @@ module.exports = class KeyringController extends EventEmitter { // the specified `address` if one exists. getKeyringForAccount (address) { const hexed = normalize(address) - return new Promise((resolve, reject) => { - - // Get all the keyrings, and associate them with their account list: - Promise.all(this.keyrings.map((keyring) => { - const accounts = keyring.getAccounts() - return Promise.all({ - keyring, - accounts, - }) - })) - // Find the keyring with the matching account and return it: - .then((result) => { - const match = result.find((candidate) => { - return candidate.accounts.map(normalize).includes(hexed) - }) - if (match) { - resolve(match.keyring) - } else { - reject('No keyring found for the requested account.') - } - }) + return Promise.all(this.keyrings.map((keyring) => { + return Promise.all([ + keyring, + keyring.getAccounts(), + ]) + })) + .then(filter((candidate) => { + const accounts = candidate[1].map(normalize) + return accounts.includes(hexed) + })) + .then((winners) => { + if (winners && winners.length > 0) { + return winners[0][0] + } else { + throw new Error('No keyring found for the requested account.') + } }) } @@ -888,4 +880,5 @@ module.exports = class KeyringController extends EventEmitter { } + function noop () {} -- cgit v1.2.3 From df0b89074b6939081828ebc214bc26ffa5a89659 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 29 Nov 2016 15:50:26 -0800 Subject: Return promise correctly from setSelectedAddress --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 900b3ca25..ac9409dbb 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -282,7 +282,7 @@ module.exports = class KeyringController extends EventEmitter { setSelectedAccount (address) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) - Promise.resolve(addr) + return Promise.resolve(addr) } // Save Account Label -- cgit v1.2.3 From 1880cda9b95f3274d56e1f4abc513d1d7ddd59c2 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 30 Nov 2016 19:34:17 -0800 Subject: Fix vault encrypting & unlocking bug This is only a bug in dev, but was committed yesterday. Sometimes the `encrypt` method was being passed values other than the password as the encryption key, leading to un-unlockable vaults. To find this, and avoid it for all time hereafter, I added several more steps to our oft-neglected integration test suite, which now fully initializes a vault, locks it, and unlocks it again, to make sure all of those steps definitely work always. --- app/scripts/keyring-controller.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index ac9409dbb..9cfc3af97 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -167,7 +167,7 @@ module.exports = class KeyringController extends EventEmitter { this.configManager.setSelectedAccount(hexAccount) return this.setupAccounts(accounts) }) - .then(this.persistAllKeyrings.bind(this)) + .then(this.persistAllKeyrings.bind(this, password)) .then(this.fullUpdate.bind(this)) } @@ -226,9 +226,11 @@ module.exports = class KeyringController extends EventEmitter { }) .then((keyrings) => { this.keyrings = keyrings - return this.setupAccounts() + return this.fullUpdate() + }) + .catch((reason) => { + return reason }) - .then(this.fullUpdate.bind(this)) } // Add New Keyring @@ -250,6 +252,7 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings.push(keyring) return this.setupAccounts(accounts) }) + .then(() => { return this.password }) .then(this.persistAllKeyrings.bind(this)) .then(() => { return keyring @@ -692,6 +695,9 @@ module.exports = class KeyringController extends EventEmitter { // Takes an account address and an iterator representing // the current number of named accounts. getBalanceAndNickname (account) { + if (!account) { + throw new Error('Problem loading account.') + } const address = normalize(account) this.ethStore.addAccount(address) return this.createNickname(address) @@ -725,7 +731,9 @@ module.exports = class KeyringController extends EventEmitter { // encrypts that array with the provided `password`, // and persists that encrypted string to storage. persistAllKeyrings (password = this.password) { - this.password = password + if (typeof password === 'string') { + this.password = password + } return Promise.all(this.keyrings.map((keyring) => { return Promise.all([keyring.type, keyring.serialize()]) .then((serializedKeyringArray) => { -- cgit v1.2.3 From c43178360203b4571d9e00880b5bf2806908c179 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 1 Dec 2016 10:21:56 -0800 Subject: Remove redundant logging block --- app/scripts/keyring-controller.js | 3 --- 1 file changed, 3 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 9cfc3af97..40c9695dd 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -228,9 +228,6 @@ module.exports = class KeyringController extends EventEmitter { this.keyrings = keyrings return this.fullUpdate() }) - .catch((reason) => { - return reason - }) } // Add New Keyring -- cgit v1.2.3 From ab9e15b782620002c0a2477829db3e56a25a7d5c Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 8 Dec 2016 14:22:02 -0800 Subject: Mostly added bad account detection Currently riddled with logs, because the migrator is inexplicably returning before generating the new style accounts for comparison. --- app/scripts/keyring-controller.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 40c9695dd..d0ce16cbb 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -113,6 +113,7 @@ module.exports = class KeyringController extends EventEmitter { conversionDate: this.configManager.getConversionDate(), keyringTypes: this.keyringTypes.map(krt => krt.type), identities: this.identities, + lostAccounts: this.configManager.getLostAccounts(), } } @@ -623,7 +624,12 @@ module.exports = class KeyringController extends EventEmitter { migrateOldVaultIfAny (password) { const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() return this.idStoreMigrator.migratedVaultForPassword(password) - .then((serialized) => { + .then((result) => { + console.log('migrator called back with') + console.dir(result) + const { serialized, lostAccounts } = result + console.dir({ serialized, lostAccounts }) + this.configManager.setLostAccounts(lostAccounts) this.password = password if (serialized && shouldMigrate) { -- cgit v1.2.3 From 7b9749e30c4f8228fe62c1ad81515117cf7504bc Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Fri, 9 Dec 2016 12:24:25 -0800 Subject: Got bad account detection working and added to state --- app/scripts/keyring-controller.js | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index d0ce16cbb..6a087c918 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -623,16 +623,17 @@ module.exports = class KeyringController extends EventEmitter { // may be completed without interruption. migrateOldVaultIfAny (password) { const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() + if (!shouldMigrate) { + return Promise.resolve() + } + return this.idStoreMigrator.migratedVaultForPassword(password) .then((result) => { - console.log('migrator called back with') - console.dir(result) - const { serialized, lostAccounts } = result - console.dir({ serialized, lostAccounts }) - this.configManager.setLostAccounts(lostAccounts) this.password = password - if (serialized && shouldMigrate) { + if (result && shouldMigrate) { + const { serialized, lostAccounts } = result + this.configManager.setLostAccounts(lostAccounts) return this.restoreKeyring(serialized) .then(keyring => keyring.getAccounts()) .then((accounts) => { -- cgit v1.2.3 From 090935f90aa3c2589fee7bc038c8f4fcf77da03c Mon Sep 17 00:00:00 2001 From: Frances Pangilinan Date: Wed, 14 Dec 2016 12:55:41 -0800 Subject: Create a TxManager --- app/scripts/keyring-controller.js | 118 ++++++-------------------------------- 1 file changed, 17 insertions(+), 101 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 40c9695dd..37b3a947f 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,6 +1,4 @@ -const async = require('async') const ethUtil = require('ethereumjs-util') -const EthQuery = require('eth-query') const bip39 = require('bip39') const Transaction = require('ethereumjs-tx') const EventEmitter = require('events').EventEmitter @@ -36,7 +34,7 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = opts.ethStore this.encryptor = encryptor this.keyringTypes = keyringTypes - + this.txManager = opts.txManager this.keyrings = [] this.identities = {} // Essentially a name hash @@ -73,7 +71,7 @@ module.exports = class KeyringController extends EventEmitter { // or accept a state-resolving promise to consume their results. // // Not all methods end with this, that might be a nice refactor. - fullUpdate() { + fullUpdate () { this.emit('update') return Promise.resolve(this.getState()) } @@ -102,8 +100,8 @@ module.exports = class KeyringController extends EventEmitter { isInitialized: (!!wallet || !!vault), isUnlocked: Boolean(this.password), isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), - unconfTxs: this.configManager.unconfirmedTxs(), - transactions: this.configManager.getTxList(), + transactions: this.txManager.getTxList(), + unconfTxs: this.txManager.getUnapprovedTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), selectedAccount: address, @@ -341,7 +339,7 @@ module.exports = class KeyringController extends EventEmitter { // Caches the requesting Dapp's callback, `onTxDoneCb`, for resolution later. addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { const configManager = this.configManager - + const txManager = this.txManager // create txData obj with parameters and meta data var time = (new Date()).getTime() var txId = createId() @@ -351,95 +349,26 @@ module.exports = class KeyringController extends EventEmitter { id: txId, txParams: txParams, time: time, - status: 'unconfirmed', + status: 'unapproved', gasMultiplier: configManager.getGasMultiplier() || 1, metamaskNetworkId: this.getNetwork(), } - // keep the onTxDoneCb around for after approval/denial (requires user interaction) // This onTxDoneCb fires completion to the Dapp's write operation. - this._unconfTxCbs[txId] = onTxDoneCb - - var provider = this.ethStore._query.currentProvider - var query = new EthQuery(provider) - + txManager.txProviderUtils.analyzeGasUsage(txData, this.txDidComplete.bind(this, txData, onTxDoneCb, cb)) // calculate metadata for tx - this.analyzeTxGasUsage(query, txData, this.txDidComplete.bind(this, txData, cb)) - } - - estimateTxGas (query, txData, blockGasLimitHex, cb) { - const txParams = txData.txParams - // check if gasLimit is already specified - txData.gasLimitSpecified = Boolean(txParams.gas) - // if not, fallback to block gasLimit - if (!txData.gasLimitSpecified) { - txParams.gas = blockGasLimitHex - } - // run tx, see if it will OOG - query.estimateGas(txParams, cb) - } - - checkForTxGasError (txData, estimatedGasHex, cb) { - txData.estimatedGas = estimatedGasHex - // all gas used - must be an error - if (estimatedGasHex === txData.txParams.gas) { - txData.simulationFails = true - } - cb() - } - - setTxGas (txData, blockGasLimitHex, cb) { - const txParams = txData.txParams - // if OOG, nothing more to do - if (txData.simulationFails) { - cb() - return - } - // if gasLimit was specified and doesnt OOG, - // use original specified amount - if (txData.gasLimitSpecified) { - txData.estimatedGas = txParams.gas - cb() - return - } - // if gasLimit not originally specified, - // try adding an additional gas buffer to our estimation for safety - const estimatedGasBn = new BN(ethUtil.stripHexPrefix(txData.estimatedGas), 16) - const blockGasLimitBn = new BN(ethUtil.stripHexPrefix(blockGasLimitHex), 16) - const estimationWithBuffer = new BN(this.addGasBuffer(estimatedGasBn), 16) - // added gas buffer is too high - if (estimationWithBuffer.gt(blockGasLimitBn)) { - txParams.gas = txData.estimatedGas - // added gas buffer is safe - } else { - const gasWithBufferHex = ethUtil.intToHex(estimationWithBuffer) - txParams.gas = gasWithBufferHex - } - cb() - return } - txDidComplete (txData, cb, err) { + txDidComplete (txData, onTxDoneCb, cb, err) { if (err) return cb(err) - const configManager = this.configManager - configManager.addTx(txData) + const txManager = this.txManager + txManager.addTx(txData, onTxDoneCb) // signal update this.emit('update') // signal completion of add tx cb(null, txData) } - analyzeTxGasUsage (query, txData, cb) { - query.getBlockByNumber('latest', true, (err, block) => { - if (err) return cb(err) - async.waterfall([ - this.estimateTxGas.bind(this, query, txData, block.gasLimit), - this.checkForTxGasError.bind(this, txData), - this.setTxGas.bind(this, txData, block.gasLimit), - ], cb) - }) - } - // Cancel Transaction // @string txId // @function cb @@ -448,14 +377,8 @@ module.exports = class KeyringController extends EventEmitter { // // Forgets any tx matching `txId`. cancelTransaction (txId, cb) { - const configManager = this.configManager - var approvalCb = this._unconfTxCbs[txId] || noop - - // reject tx - approvalCb(null, false) - // clean up - configManager.rejectTx(txId) - delete this._unconfTxCbs[txId] + const txManager = this.txManager + txManager.setTxStatusRejected(txId) if (cb && typeof cb === 'function') { cb() @@ -473,16 +396,10 @@ module.exports = class KeyringController extends EventEmitter { // // Calls back the cached Dapp's confirmation callback, also. approveTransaction (txId, cb) { - const configManager = this.configManager - var approvalCb = this._unconfTxCbs[txId] || noop - - // accept tx - cb() - approvalCb(null, true) - // clean up - configManager.confirmTx(txId) - delete this._unconfTxCbs[txId] + const txManager = this.txManager + txManager.setTxStatusSigned(txId) this.emit('update') + cb() } signTransaction (txParams, cb) { @@ -510,9 +427,9 @@ module.exports = class KeyringController extends EventEmitter { .then((tx) => { // Add the tx hash to the persisted meta-tx object var txHash = ethUtil.bufferToHex(tx.hash()) - var metaTx = this.configManager.getTx(txParams.metamaskId) + var metaTx = this.txManager.getTx(txParams.metamaskId) metaTx.hash = txHash - this.configManager.updateTx(metaTx) + this.txManager.updateTx(metaTx) // return raw serialized tx var rawTx = ethUtil.bufferToHex(tx.serialize()) @@ -586,7 +503,6 @@ module.exports = class KeyringController extends EventEmitter { // Attempts to sign the provided @object msgParams. signMessage (msgParams, cb) { try { - const msgId = msgParams.metamaskId delete msgParams.metamaskId const approvalCb = this._unconfMsgCbs[msgId] || noop -- cgit v1.2.3 From e9bea92ac3243e58321cd8cf3f44f0df0c66aa70 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Mon, 19 Dec 2016 14:55:52 -0800 Subject: Lint. --- app/scripts/keyring-controller.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 40c9695dd..ca4c306be 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -73,7 +73,7 @@ module.exports = class KeyringController extends EventEmitter { // or accept a state-resolving promise to consume their results. // // Not all methods end with this, that might be a nice refactor. - fullUpdate() { + fullUpdate () { this.emit('update') return Promise.resolve(this.getState()) } @@ -586,7 +586,6 @@ module.exports = class KeyringController extends EventEmitter { // Attempts to sign the provided @object msgParams. signMessage (msgParams, cb) { try { - const msgId = msgParams.metamaskId delete msgParams.metamaskId const approvalCb = this._unconfMsgCbs[msgId] || noop -- cgit v1.2.3 From 26f1e6cbd2af9d6bb0c58871635466c459cc87d8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 19 Dec 2016 21:55:02 -0800 Subject: Remove encryptor in favor of external browser-passworder I broke out the encryptor lib into its own module on npm called browser-passworder. --- app/scripts/keyring-controller.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index ca4c306be..58366c26f 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -5,8 +5,9 @@ const bip39 = require('bip39') const Transaction = require('ethereumjs-tx') const EventEmitter = require('events').EventEmitter const filter = require('promise-filter') +const encryptor = require('browser-passworder') + const normalize = require('./lib/sig-util').normalize -const encryptor = require('./lib/encryptor') const messageManager = require('./lib/message-manager') const IdStoreMigrator = require('./lib/idStore-migrator') const BN = ethUtil.BN -- cgit v1.2.3 From 931ae5f64a233b472c3dada8aa6af77e0bffad5e Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Tue, 20 Dec 2016 13:53:14 -0800 Subject: Make notices confirmation configurable - Confirm button will now dismiss the lost accounts array. --- app/scripts/keyring-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 2888e58a9..61ee56638 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -114,7 +114,6 @@ module.exports = class KeyringController extends EventEmitter { conversionDate: this.configManager.getConversionDate(), keyringTypes: this.keyringTypes.map(krt => krt.type), identities: this.identities, - lostAccounts: this.configManager.getLostAccounts(), } } -- cgit v1.2.3 From 48f2ae2154b6e804ee60cfc1235025c128a6cfa8 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 11:01:04 -0800 Subject: Move old keystore migration code to metamask controller Allows keyring controller to be more generic, less opinionated, and who knows, maybe sooner publishable as its own thing. --- app/scripts/keyring-controller.js | 46 +-------------------------------------- 1 file changed, 1 insertion(+), 45 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 61ee56638..1786f7c24 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -9,7 +9,6 @@ const encryptor = require('browser-passworder') const normalize = require('./lib/sig-util').normalize const messageManager = require('./lib/message-manager') -const IdStoreMigrator = require('./lib/idStore-migrator') const BN = ethUtil.BN // Keyrings: @@ -45,11 +44,6 @@ module.exports = class KeyringController extends EventEmitter { this._unconfMsgCbs = {} this.getNetwork = opts.getNetwork - - // TEMPORARY UNTIL FULL DEPRECATION: - this.idStoreMigrator = new IdStoreMigrator({ - configManager: this.configManager, - }) } // Set Store @@ -221,10 +215,7 @@ module.exports = class KeyringController extends EventEmitter { // Temporarily also migrates any old-style vaults first, as well. // (Pre MetaMask 3.0.0) submitPassword (password) { - return this.migrateOldVaultIfAny(password) - .then(() => { - return this.unlockKeyrings(password) - }) + return this.unlockKeyrings(password) .then((keyrings) => { this.keyrings = keyrings return this.fullUpdate() @@ -610,41 +601,6 @@ module.exports = class KeyringController extends EventEmitter { // THESE METHODS ARE ONLY USED INTERNALLY TO THE KEYRING-CONTROLLER // AND SO MAY BE CHANGED MORE LIBERALLY THAN THE ABOVE METHODS. - // Migrate Old Vault If Any - // @string password - // - // returns Promise() - // - // Temporary step used when logging in. - // Checks if old style (pre-3.0.0) Metamask Vault exists. - // If so, persists that vault in the new vault format - // with the provided password, so the other unlock steps - // may be completed without interruption. - migrateOldVaultIfAny (password) { - const shouldMigrate = !!this.configManager.getWallet() && !this.configManager.getVault() - if (!shouldMigrate) { - return Promise.resolve() - } - - return this.idStoreMigrator.migratedVaultForPassword(password) - .then((result) => { - this.password = password - - if (result && shouldMigrate) { - const { serialized, lostAccounts } = result - this.configManager.setLostAccounts(lostAccounts) - return this.restoreKeyring(serialized) - .then(keyring => keyring.getAccounts()) - .then((accounts) => { - this.configManager.setSelectedAccount(accounts[0]) - return this.persistAllKeyrings() - }) - } else { - return Promise.resolve() - } - }) - } - // Create First Key Tree // returns @Promise // -- cgit v1.2.3 From 6e78494846c9032fbf1264a0225c0df4df0867cb Mon Sep 17 00:00:00 2001 From: Frances Pangilinan Date: Fri, 16 Dec 2016 10:33:36 -0800 Subject: First pass at revision requests --- app/scripts/keyring-controller.js | 101 ++------------------------------------ 1 file changed, 5 insertions(+), 96 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 37b3a947f..64c2ac933 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -100,8 +100,6 @@ module.exports = class KeyringController extends EventEmitter { isInitialized: (!!wallet || !!vault), isUnlocked: Boolean(this.password), isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), - transactions: this.txManager.getTxList(), - unconfTxs: this.txManager.getUnapprovedTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), selectedAccount: address, @@ -319,89 +317,10 @@ module.exports = class KeyringController extends EventEmitter { } - // SIGNING RELATED METHODS + // SIGNING METHODS // - // SIGN, SUBMIT TX, CANCEL, AND APPROVE. - // THIS SECTION INVOLVES THE REQUEST, STORING, AND SIGNING OF DATA - // WITH THE KEYS STORED IN THIS CONTROLLER. - - - // Add Unconfirmed Transaction - // @object txParams - // @function onTxDoneCb - // @function cb - // - // Calls back `cb` with @object txData = { txParams } - // Calls back `onTxDoneCb` with `true` or an `error` depending on result. - // - // Prepares the given `txParams` for final confirmation and approval. - // Estimates gas and other preparatory steps. - // Caches the requesting Dapp's callback, `onTxDoneCb`, for resolution later. - addUnconfirmedTransaction (txParams, onTxDoneCb, cb) { - const configManager = this.configManager - const txManager = this.txManager - // create txData obj with parameters and meta data - var time = (new Date()).getTime() - var txId = createId() - txParams.metamaskId = txId - txParams.metamaskNetworkId = this.getNetwork() - var txData = { - id: txId, - txParams: txParams, - time: time, - status: 'unapproved', - gasMultiplier: configManager.getGasMultiplier() || 1, - metamaskNetworkId: this.getNetwork(), - } - // keep the onTxDoneCb around for after approval/denial (requires user interaction) - // This onTxDoneCb fires completion to the Dapp's write operation. - txManager.txProviderUtils.analyzeGasUsage(txData, this.txDidComplete.bind(this, txData, onTxDoneCb, cb)) - // calculate metadata for tx - } - - txDidComplete (txData, onTxDoneCb, cb, err) { - if (err) return cb(err) - const txManager = this.txManager - txManager.addTx(txData, onTxDoneCb) - // signal update - this.emit('update') - // signal completion of add tx - cb(null, txData) - } - - // Cancel Transaction - // @string txId - // @function cb - // - // Calls back `cb` with no error if provided. - // - // Forgets any tx matching `txId`. - cancelTransaction (txId, cb) { - const txManager = this.txManager - txManager.setTxStatusRejected(txId) - - if (cb && typeof cb === 'function') { - cb() - } - } - - // Approve Transaction - // @string txId - // @function cb - // - // Calls back `cb` with no error always. - // - // Attempts to sign a Transaction with `txId` - // and submit it to the blockchain. - // - // Calls back the cached Dapp's confirmation callback, also. - approveTransaction (txId, cb) { - const txManager = this.txManager - txManager.setTxStatusSigned(txId) - this.emit('update') - cb() - } - + // This method signs tx and returns a promise for + // TX Manager to update the state after signing signTransaction (txParams, cb) { try { const address = normalize(txParams.from) @@ -420,20 +339,10 @@ module.exports = class KeyringController extends EventEmitter { txParams.data = normalize(txParams.data) txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) txParams.nonce = normalize(txParams.nonce) - const tx = new Transaction(txParams) return keyring.signTransaction(address, tx) - }) - .then((tx) => { - // Add the tx hash to the persisted meta-tx object - var txHash = ethUtil.bufferToHex(tx.hash()) - var metaTx = this.txManager.getTx(txParams.metamaskId) - metaTx.hash = txHash - this.txManager.updateTx(metaTx) - - // return raw serialized tx - var rawTx = ethUtil.bufferToHex(tx.serialize()) - cb(null, rawTx) + }).then((tx) => { + return {tx, txParams, cb} }) } catch (e) { cb(e) -- cgit v1.2.3 From 1ebcbe296b060c9cf431d485d7bb84f696edbdf5 Mon Sep 17 00:00:00 2001 From: Frances Pangilinan Date: Tue, 20 Dec 2016 13:12:14 -0800 Subject: Migrate all tx mutation code out of keyring controller and Fix up txManager to reflect code review requests --- app/scripts/keyring-controller.js | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 64c2ac933..0a06e4a5d 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -1,6 +1,5 @@ const ethUtil = require('ethereumjs-util') const bip39 = require('bip39') -const Transaction = require('ethereumjs-tx') const EventEmitter = require('events').EventEmitter const filter = require('promise-filter') const normalize = require('./lib/sig-util').normalize @@ -321,28 +320,14 @@ module.exports = class KeyringController extends EventEmitter { // // This method signs tx and returns a promise for // TX Manager to update the state after signing - signTransaction (txParams, cb) { + signTransaction (ethTx, selectedAddress, txId, cb) { try { - const address = normalize(txParams.from) + const address = normalize(selectedAddress) return this.getKeyringForAccount(address) .then((keyring) => { - // Handle gas pricing - var gasMultiplier = this.configManager.getGasMultiplier() || 1 - var gasPrice = new BN(ethUtil.stripHexPrefix(txParams.gasPrice), 16) - gasPrice = gasPrice.mul(new BN(gasMultiplier * 100, 10)).div(new BN(100, 10)) - txParams.gasPrice = ethUtil.intToHex(gasPrice.toNumber()) - - // normalize values - txParams.to = normalize(txParams.to) - txParams.from = normalize(txParams.from) - txParams.value = normalize(txParams.value) - txParams.data = normalize(txParams.data) - txParams.gasLimit = normalize(txParams.gasLimit || txParams.gas) - txParams.nonce = normalize(txParams.nonce) - const tx = new Transaction(txParams) - return keyring.signTransaction(address, tx) + return keyring.signTransaction(address, ethTx) }).then((tx) => { - return {tx, txParams, cb} + this.emit(`${txId}:signed`, {tx, txId, cb}) }) } catch (e) { cb(e) -- cgit v1.2.3 From a85c691b71d5142d2412000930328fbe9161760a Mon Sep 17 00:00:00 2001 From: Frances Pangilinan Date: Wed, 21 Dec 2016 14:06:15 -0800 Subject: Remove txManager in keyring controller --- app/scripts/keyring-controller.js | 2 -- 1 file changed, 2 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 0a06e4a5d..a58742228 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -33,11 +33,9 @@ module.exports = class KeyringController extends EventEmitter { this.ethStore = opts.ethStore this.encryptor = encryptor this.keyringTypes = keyringTypes - this.txManager = opts.txManager this.keyrings = [] this.identities = {} // Essentially a name hash - this._unconfTxCbs = {} this._unconfMsgCbs = {} this.getNetwork = opts.getNetwork -- cgit v1.2.3 From 05ce7086f78e344aee23bb95de56d28317074a7d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 21 Dec 2016 17:19:53 -0800 Subject: Added error when trying to unlock uninitialized vault --- app/scripts/keyring-controller.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1786f7c24..4e9193ab2 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -721,6 +721,10 @@ module.exports = class KeyringController extends EventEmitter { // initializing the persisted keyrings to RAM. unlockKeyrings (password) { const encryptedVault = this.configManager.getVault() + if (!encryptedVault) { + throw new Error('Cannot unlock without a previous vault.') + } + return this.encryptor.decrypt(password, encryptedVault) .then((vault) => { this.password = password -- cgit v1.2.3 From a10fe6b6f4217b3984f861bb8ad69d075f672872 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 22 Dec 2016 16:28:14 -0800 Subject: Return keyring metadata on metamask state object Required making the getState methods for both keyringController and metamaskController async. They both now return promises, and the main metamask-controller.getState method is now nodeified. Will allow the UI to render loose keys differently than persisted keys. --- app/scripts/keyring-controller.js | 61 +++++++++++++++++++++++++++------------ 1 file changed, 42 insertions(+), 19 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 4e9193ab2..d53de1ab6 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -91,26 +91,32 @@ module.exports = class KeyringController extends EventEmitter { const address = configManager.getSelectedAccount() const wallet = configManager.getWallet() // old style vault const vault = configManager.getVault() // new style vault - - return { - seedWords: this.configManager.getSeedWords(), - isInitialized: (!!wallet || !!vault), - isUnlocked: Boolean(this.password), - isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), // AUDIT this.configManager.getConfirmedDisclaimer(), - unconfTxs: this.configManager.unconfirmedTxs(), - transactions: this.configManager.getTxList(), - unconfMsgs: messageManager.unconfirmedMsgs(), - messages: messageManager.getMsgList(), - selectedAccount: address, - shapeShiftTxList: this.configManager.getShapeShiftTxList(), - currentFiat: this.configManager.getCurrentFiat(), - conversionRate: this.configManager.getConversionRate(), - conversionDate: this.configManager.getConversionDate(), - keyringTypes: this.keyringTypes.map(krt => krt.type), - identities: this.identities, - } + const keyrings = this.keyrings + + return Promise.all(keyrings.map(this.displayForKeyring)) + .then((displayKeyrings) => { + return { + seedWords: this.configManager.getSeedWords(), + isInitialized: (!!wallet || !!vault), + isUnlocked: Boolean(this.password), + isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), + unconfTxs: this.configManager.unconfirmedTxs(), + transactions: this.configManager.getTxList(), + unconfMsgs: messageManager.unconfirmedMsgs(), + messages: messageManager.getMsgList(), + selectedAccount: address, + shapeShiftTxList: this.configManager.getShapeShiftTxList(), + currentFiat: this.configManager.getCurrentFiat(), + conversionRate: this.configManager.getConversionRate(), + conversionDate: this.configManager.getConversionDate(), + keyringTypes: this.keyringTypes.map(krt => krt.type), + identities: this.identities, + keyrings: displayKeyrings, + } + }) } + // Create New Vault And Keychain // @string password - The password to encrypt the vault with // @@ -693,7 +699,7 @@ module.exports = class KeyringController extends EventEmitter { if (typeof password === 'string') { this.password = password } - return Promise.all(this.keyrings.map((keyring) => { + return Promise.all(this.keyrings.map((keyring, i) => { return Promise.all([keyring.type, keyring.serialize()]) .then((serializedKeyringArray) => { // Label the output values on each serialized Keyring: @@ -744,6 +750,7 @@ module.exports = class KeyringController extends EventEmitter { // On success, returns the resulting @Keyring instance. restoreKeyring (serialized) { const { type, data } = serialized + const Keyring = this.getKeyringClassForType(type) const keyring = new Keyring() return keyring.deserialize(data) @@ -816,6 +823,22 @@ module.exports = class KeyringController extends EventEmitter { }) } + // Display For Keyring + // @Keyring keyring + // + // returns Promise( @Object { type:String, accounts:Array } ) + // + // Is used for adding the current keyrings to the state object. + displayForKeyring (keyring) { + return keyring.getAccounts() + .then((accounts) => { + return { + type: keyring.type, + accounts: accounts, + } + }) + } + // Add Gas Buffer // @string gas (as hexadecimal value) // -- cgit v1.2.3 From af2c7004b05ad985b9ec8fc16b8bbec1765bf062 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Mon, 2 Jan 2017 15:08:18 -0800 Subject: Make single letter variables more verbose --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 05c4a26fa..92429f7f5 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -508,7 +508,7 @@ module.exports = class KeyringController extends EventEmitter { if (typeof password === 'string') { this.password = password } - return Promise.all(this.keyrings.map((keyring, i) => { + return Promise.all(this.keyrings.map((keyring) => { return Promise.all([keyring.type, keyring.serialize()]) .then((serializedKeyringArray) => { // Label the output values on each serialized Keyring: -- cgit v1.2.3 From e6da8e2762cd54975c334314357f1cd27cc980c8 Mon Sep 17 00:00:00 2001 From: Frankie Date: Wed, 4 Jan 2017 13:04:33 -0800 Subject: Fix signing of transactions --- app/scripts/keyring-controller.js | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 016740d88..acec8feb1 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -310,20 +310,22 @@ module.exports = class KeyringController extends EventEmitter { // // This method signs tx and returns a promise for // TX Manager to update the state after signing - signTransaction (ethTx, selectedAddress, txId, cb) { - try { - const address = normalize(selectedAddress) - return this.getKeyringForAccount(address) - .then((keyring) => { - return keyring.signTransaction(address, ethTx) - }).then((tx) => { - this.emit(`${txId}:signed`, {tx, txId, cb}) - }) - } catch (e) { - cb(e) - } - } + signTransaction (ethTx, selectedAddress, txId) { + return new Promise((resolve, reject) => { + try { + const address = normalize(selectedAddress) + return this.getKeyringForAccount(address) + .then((keyring) => { + return keyring.signTransaction(address, ethTx) + }).then((tx) => { + resolve({tx, txId}) + }) + } catch (e) { + reject(e) + } + }) + } // Add Unconfirmed Message // @object msgParams // @function cb -- cgit v1.2.3 From cf6817092b92930ab96e1c9e610669b485b384ff Mon Sep 17 00:00:00 2001 From: Frankie Date: Wed, 4 Jan 2017 15:03:45 -0800 Subject: remove unnecessary try statments --- app/scripts/keyring-controller.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index 1a26a887f..c58be0aae 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -318,18 +318,12 @@ module.exports = class KeyringController extends EventEmitter { // TX Manager to update the state after signing signTransaction (ethTx, selectedAddress, txId) { - return new Promise((resolve, reject) => { - try { - const address = normalize(selectedAddress) - return this.getKeyringForAccount(address) - .then((keyring) => { - return keyring.signTransaction(address, ethTx) - }).then((tx) => { - resolve({tx, txId}) - }) - } catch (e) { - reject(e) - } + const address = normalize(selectedAddress) + return this.getKeyringForAccount(address) + .then((keyring) => { + return keyring.signTransaction(address, ethTx) + }).then((tx) => { + return {tx, txId} }) } // Add Unconfirmed Message -- cgit v1.2.3 From 0fae263a9acb1f4023070b37ee1b91815e34de86 Mon Sep 17 00:00:00 2001 From: Frankie Date: Tue, 10 Jan 2017 11:52:25 -0800 Subject: Take some of the tx Logic out of the UI and create a visble state for pending and unaproved transactions --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c58be0aae..a457a2560 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -95,7 +95,6 @@ module.exports = class KeyringController extends EventEmitter { isInitialized: (!!wallet || !!vault), isUnlocked: Boolean(this.password), isDisclaimerConfirmed: this.configManager.getConfirmedDisclaimer(), - transactions: this.configManager.getTxList(), unconfMsgs: messageManager.unconfirmedMsgs(), messages: messageManager.getMsgList(), selectedAccount: address, @@ -273,6 +272,7 @@ module.exports = class KeyringController extends EventEmitter { setSelectedAccount (address) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) + this.emit('update') return Promise.resolve(addr) } -- cgit v1.2.3 From d87a7b2a767def40d89138103eb53c665419cc3d Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 11 Jan 2017 14:58:20 -0800 Subject: Send update to UI when changing selected account Fixes #981 --- app/scripts/keyring-controller.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index c58be0aae..d4c0d863e 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -273,7 +273,7 @@ module.exports = class KeyringController extends EventEmitter { setSelectedAccount (address) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) - return Promise.resolve(addr) + return this.fullUpdate() } // Save Account Label -- cgit v1.2.3 From 576e2ad64df293adcc8c2494a3648100ba4b28f5 Mon Sep 17 00:00:00 2001 From: Frankie Date: Wed, 11 Jan 2017 15:44:21 -0800 Subject: Fix wording and icon of failed txs --- app/scripts/keyring-controller.js | 1 - 1 file changed, 1 deletion(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index a457a2560..81e6a4905 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -272,7 +272,6 @@ module.exports = class KeyringController extends EventEmitter { setSelectedAccount (address) { var addr = normalize(address) this.configManager.setSelectedAccount(addr) - this.emit('update') return Promise.resolve(addr) } -- cgit v1.2.3 From 29e83d71a82bfdbeadc9fbecfa97d73ef11fecfb Mon Sep 17 00:00:00 2001 From: kumavis Date: Fri, 13 Jan 2017 02:00:11 -0800 Subject: background - handle tx finalization in controllers instead of provider-engine --- app/scripts/keyring-controller.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'app/scripts/keyring-controller.js') diff --git a/app/scripts/keyring-controller.js b/app/scripts/keyring-controller.js index d4c0d863e..df2910187 100644 --- a/app/scripts/keyring-controller.js +++ b/app/scripts/keyring-controller.js @@ -317,13 +317,11 @@ module.exports = class KeyringController extends EventEmitter { // This method signs tx and returns a promise for // TX Manager to update the state after signing - signTransaction (ethTx, selectedAddress, txId) { - const address = normalize(selectedAddress) - return this.getKeyringForAccount(address) + signTransaction (ethTx, _fromAddress) { + const fromAddress = normalize(_fromAddress) + return this.getKeyringForAccount(fromAddress) .then((keyring) => { - return keyring.signTransaction(address, ethTx) - }).then((tx) => { - return {tx, txId} + return keyring.signTransaction(fromAddress, ethTx) }) } // Add Unconfirmed Message -- cgit v1.2.3