breakout idmgmt

This commit is contained in:
kumavis 2016-01-16 16:22:54 -08:00
parent 7347a66eb0
commit 722acdad35
3 changed files with 251 additions and 226 deletions

View File

@ -1,17 +1,25 @@
const Dnode = require('dnode')
const KeyStore = require('eth-lightwallet').keystore
const PortStream = require('./lib/port-stream.js')
const MetaMaskProvider = require('./lib/metamask-provider')
const IdentityManager = require('./lib/idmgmt')
console.log('ready to roll')
var wallet = IdentityManager()
// setup provider
var zeroClient = MetaMaskProvider({
rpcUrl: 'https://testrpc.metamask.io/',
getAccounts: getAccounts,
sendTransaction: confirmTransaction,
rpcUrl: 'https://rawtestrpc.metamask.io/',
getAccounts: wallet.getAccounts.bind(wallet),
sendTransaction: wallet.confirmTransaction.bind(wallet),
})
wallet.setProvider(zeroClient)
zeroClient.on('block', function(block){
wallet.newBlock(block)
})
// setup messaging
chrome.runtime.onConnect.addListener(connectRemote)
function connectRemote(remotePort){
@ -27,13 +35,7 @@ function connectRemote(remotePort){
function handleInternalCommunication(remotePort){
var duplex = new PortStream(remotePort)
var remote = Dnode({
getState: getState,
setLocked: setLocked,
submitPassword: submitPassword,
setSelectedAddress: setSelectedAddress,
signTransaction: signTransaction,
})
var remote = Dnode(wallet)
duplex.pipe(remote).pipe(duplex)
}
@ -51,159 +53,6 @@ function onRpcRequest(remotePort, payload){
})
}
// id mgmt
var selectedAddress = null
function getState(cb){
var result = _getState()
cb(null, result)
}
function _getState(cb){
var unlocked = isUnlocked()
var result = {
isUnlocked: unlocked,
identities: unlocked ? getIdentities() : {},
selectedAddress: selectedAddress,
}
return result
}
function isUnlocked(){
var password = window.sessionStorage['password']
var result = Boolean(password)
return result
}
function setLocked(){
delete window.sessionStorage['password']
}
function setSelectedAddress(address, cb){
selectedAddress = address
cb(null, _getState())
}
function submitPassword(password, cb){
console.log('submitPassword:', password)
tryPassword(password, function(err){
if (err) console.log('bad password:', password, err)
if (err) return cb(err)
console.log('good password:', password)
window.sessionStorage['password'] = password
cb(null, _getState())
})
}
function getAccounts(cb){
var identities = getIdentities()
var result = selectedAddress ? [selectedAddress] : []
cb(null, result)
}
function getIdentities(cb){
var keyStore = getKeyStore()
var addresses = keyStore.getAddresses()
var accountStore = {}
addresses.map(function(address){
address = '0x'+address
accountStore[address] = {
name: 'Wally',
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
address: address,
balance: 10.005,
txCount: 16,
}
})
return accountStore
}
function tryPassword(password, cb){
var keyStore = getKeyStore(password)
var address = keyStore.getAddresses()[0]
if (!address) return cb(new Error('KeyStore - No address to check.'))
var hdPathString = keyStore.defaultHdPathString
try {
var encKey = keyStore.generateEncKey(password)
var encPrivKey = keyStore.ksData[hdPathString].encPrivKeys[address]
var privKey = KeyStore._decryptKey(encPrivKey, encKey)
var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
} catch (err) {
return cb(err)
}
if (addrFromPrivKey !== address) return cb(new Error('KeyStore - Decrypting private key failed!'))
cb()
}
function confirmTransaction(txParams, cb){
console.log('confirmTransaction:', txParams)
}
function signTransaction(txParams, cb){
console.log('signTransaction:', txParams)
}
var keyStore = null
function getKeyStore(password){
if (keyStore) return keyStore
password = password || getPassword()
var serializedKeystore = window.localStorage['lightwallet']
// returning user
if (serializedKeystore) {
keyStore = KeyStore.deserialize(serializedKeystore)
// first time here
} else {
var defaultPassword = 'test'
console.log('creating new keystore with default password:', defaultPassword)
var secretSeed = KeyStore.generateRandomSeed()
keyStore = new KeyStore(secretSeed, defaultPassword)
keyStore.generateNewAddress(defaultPassword, 3)
saveKeystore()
}
keyStore.passwordProvider = unlockKeystore
return keyStore
}
function saveKeystore(){
window.localStorage['lightwallet'] = keyStore.serialize()
}
function getPassword(){
var password = window.sessionStorage['password']
if (!password) throw new Error('No password found...')
}
function unlockKeystore(cb){
var password = getPassword()
console.warn('unlocking keystore...')
cb(null, password)
}
// // load from storage
// chrome.storage.sync.get(function(data){
// for (var key in data) {
// var serialized = data[key]
// var tx = deserializeTx(serialized)
// var hash = simpleHash(serialized)
// unsignedTxs[hash] = tx
// }
// updateBadge()
// })
// // listen to storage changes
// chrome.storage.onChanged.addListener(function(changes, namespace) {
// for (key in changes) {
// var storageChange = changes[key]
// if (storageChange.oldValue && !storageChange.newValue) {
// // was removed
// removeTransaction(storageChange.oldValue)
// } else if (!storageChange.oldValue && storageChange.newValue) {
// // was added
// addTransaction(deserializeTx(storageChange.newValue))
// }
// }
// })
// setup badge text
// updateBadge()
@ -231,60 +80,3 @@ function unlockKeystore(cb){
// }
// }
// function addTransaction(tx){
// var serialized = serializeTx(tx)
// var hash = simpleHash(serialized)
// unsignedTxs[hash] = tx
// var data = {}
// data[hash] = serialized
// chrome.storage.sync.set(data)
// // trigger ui changes
// updateBadge()
// }
// function removeTransaction(serialized){
// var hash = simpleHash(serialized)
// delete unsignedTxs[hash]
// var data = {}
// data[hash] = undefined
// chrome.storage.sync.set(data)
// // trigger ui changes
// updateBadge()
// }
// function exportUnsignedTxs(remote){
// console.log('exporting txs!', unsignedTxs)
// var data = {
// type: 'importUnsignedTxs',
// payload: getValues(unsignedTxs),
// }
// remote.postMessage(data)
// }
// function simpleHash(input) {
// var hash = 0, i, chr, len
// if (input.length == 0) return hash
// for (i = 0, len = input.length; i < len; i++) {
// chr = input.charCodeAt(i)
// hash = ((hash << 5) - hash) + chr
// hash |= 0 // Convert to 32bit integer
// }
// return hash
// }
// function serializeTx(tx){
// return JSON.stringify(tx)
// }
// function deserializeTx(tx){
// return JSON.parse(tx)
// }
// function getValues(obj){
// var output = []
// for (var key in obj) {
// output.push(obj[key])
// }
// return output
// }

233
app/scripts/lib/idmgmt.js Normal file
View File

@ -0,0 +1,233 @@
const EventEmitter = require('events').EventEmitter
const async = require('async')
const KeyStore = require('eth-lightwallet').keystore
const createPayload = require('web3-provider-engine/util/create-payload')
var selectedAddress = null
var identities = {}
module.exports = IdentityManager
var provider = null
var pubsub = new EventEmitter()
function IdentityManager(opts){
opts = opts || {}
providerEngine = opts.providerEngine
return {
// plugin popup
getState: getState,
subscribe: subscribe,
submitPassword: submitPassword,
setSelectedAddress: setSelectedAddress,
signTransaction: signTransaction,
setLocked: setLocked,
// eth rpc
getAccounts: getAccounts,
confirmTransaction: confirmTransaction,
// etc
newBlock: newBlock,
setProvider: setProvider,
}
}
function setProvider(_provider){
provider = _provider
}
function newBlock(block){
pubsub.emit('block', block)
updateIdentities()
}
// on new block, update our accounts (but only if we're unlocked)
function subscribe(cb){
pubsub.on('block', sendUpdateState)
function sendUpdateState(){
if (!isUnlocked()) return
updateIdentities(function(){
var state = _getState()
cb(state)
})
}
}
function getState(cb){
var result = _getState()
cb(null, result)
}
function _getState(cb){
var unlocked = isUnlocked()
var result = {
isUnlocked: unlocked,
identities: unlocked ? getIdentities() : {},
selectedAddress: selectedAddress,
}
return result
}
function isUnlocked(){
var password = window.sessionStorage['password']
var result = Boolean(password)
return result
}
function setLocked(){
delete window.sessionStorage['password']
}
function setSelectedAddress(address, cb){
selectedAddress = address
cb(null, _getState())
}
function submitPassword(password, cb){
console.log('submitPassword:', password)
tryPassword(password, function(err){
if (err) console.log('bad password:', password, err)
if (err) return cb(err)
console.log('good password:', password)
window.sessionStorage['password'] = password
// load identities before returning...
loadIdentities()
var state = _getState()
cb(null, state)
// trigger an update but dont wait for it
updateIdentities()
})
}
// get the current selected address
function getAccounts(cb){
var result = selectedAddress ? [selectedAddress] : []
console.log('getAccounts:', result)
cb(null, result)
}
function getIdentities(){
return identities
}
// load identities from keyStore
function loadIdentities(){
if (!isUnlocked()) throw new Error('not unlocked')
var keyStore = getKeyStore()
var addresses = keyStore.getAddresses().map(function(address){ return '0x'+address })
addresses.forEach(function(address){
var identity = {
name: 'Wally',
img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
address: address,
balance: null,
txCount: null,
}
identities[address] = identity
})
}
// foreach in identities, update balance + nonce
function updateIdentities(cb){
cb = cb || function(){}
if (!isUnlocked()) return cb(new Error('Not unlocked.'))
var addresses = Object.keys(identities)
async.map(addresses, updateIdentity, cb)
}
// gets latest info from the network for the identity
function updateIdentity(address, cb){
async.parallel([
getAccountBalance.bind(null, address),
getTxCount.bind(null, address),
], function(err, result){
if (err) return cb(err)
var identity = identities[address]
identity.balance = result[0]
identity.txCount = result[1]
cb()
})
}
function getTxCount(address, cb){
provider.sendAsync(createPayload({
method: 'eth_getTransactionCount',
params: [address],
}), function(err, res){
if (err) return cb(err)
if (res.error) return cb(res.error)
cb(null, res.result)
})
}
function getAccountBalance(address, cb){
provider.sendAsync(createPayload({
method: 'eth_getBalance',
params: [address],
}), function(err, res){
if (err) return cb(err)
if (res.error) return cb(res.error)
cb(null, res.result)
})
}
function tryPassword(password, cb){
var keyStore = getKeyStore(password)
var address = keyStore.getAddresses()[0]
if (!address) return cb(new Error('KeyStore - No address to check.'))
var hdPathString = keyStore.defaultHdPathString
try {
var encKey = keyStore.generateEncKey(password)
var encPrivKey = keyStore.ksData[hdPathString].encPrivKeys[address]
var privKey = KeyStore._decryptKey(encPrivKey, encKey)
var addrFromPrivKey = KeyStore._computeAddressFromPrivKey(privKey)
} catch (err) {
return cb(err)
}
if (addrFromPrivKey !== address) return cb(new Error('KeyStore - Decrypting private key failed!'))
cb()
}
function confirmTransaction(txParams, cb){
console.log('confirmTransaction:', txParams)
}
function signTransaction(txParams, cb){
console.log('signTransaction:', txParams)
}
var keyStore = null
function getKeyStore(password){
if (keyStore) return keyStore
password = password || getPassword()
var serializedKeystore = window.localStorage['lightwallet']
// returning user
if (serializedKeystore) {
keyStore = KeyStore.deserialize(serializedKeystore)
// first time here
} else {
var defaultPassword = 'test'
console.log('creating new keystore with default password:', defaultPassword)
var secretSeed = KeyStore.generateRandomSeed()
keyStore = new KeyStore(secretSeed, defaultPassword)
keyStore.generateNewAddress(defaultPassword, 3)
saveKeystore()
}
keyStore.passwordProvider = unlockKeystore
return keyStore
}
function saveKeystore(){
window.localStorage['lightwallet'] = keyStore.serialize()
}
function getPassword(){
var password = window.sessionStorage['password']
if (!password) throw new Error('No password found...')
}
function unlockKeystore(cb){
var password = getPassword()
console.warn('unlocking keystore...')
cb(null, password)
}

View File

@ -42,11 +42,11 @@ function metamaskProvider(opts){
}))
// log new blocks
// engine.on('block', function(block){
// console.log('================================')
// console.log('BLOCK CHANGED:', '#'+block.number.toString('hex'), '0x'+block.hash.toString('hex'))
// console.log('================================')
// })
engine.on('block', function(block){
// console.log('================================')
console.log('BLOCK CHANGED:', '#'+block.number.toString('hex'), '0x'+block.hash.toString('hex'))
// console.log('================================')
})
// start polling for blocks
engine.start()