1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-01 21:57:06 +01:00
metamask-extension/app/scripts/lib/idmgmt.js

280 lines
7.6 KiB
JavaScript
Raw Normal View History

2016-01-17 10:27:25 +01:00
const inherits = require('util').inherits
2016-01-17 01:22:54 +01:00
const EventEmitter = require('events').EventEmitter
const async = require('async')
const KeyStore = require('eth-lightwallet').keystore
const createPayload = require('web3-provider-engine/util/create-payload')
2016-01-18 08:31:49 +01:00
const Transaction = require('ethereumjs-tx')
2016-01-17 01:22:54 +01:00
module.exports = IdentityManager
2016-01-18 08:31:49 +01:00
var selectedAddress = null
var identities = {}
var unconfTxs = {}
2016-01-17 01:22:54 +01:00
var provider = null
2016-01-18 08:31:49 +01:00
var defaultPassword = 'test'
2016-01-17 01:22:54 +01:00
2016-01-17 08:38:40 +01:00
2016-01-17 10:27:25 +01:00
inherits(IdentityManager, EventEmitter)
2016-01-17 01:22:54 +01:00
function IdentityManager(opts){
2016-01-17 10:27:25 +01:00
const self = this
self.on('block', function(){
self.updateIdentities()
})
2016-01-17 01:22:54 +01:00
}
2016-01-17 08:38:40 +01:00
// plugin popup
IdentityManager.prototype.getState = getState
IdentityManager.prototype.submitPassword = submitPassword
IdentityManager.prototype.setSelectedAddress = setSelectedAddress
IdentityManager.prototype.signTransaction = signTransaction
IdentityManager.prototype.setLocked = setLocked
// eth rpc
IdentityManager.prototype.getAccounts = getAccounts
2016-01-18 08:31:49 +01:00
IdentityManager.prototype.addUnconfirmedTransaction = addUnconfirmedTransaction
2016-01-17 08:38:40 +01:00
// etc
IdentityManager.prototype.newBlock = newBlock
IdentityManager.prototype.setProvider = setProvider
2016-01-17 01:22:54 +01:00
function setProvider(_provider){
provider = _provider
}
function newBlock(block){
2016-01-17 10:27:25 +01:00
var self = this
self.emit('block', block)
2016-01-17 01:22:54 +01:00
}
function getState(cb){
var result = _getState()
cb(null, result)
}
function _getState(cb){
var unlocked = isUnlocked()
var result = {
isUnlocked: unlocked,
identities: unlocked ? getIdentities() : {},
2016-01-18 08:31:49 +01:00
unconfTxs: unlocked ? unconfTxs() : {},
2016-01-17 01:22:54 +01:00
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){
2016-01-17 10:27:25 +01:00
const self = this
2016-01-17 01:22:54 +01:00
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...
2016-01-17 10:27:25 +01:00
self.loadIdentities()
2016-01-17 01:22:54 +01:00
var state = _getState()
cb(null, state)
// trigger an update but dont wait for it
2016-01-17 10:27:25 +01:00
console.log(self)
self.updateIdentities()
2016-01-17 01:22:54 +01:00
})
}
// 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
2016-01-17 10:27:25 +01:00
IdentityManager.prototype.loadIdentities = function(){
const self = this
2016-01-17 01:22:54 +01:00
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
})
2016-01-17 10:27:25 +01:00
self.emit('update', _getState())
2016-01-17 01:22:54 +01:00
}
// foreach in identities, update balance + nonce
2016-01-17 10:27:25 +01:00
IdentityManager.prototype.updateIdentities = function(cb){
var self = this
2016-01-17 01:22:54 +01:00
cb = cb || function(){}
if (!isUnlocked()) return cb(new Error('Not unlocked.'))
var addresses = Object.keys(identities)
2016-01-17 10:27:25 +01:00
async.map(addresses, self.updateIdentity.bind(self), cb)
2016-01-17 01:22:54 +01:00
}
// gets latest info from the network for the identity
2016-01-17 10:27:25 +01:00
IdentityManager.prototype.updateIdentity = function(address, cb){
var self = this
2016-01-17 01:22:54 +01:00
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]
2016-01-17 10:27:25 +01:00
self.emit('update', _getState())
2016-01-17 01:22:54 +01:00
cb()
})
}
function getTxCount(address, cb){
provider.sendAsync(createPayload({
method: 'eth_getTransactionCount',
2016-01-17 08:38:40 +01:00
// we actually want the pending txCount
// but pending is broken in provider-engine
// https://github.com/MetaMask/provider-engine/issues/11
// params: [address, 'pending'],
params: [address, 'latest'],
2016-01-17 01:22:54 +01:00
}), 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',
2016-01-17 08:38:40 +01:00
params: [address, 'latest'],
2016-01-17 01:22:54 +01:00
}), 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()
}
2016-01-18 08:31:49 +01:00
function addUnconfirmedTransaction(txParams, cb){
var time = (new Date()).getTime()
var id = time
unconfTxs[id] = {
txParams: txParams,
time: time,
}
console.log('addUnconfirmedTransaction:', txParams)
// temp - just sign the tx
// otherwise we need to keep the cb around
signTransaction(id, cb)
2016-01-17 01:22:54 +01:00
}
function signTransaction(txParams, cb){
console.log('signTransaction:', txParams)
2016-01-18 08:31:49 +01:00
try {
// console.log('signing tx:', txParams)
var tx = new Transaction({
nonce: txParams.nonce,
to: txParams.to,
value: txParams.value,
data: txParams.input,
gasPrice: txParams.gasPrice,
gasLimit: txParams.gas,
})
var keyStore = getKeyStore()
var serializedTx = keystore.signTx(tx.serialize(), defaultPassword, selectedAddress)
tx.sign(privateKey)
// // deserialize and dump values to confirm configuration
// var verifyTx = new Transaction(tx.serialize())
// console.log('signed transaction:', {
// to: '0x'+verifyTx.to.toString('hex'),
// from: '0x'+verifyTx.from.toString('hex'),
// nonce: '0x'+verifyTx.nonce.toString('hex'),
// value: (ethUtil.bufferToInt(verifyTx.value)/1e18)+' ether',
// data: '0x'+verifyTx.data.toString('hex'),
// gasPrice: '0x'+verifyTx.gasPrice.toString('hex'),
// gasLimit: '0x'+verifyTx.gasLimit.toString('hex'),
// })
cb(null, serializedTx)
} catch (err) {
cb(err)
}
2016-01-17 01:22:54 +01:00
}
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 {
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)
}