1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Implemented BIP44 compliance test.

Also added the hdPath that Christian had told me to our calls to the LightWallet, but this does not seem to have made us generate the same accounts as `testrpc` yet.
This commit is contained in:
Dan Finlay 2016-03-25 14:51:19 -07:00
parent 37fd45e5b7
commit a2c7ccafa6
4 changed files with 84 additions and 63 deletions

View File

@ -53,18 +53,17 @@ IdentityStore.prototype.createNewVault = function(password, entropy, cb){
} }
IdentityStore.prototype.recoverFromSeed = function(password, seed, cb){ IdentityStore.prototype.recoverFromSeed = function(password, seed, cb){
const self = this this._createIdmgmt(password, seed, null, (err) => {
self._createIdmgmt(password, seed, null, function(err){
if (err) return cb(err) if (err) return cb(err)
self._loadIdentities()
self._didUpdate() this._loadIdentities()
this._didUpdate()
cb() cb()
}) })
} }
IdentityStore.prototype.setStore = function(store){ IdentityStore.prototype.setStore = function(store){
const self = this this._ethStore = store
self._ethStore = store
} }
IdentityStore.prototype.clearSeedWordCache = function(cb) { IdentityStore.prototype.clearSeedWordCache = function(cb) {
@ -73,46 +72,40 @@ IdentityStore.prototype.clearSeedWordCache = function(cb) {
} }
IdentityStore.prototype.getState = function(){ IdentityStore.prototype.getState = function(){
const self = this
const cachedSeeds = window.localStorage['seedWords'] const cachedSeeds = window.localStorage['seedWords']
return clone(extend(self._currentState, { return clone(extend(this._currentState, {
isInitialized: !!window.localStorage['lightwallet'] && !cachedSeeds, isInitialized: !!window.localStorage['lightwallet'] && !cachedSeeds,
isUnlocked: self._isUnlocked(), isUnlocked: this._isUnlocked(),
seedWords: cachedSeeds, seedWords: cachedSeeds,
})) }))
} }
IdentityStore.prototype.getSelectedAddress = function(){ IdentityStore.prototype.getSelectedAddress = function(){
const self = this return this._currentState.selectedAddress
return self._currentState.selectedAddress
} }
IdentityStore.prototype.setSelectedAddress = function(address){ IdentityStore.prototype.setSelectedAddress = function(address){
const self = this this._currentState.selectedAddress = address
self._currentState.selectedAddress = address this._didUpdate()
self._didUpdate()
} }
IdentityStore.prototype.setLocked = function(cb){ IdentityStore.prototype.setLocked = function(cb){
const self = this delete this._keyStore
delete self._keyStore delete this._idmgmt
delete self._idmgmt
cb() cb()
} }
IdentityStore.prototype.submitPassword = function(password, cb){ IdentityStore.prototype.submitPassword = function(password, cb){
const self = this this._tryPassword(password, (err) => {
self._tryPassword(password, function(err){
if (err) return cb(err) if (err) return cb(err)
// load identities before returning... // load identities before returning...
self._loadIdentities() this._loadIdentities()
cb() cb()
}) })
} }
// comes from dapp via zero-client hooked-wallet provider // comes from dapp via zero-client hooked-wallet provider
IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
var self = this
// create txData obj with parameters and meta data // create txData obj with parameters and meta data
var time = (new Date()).getTime() var time = (new Date()).getTime()
@ -123,55 +116,51 @@ IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
time: time, time: time,
status: 'unconfirmed', status: 'unconfirmed',
} }
self._currentState.unconfTxs[txId] = txData this._currentState.unconfTxs[txId] = txData
console.log('addUnconfirmedTransaction:', txData)
// keep the cb around for after approval (requires user interaction) // keep the cb around for after approval (requires user interaction)
self._unconfTxCbs[txId] = cb this._unconfTxCbs[txId] = cb
// signal update // signal update
self._didUpdate() this._didUpdate()
return txId return txId
} }
// comes from metamask ui // comes from metamask ui
IdentityStore.prototype.approveTransaction = function(txId, cb){ IdentityStore.prototype.approveTransaction = function(txId, cb){
const self = this var txData = this._currentState.unconfTxs[txId]
var txData = self._currentState.unconfTxs[txId]
var txParams = txData.txParams var txParams = txData.txParams
var approvalCb = self._unconfTxCbs[txId] || noop var approvalCb = this._unconfTxCbs[txId] || noop
// accept tx // accept tx
cb() cb()
approvalCb(null, true) approvalCb(null, true)
// clean up // clean up
delete self._currentState.unconfTxs[txId] delete this._currentState.unconfTxs[txId]
delete self._unconfTxCbs[txId] delete this._unconfTxCbs[txId]
self._didUpdate() this._didUpdate()
} }
// comes from metamask ui // comes from metamask ui
IdentityStore.prototype.cancelTransaction = function(txId){ IdentityStore.prototype.cancelTransaction = function(txId){
const self = this var txData = this._currentState.unconfTxs[txId]
var approvalCb = this._unconfTxCbs[txId] || noop
var txData = self._currentState.unconfTxs[txId]
var approvalCb = self._unconfTxCbs[txId] || noop
// reject tx // reject tx
approvalCb(null, false) approvalCb(null, false)
// clean up // clean up
delete self._currentState.unconfTxs[txId] delete this._currentState.unconfTxs[txId]
delete self._unconfTxCbs[txId] delete this._unconfTxCbs[txId]
self._didUpdate() this._didUpdate()
} }
// performs the actual signing, no autofill of params // performs the actual signing, no autofill of params
IdentityStore.prototype.signTransaction = function(txParams, cb){ IdentityStore.prototype.signTransaction = function(txParams, cb){
const self = this
try { try {
console.log('signing tx...', txParams) console.log('signing tx...', txParams)
var rawTx = self._idmgmt.signTx(txParams) var rawTx = this._idmgmt.signTx(txParams)
cb(null, rawTx) cb(null, rawTx)
} catch (err) { } catch (err) {
cb(err) cb(err)
@ -183,13 +172,11 @@ IdentityStore.prototype.signTransaction = function(txParams, cb){
// //
IdentityStore.prototype._didUpdate = function(){ IdentityStore.prototype._didUpdate = function(){
const self = this this.emit('update', this.getState())
self.emit('update', self.getState())
} }
IdentityStore.prototype._isUnlocked = function(){ IdentityStore.prototype._isUnlocked = function(){
const self = this var result = Boolean(this._keyStore) && Boolean(this._idmgmt)
var result = Boolean(self._keyStore) && Boolean(self._idmgmt)
return result return result
} }
@ -199,22 +186,21 @@ IdentityStore.prototype._cacheSeedWordsUntilConfirmed = function(seedWords) {
// load identities from keyStoreet // load identities from keyStoreet
IdentityStore.prototype._loadIdentities = function(){ IdentityStore.prototype._loadIdentities = function(){
const self = this if (!this._isUnlocked()) throw new Error('not unlocked')
if (!self._isUnlocked()) throw new Error('not unlocked')
// get addresses and normalize address hexString // get addresses and normalize address hexString
var addresses = self._keyStore.getAddresses(this.hdPathString).map(function(address){ return '0x'+address }) var addresses = this._keyStore.getAddresses(this.hdPathString).map((address) => { return '0x'+address })
addresses.forEach(function(address){ addresses.forEach((address) => {
// // add to ethStore // // add to ethStore
self._ethStore.addAccount(address) this._ethStore.addAccount(address)
// add to identities // add to identities
var identity = { var identity = {
name: 'Wally', name: 'Wally',
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd', img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
address: address, address: address,
} }
self._currentState.identities[address] = identity this._currentState.identities[address] = identity
}) })
self._didUpdate() this._didUpdate()
} }
// //
@ -222,8 +208,7 @@ IdentityStore.prototype._loadIdentities = function(){
// //
IdentityStore.prototype._tryPassword = function(password, cb){ IdentityStore.prototype._tryPassword = function(password, cb){
const self = this this._createIdmgmt(password, null, null, cb)
self._createIdmgmt(password, null, null, cb)
} }
IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){
@ -233,7 +218,7 @@ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){
var serializedKeystore = window.localStorage['lightwallet'] var serializedKeystore = window.localStorage['lightwallet']
if (seed) { if (seed) {
this._restoreFromSeed(keyStore, seed, derivedKey) keyStore = this._restoreFromSeed(seed, derivedKey)
// returning user, recovering from localStorage // returning user, recovering from localStorage
} else if (serializedKeystore) { } else if (serializedKeystore) {
@ -256,11 +241,12 @@ IdentityStore.prototype._createIdmgmt = function(password, seed, entropy, cb){
}) })
} }
IdentityStore.prototype._restoreFromSeed = function(keyStore, seed, derivedKey) { IdentityStore.prototype._restoreFromSeed = function(seed, derivedKey) {
keyStore = new LightwalletKeyStore(seed, derivedKey) var keyStore = new LightwalletKeyStore(seed, derivedKey, this.hdPathString)
keyStore.generateNewAddress(derivedKey, 3, hdPathString) keyStore.generateNewAddress(derivedKey, 3, this.hdPathString)
window.localStorage['lightwallet'] = keyStore.serialize() window.localStorage['lightwallet'] = keyStore.serialize()
console.log('restored from seed. saved to keystore localStorage') console.log('restored from seed. saved to keystore localStorage')
return keyStore
} }
IdentityStore.prototype._loadFromLocalStorage = function(serializedKeystore, derivedKey) { IdentityStore.prototype._loadFromLocalStorage = function(serializedKeystore, derivedKey) {

View File

@ -5,8 +5,8 @@
"private": true, "private": true,
"scripts": { "scripts": {
"start": "gulp dev", "start": "gulp dev",
"test": "mocha --compilers js:babel-register", "test": "mocha --compilers js:babel-register --recursive",
"watch": "mocha watch --compilers js:babel-register" "watch": "mocha watch --compilers js:babel-register --recursive"
}, },
"dependencies": { "dependencies": {
"async": "^1.5.2", "async": "^1.5.2",
@ -44,6 +44,8 @@
"lodash.assign": "^4.0.6", "lodash.assign": "^4.0.6",
"mocha": "^2.4.5", "mocha": "^2.4.5",
"mocha-jsdom": "^1.1.0", "mocha-jsdom": "^1.1.0",
"mocha-sinon": "^1.1.5",
"sinon": "^1.17.3",
"tape": "^4.5.1", "tape": "^4.5.1",
"vinyl-buffer": "^1.0.0", "vinyl-buffer": "^1.0.0",
"vinyl-source-stream": "^1.1.0", "vinyl-source-stream": "^1.1.0",

4
test/helper.js Normal file
View File

@ -0,0 +1,4 @@
require('mocha-sinon')()
var jsdom = require('mocha-jsdom')
jsdom()

View File

@ -1,7 +1,5 @@
var assert = require('assert') var assert = require('assert')
var IdentityStore = require('../app/scripts/lib/idStore') var IdentityStore = require('../../app/scripts/lib/idStore')
var jsdom = require('mocha-jsdom')
jsdom()
describe('IdentityStore', function() { describe('IdentityStore', function() {
@ -38,15 +36,46 @@ describe('IdentityStore', function() {
}) })
}) })
it('should return the expected keystore', function () { it('should return the expected keystore', function (done) {
idStore.recoverFromSeed(password, seedWords, (err) => { idStore.recoverFromSeed(password, seedWords, (err) => {
assert.ifError(err) assert.ifError(err)
let newKeystore = idStore._idmgmt.keyStore let newKeystore = idStore._idmgmt.keyStore
assert.equal(newKeystore, originalKeystore) assert.equal(newKeystore, originalKeystore)
done()
}) })
}) })
}) })
}) })
describe('#recoverFromSeed BIP44 compliance', function() {
let seedWords = 'picnic injury awful upper eagle junk alert toss flower renew silly vague'
let firstAccount = '0xaceef0221414801dde7f732196b1c9d8ea60b637'
let password = 'secret!'
let accounts = []
let idStore
before(function() {
window.localStorage = {} // Hacking localStorage support into JSDom
idStore = new IdentityStore({
addAccount(acct) {
console.log(`pushing account ${acct}`)
accounts.push(acct)
},
})
})
it('should return the expected first account', function (done) {
idStore.recoverFromSeed(password, seedWords, (err) => {
assert.ifError(err)
let newKeystore = idStore._idmgmt.keyStore
assert.equal(accounts[0], firstAccount)
done()
})
})
})
}) })