mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 01:39:44 +01:00
breakout idmgmt
This commit is contained in:
parent
7347a66eb0
commit
722acdad35
@ -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
233
app/scripts/lib/idmgmt.js
Normal 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)
|
||||
}
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user