Skip to content

Commit b8f75e3

Browse files
authored
Merge pull request #644 from MetaMask/revert-638-i555-SaltVault
Revert "Add new eth-lightwallet salting to vault."
2 parents fcc9ca8 + c37c050 commit b8f75e3

File tree

8 files changed

+89
-151
lines changed

8 files changed

+89
-151
lines changed

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
- MetaMask logo now renders as super lightweight SVG, improving compatibility and performance.
1111
- Now showing loading indication during vault unlocking, to clarify behavior for users who are experience slow unlocks.
1212
- Now only initially creates one wallet when restoring a vault, to reduce some users' confusion.
13-
- Improved the security of vault encryption by ensuring passwords are always uniquely salted.
1413

1514
## 2.10.2 2016-09-02
1615

app/scripts/lib/idStore.js

Lines changed: 61 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ const inherits = require('util').inherits
33
const async = require('async')
44
const ethUtil = require('ethereumjs-util')
55
const EthQuery = require('eth-query')
6-
const KeyStore = require('eth-lightwallet').keystore
6+
const LightwalletKeyStore = require('eth-lightwallet').keystore
77
const clone = require('clone')
88
const extend = require('xtend')
99
const createId = require('web3-provider-engine/util/random-id')
@@ -50,16 +50,15 @@ IdentityStore.prototype.createNewVault = function (password, entropy, cb) {
5050
if (serializedKeystore) {
5151
this.configManager.setData({})
5252
}
53-
5453
this._createIdmgmt(password, null, entropy, (err) => {
5554
if (err) return cb(err)
5655

56+
this._loadIdentities()
57+
this._didUpdate()
5758
this._autoFaucet()
5859

5960
this.configManager.setShowSeedWords(true)
6061
var seedWords = this._idmgmt.getSeed()
61-
62-
6362
cb(null, seedWords)
6463
})
6564
}
@@ -76,6 +75,7 @@ IdentityStore.prototype.recoverFromSeed = function (password, seed, cb) {
7675
if (err) return cb(err)
7776

7877
this._loadIdentities()
78+
this._didUpdate()
7979
cb(null, this.getState())
8080
})
8181
}
@@ -125,20 +125,15 @@ IdentityStore.prototype.getSelectedAddress = function () {
125125
return configManager.getSelectedAccount()
126126
}
127127

128-
IdentityStore.prototype.setSelectedAddressSync = function (address) {
128+
IdentityStore.prototype.setSelectedAddress = function (address, cb) {
129129
const configManager = this.configManager
130130
if (!address) {
131131
var addresses = this._getAddresses()
132132
address = addresses[0]
133133
}
134134

135135
configManager.setSelectedAccount(address)
136-
return address
137-
}
138-
139-
IdentityStore.prototype.setSelectedAddress = function (address, cb) {
140-
const resultAddress = this.setSelectedAddressSync(address)
141-
if (cb) return cb(null, resultAddress)
136+
if (cb) return cb(null, address)
142137
}
143138

144139
IdentityStore.prototype.revealAccount = function (cb) {
@@ -148,7 +143,6 @@ IdentityStore.prototype.revealAccount = function (cb) {
148143

149144
keyStore.setDefaultHdDerivationPath(this.hdPathString)
150145
keyStore.generateNewAddress(derivedKey, 1)
151-
152146
configManager.setWallet(keyStore.serialize())
153147

154148
this._loadIdentities()
@@ -399,6 +393,7 @@ IdentityStore.prototype._loadIdentities = function () {
399393
var addresses = this._getAddresses()
400394
addresses.forEach((address, i) => {
401395
// // add to ethStore
396+
this._ethStore.addAccount(address)
402397
// add to identities
403398
const defaultLabel = 'Wallet ' + (i + 1)
404399
const nickname = configManager.nicknameForWallet(address)
@@ -417,6 +412,7 @@ IdentityStore.prototype.saveAccountLabel = function (account, label, cb) {
417412
configManager.setNicknameForWallet(account, label)
418413
this._loadIdentities()
419414
cb(null, label)
415+
this._didUpdate()
420416
}
421417

422418
// mayBeFauceting
@@ -440,76 +436,77 @@ IdentityStore.prototype._mayBeFauceting = function (i) {
440436
//
441437

442438
IdentityStore.prototype.tryPassword = function (password, cb) {
443-
var serializedKeystore = this.configManager.getWallet()
444-
var keyStore = KeyStore.deserialize(serializedKeystore)
445-
446-
keyStore.keyFromPassword(password, (err, pwDerivedKey) => {
447-
if (err) return cb(err)
448-
449-
const isCorrect = keyStore.isDerivedKeyCorrect(pwDerivedKey)
450-
if (!isCorrect) return cb(new Error('Lightwallet - password incorrect'))
451-
452-
cb()
453-
})
439+
this._createIdmgmt(password, null, null, cb)
454440
}
455441

456-
IdentityStore.prototype._createIdmgmt = function (password, seedPhrase, entropy, cb) {
457-
const opts = {
458-
password,
459-
hdPathString: this.hdPathString,
460-
}
461-
462-
if (seedPhrase) {
463-
opts.seedPhrase = seedPhrase
464-
}
442+
IdentityStore.prototype._createIdmgmt = function (password, seed, entropy, cb) {
443+
const configManager = this.configManager
465444

466-
KeyStore.createVault(opts, (err, keyStore) => {
445+
var keyStore = null
446+
LightwalletKeyStore.deriveKeyFromPassword(password, (err, derivedKey) => {
467447
if (err) return cb(err)
448+
var serializedKeystore = configManager.getWallet()
449+
450+
if (seed) {
451+
try {
452+
keyStore = this._restoreFromSeed(password, seed, derivedKey)
453+
} catch (e) {
454+
return cb(e)
455+
}
456+
457+
// returning user, recovering from storage
458+
} else if (serializedKeystore) {
459+
keyStore = LightwalletKeyStore.deserialize(serializedKeystore)
460+
var isCorrect = keyStore.isDerivedKeyCorrect(derivedKey)
461+
if (!isCorrect) return cb(new Error('Lightwallet - password incorrect'))
462+
463+
// first time here
464+
} else {
465+
keyStore = this._createFirstWallet(entropy, derivedKey)
466+
}
468467

469468
this._keyStore = keyStore
470-
471-
keyStore.keyFromPassword(password, (err, derivedKey) => {
472-
if (err) return cb(err)
473-
474-
this.purgeCache()
475-
476-
keyStore.addHdDerivationPath(this.hdPathString, derivedKey, {curve: 'secp256k1', purpose: 'sign'})
477-
478-
this._createFirstWallet(derivedKey)
479-
480-
this._idmgmt = new IdManagement({
481-
keyStore: keyStore,
482-
derivedKey: derivedKey,
483-
configManager: this.configManager,
484-
})
485-
486-
this.setSelectedAddressSync()
487-
488-
cb()
469+
this._idmgmt = new IdManagement({
470+
keyStore: keyStore,
471+
derivedKey: derivedKey,
472+
hdPathSTring: this.hdPathString,
473+
configManager: this.configManager,
489474
})
475+
476+
cb()
490477
})
491478
}
492479

493-
IdentityStore.prototype.purgeCache = function () {
494-
this._getAddresses().forEach((address) => {
495-
this._ethStore.del(address)
496-
})
480+
IdentityStore.prototype._restoreFromSeed = function (password, seed, derivedKey) {
481+
const configManager = this.configManager
482+
var keyStore = new LightwalletKeyStore(seed, derivedKey, this.hdPathString)
483+
keyStore.addHdDerivationPath(this.hdPathString, derivedKey, {curve: 'secp256k1', purpose: 'sign'})
484+
keyStore.setDefaultHdDerivationPath(this.hdPathString)
485+
486+
keyStore.generateNewAddress(derivedKey, 1)
487+
configManager.setWallet(keyStore.serialize())
488+
if (global.METAMASK_DEBUG) {
489+
console.log('restored from seed. saved to keystore')
490+
}
491+
return keyStore
497492
}
498493

499-
IdentityStore.prototype._createFirstWallet = function (derivedKey) {
500-
const keyStore = this._keyStore
494+
IdentityStore.prototype._createFirstWallet = function (entropy, derivedKey) {
495+
const configManager = this.configManager
496+
var secretSeed = LightwalletKeyStore.generateRandomSeed(entropy)
497+
var keyStore = new LightwalletKeyStore(secretSeed, derivedKey, this.hdPathString)
498+
keyStore.addHdDerivationPath(this.hdPathString, derivedKey, {curve: 'secp256k1', purpose: 'sign'})
501499
keyStore.setDefaultHdDerivationPath(this.hdPathString)
500+
502501
keyStore.generateNewAddress(derivedKey, 1)
503-
this.configManager.setWallet(keyStore.serialize())
504-
var addresses = keyStore.getAddresses()
505-
this._ethStore.addAccount(ethUtil.addHexPrefix(addresses[0]))
502+
configManager.setWallet(keyStore.serialize())
503+
console.log('saved to keystore')
504+
return keyStore
506505
}
507506

508507
// get addresses and normalize address hexString
509508
IdentityStore.prototype._getAddresses = function () {
510-
return this._keyStore.getAddresses(this.hdPathString).map((address) => {
511-
return ethUtil.addHexPrefix(address)
512-
})
509+
return this._keyStore.getAddresses(this.hdPathString).map((address) => { return '0x' + address })
513510
}
514511

515512
IdentityStore.prototype._autoFaucet = function () {

test/unit/idStore-test.js

Lines changed: 10 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
var assert = require('assert')
22
var IdentityStore = require('../../app/scripts/lib/idStore')
33
var configManagerGen = require('../lib/mock-config-manager')
4-
const ethUtil = require('ethereumjs-util')
5-
const async = require('async')
64

75
describe('IdentityStore', function() {
86

@@ -20,12 +18,11 @@ describe('IdentityStore', function() {
2018
idStore = new IdentityStore({
2119
configManager: configManagerGen(),
2220
ethStore: {
23-
addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) },
21+
addAccount(acct) { accounts.push(acct) },
2422
},
2523
})
2624

2725
idStore.createNewVault(password, entropy, (err, seeds) => {
28-
assert.ifError(err, 'createNewVault threw error')
2926
seedWords = seeds
3027
originalKeystore = idStore._idmgmt.keyStore
3128
done()
@@ -41,7 +38,7 @@ describe('IdentityStore', function() {
4138
idStore = new IdentityStore({
4239
configManager: configManagerGen(),
4340
ethStore: {
44-
addAccount(acct) { newAccounts.push(ethUtil.addHexPrefix(acct)) },
41+
addAccount(acct) { newAccounts.push(acct) },
4542
},
4643
})
4744
})
@@ -60,90 +57,32 @@ describe('IdentityStore', function() {
6057
})
6158

6259
describe('#recoverFromSeed BIP44 compliance', function() {
63-
const salt = 'lightwalletSalt'
60+
let seedWords = 'picnic injury awful upper eagle junk alert toss flower renew silly vague'
61+
let firstAccount = '0x5d8de92c205279c10e5669f797b853ccef4f739a'
6462

6563
let password = 'secret!'
6664
let accounts = []
6765
let idStore
6866

69-
var assertions = [
70-
{
71-
seed: 'picnic injury awful upper eagle junk alert toss flower renew silly vague',
72-
account: '0x5d8de92c205279c10e5669f797b853ccef4f739a',
73-
},
74-
{
75-
seed: 'radar blur cabbage chef fix engine embark joy scheme fiction master release',
76-
account: '0xe15d894becb0354c501ae69429b05143679f39e0',
77-
},
78-
{
79-
seed: 'phone coyote caught pattern found table wedding list tumble broccoli chief swing',
80-
account: '0xb0e868f24bc7fec2bce2efc2b1c344d7569cd9d2',
81-
},
82-
{
83-
seed: 'recycle tag bird palace blue village anxiety census cook soldier example music',
84-
account: '0xab34a45920afe4af212b96ec51232aaa6a33f663',
85-
},
86-
{
87-
seed: 'half glimpse tape cute harvest sweet bike voyage actual floor poet lazy',
88-
account: '0x28e9044597b625ac4beda7250011670223de43b2',
89-
},
90-
{
91-
seed: 'flavor tiger carpet motor angry hungry document inquiry large critic usage liar',
92-
account: '0xb571be96558940c4e9292e1999461aa7499fb6cd',
93-
},
94-
]
95-
9667
before(function() {
9768
window.localStorage = {} // Hacking localStorage support into JSDom
9869

9970
idStore = new IdentityStore({
10071
configManager: configManagerGen(),
10172
ethStore: {
102-
addAccount(acct) { accounts.push(ethUtil.addHexPrefix(acct)) },
73+
addAccount(acct) { accounts.push(acct) },
10374
},
10475
})
10576
})
10677

107-
beforeEach(function() {
108-
accounts = []
109-
})
110-
111-
it('should enforce seed compliance with TestRPC', function (done) {
112-
const tests = assertions.map((assertion) => {
113-
return function (cb) {
114-
accounts = []
115-
idStore.recoverFromSeed(password, assertion.seed, (err) => {
116-
assert.ifError(err)
117-
118-
var received = accounts[0].toLowerCase()
119-
var expected = assertion.account.toLowerCase()
120-
assert.equal(received, expected)
121-
cb()
122-
})
123-
}
124-
})
78+
it('should return the expected first account', function (done) {
12579

126-
async.series(tests, function(err, results) {
80+
idStore.recoverFromSeed(password, seedWords, (err) => {
12781
assert.ifError(err)
128-
done()
129-
})
130-
})
13182

132-
it('should allow restoring and unlocking again', function (done) {
133-
const assertion = assertions[0]
134-
idStore.recoverFromSeed(password, assertion.seed, (err) => {
135-
assert.ifError(err)
136-
137-
var received = accounts[0].toLowerCase()
138-
var expected = assertion.account.toLowerCase()
139-
assert.equal(received, expected)
140-
141-
142-
idStore.submitPassword(password, function(err, account) {
143-
assert.ifError(err)
144-
assert.equal(account, expected)
145-
done()
146-
})
83+
let newKeystore = idStore._idmgmt.keyStore
84+
assert.equal(accounts[0], firstAccount)
85+
done()
14786
})
14887
})
14988
})

ui/app/accounts/account-list-item.js

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ const EthBalance = require('../components/eth-balance')
77
const CopyButton = require('../components/copyButton')
88
const Identicon = require('../components/identicon')
99

10-
module.exports = AccountListItem
10+
module.exports = NewComponent
1111

12-
inherits(AccountListItem, Component)
13-
function AccountListItem () {
12+
inherits(NewComponent, Component)
13+
function NewComponent () {
1414
Component.call(this)
1515
}
1616

17-
AccountListItem.prototype.render = function () {
17+
NewComponent.prototype.render = function () {
1818
const identity = this.props.identity
1919
var isSelected = this.props.selectedAddress === identity.address
2020
var account = this.props.accounts[identity.address]
@@ -23,6 +23,9 @@ AccountListItem.prototype.render = function () {
2323
return (
2424
h(`.accounts-list-option.flex-row.flex-space-between.pointer.hover-white${selectedClass}`, {
2525
key: `account-panel-${identity.address}`,
26+
style: {
27+
flex: '1 0 auto',
28+
},
2629
onClick: (event) => this.props.onShowDetail(identity.address, event),
2730
}, [
2831

@@ -70,7 +73,7 @@ AccountListItem.prototype.render = function () {
7073
)
7174
}
7275

73-
AccountListItem.prototype.pendingOrNot = function () {
76+
NewComponent.prototype.pendingOrNot = function () {
7477
const pending = this.props.pending
7578
if (pending.length === 0) return null
7679
return h('.pending-dot', pending.length)

0 commit comments

Comments
 (0)