aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/lib/idStore.js
diff options
context:
space:
mode:
authorkumavis <aaron@kumavis.me>2016-02-11 09:44:46 +0800
committerkumavis <aaron@kumavis.me>2016-02-11 09:44:46 +0800
commitf8c5b903209fd5d0dd991a2455604a98b1b30b48 (patch)
tree25b6232be281eff4bbe53f966ce629c76fa97612 /app/scripts/lib/idStore.js
parent31c9bf3c263f6932eb5e4484c64f5dfc6de72e7f (diff)
downloadtangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar.gz
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar.bz2
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar.lz
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar.xz
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.tar.zst
tangerine-wallet-browser-f8c5b903209fd5d0dd991a2455604a98b1b30b48.zip
idmgmt - refactor
Diffstat (limited to 'app/scripts/lib/idStore.js')
-rw-r--r--app/scripts/lib/idStore.js263
1 files changed, 263 insertions, 0 deletions
diff --git a/app/scripts/lib/idStore.js b/app/scripts/lib/idStore.js
new file mode 100644
index 000000000..0dfc4deed
--- /dev/null
+++ b/app/scripts/lib/idStore.js
@@ -0,0 +1,263 @@
+const EventEmitter = require('events').EventEmitter
+const inherits = require('util').inherits
+const Transaction = require('ethereumjs-tx')
+const KeyStore = require('eth-lightwallet').keystore
+const async = require('async')
+const clone = require('clone')
+const extend = require('xtend')
+const createId = require('web3-provider-engine/util/random-id')
+
+
+module.exports = IdentityStore
+
+
+inherits(IdentityStore, EventEmitter)
+function IdentityStore(ethStore) {
+ const self = this
+ EventEmitter.call(self)
+
+ // we just use the ethStore to auto-add accounts
+ self._ethStore = ethStore
+
+ self._currentState = {
+ selectedAddress: null,
+ identities: {},
+ unconfTxs: {},
+ }
+ // not part of serilized metamask state - only kept in memory
+ self._unconfTxCbs = {}
+}
+
+//
+// public
+//
+
+IdentityStore.prototype.setStore = function(store){
+ const self = this
+ self._ethStore = store
+}
+
+IdentityStore.prototype.getState = function(){
+ const self = this
+ return clone(extend(self._currentState, {
+ isUnlocked: self._isUnlocked(),
+ }))
+}
+
+IdentityStore.prototype.getSelectedAddress = function(){
+ const self = this
+ return self._currentState.selectedAddress
+}
+
+IdentityStore.prototype.setSelectedAddress = function(address){
+ const self = this
+ self._currentState.selectedAddress = address
+ self._didUpdate()
+}
+
+IdentityStore.prototype.addUnconfirmedTransaction = function(txParams, cb){
+ var self = this
+
+ var time = (new Date()).getTime()
+ var txId = createId()
+ self._currentState.unconfTxs[txId] = {
+ id: txId,
+ txParams: txParams,
+ time: time,
+ status: 'unconfirmed',
+ }
+ console.log('addUnconfirmedTransaction:', txParams)
+
+ // temp - just sign the tx
+ // otherwise we need to keep the cb around
+ // signTransaction(txId, cb)
+ self._unconfTxCbs[txId] = cb
+
+ // signal update
+ self._didUpdate()
+}
+
+
+
+IdentityStore.prototype.setLocked = function(){
+ const self = this
+ delete self._keyStore
+ delete window.sessionStorage['password']
+}
+
+IdentityStore.prototype.submitPassword = function(password, cb){
+ const self = this
+ console.log('submitPassword:', password)
+ self._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...
+ self._loadIdentities()
+ cb()
+ })
+}
+
+IdentityStore.prototype.signTransaction = function(password, txId, cb){
+ const self = this
+
+ var txData = self._currentState.unconfTxs[txId]
+ var txParams = txData.txParams
+
+ self._signTransaction(txParams, function(err, rawTx, txHash){
+ if (err) {
+ throw err
+ txData.status = 'error'
+ txData.error = err
+ self._didUpdate()
+ return
+ }
+
+ txData.hash = txHash
+ txData.status = 'pending'
+
+ // for now just remove it
+ delete self._currentState.unconfTxs[txData.id]
+
+ // rpc callback
+ var txSigCb = self._unconfTxCbs[txId] || noop
+ txSigCb(null, rawTx)
+
+ // confirm tx callback
+ cb()
+
+ self._didUpdate()
+ })
+}
+
+//
+// private
+//
+
+// internal - actually signs the tx
+IdentityStore.prototype._signTransaction = function(txParams, cb){
+ const self = this
+ 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 password = self._getPassword()
+ var serializedTx = self._keyStore.signTx(tx.serialize(), password, self._currentState.selectedAddress)
+
+ // // 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, tx.hash())
+ } catch (err) {
+ cb(err)
+ }
+}
+
+IdentityStore.prototype._didUpdate = function(){
+ const self = this
+ self.emit('update', self.getState())
+}
+
+IdentityStore.prototype._isUnlocked = function(){
+ const self = this
+ // var password = window.sessionStorage['password']
+ // var result = Boolean(password)
+ var result = Boolean(self._keyStore)
+ return result
+}
+
+// load identities from keyStore
+IdentityStore.prototype._loadIdentities = function(){
+ const self = this
+ if (!self._isUnlocked()) throw new Error('not unlocked')
+ // get addresses and normalize address hexString
+ var addresses = self._keyStore.getAddresses().map(function(address){ return '0x'+address })
+ addresses.forEach(function(address){
+ // add to ethStore
+ self._ethStore.addAccount(address)
+ // add to identities
+ var identity = {
+ name: 'Wally',
+ img: 'QmW6hcwYzXrNkuHrpvo58YeZvbZxUddv69ATSHY3BHpPdd',
+ address: address,
+ }
+ self._currentState.identities[address] = identity
+ })
+ self._didUpdate()
+}
+
+//
+// keyStore managment - unlocking + deserialization
+//
+
+IdentityStore.prototype._tryPassword = function(password, cb){
+ const self = this
+ var keyStore = self._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()
+}
+
+IdentityStore.prototype._getKeyStore = function(password){
+ const self = this
+ var keyStore = null
+ var serializedKeystore = window.localStorage['lightwallet']
+ // returning user
+ if (serializedKeystore) {
+ keyStore = KeyStore.deserialize(serializedKeystore)
+ // first time here
+ } else {
+ console.log('creating new keystore with password:', password)
+ var secretSeed = KeyStore.generateRandomSeed()
+ keyStore = new KeyStore(secretSeed, password)
+ keyStore.generateNewAddress(password, 3)
+ self._saveKeystore(keyStore)
+ }
+ keyStore.passwordProvider = function getPassword(cb){
+ cb(null, self._getPassword())
+ }
+ self._keyStore = keyStore
+ return keyStore
+}
+
+IdentityStore.prototype._saveKeystore = function(keyStore){
+ const self = this
+ window.localStorage['lightwallet'] = keyStore.serialize()
+}
+
+IdentityStore.prototype._getPassword = function(){
+ const self = this
+ var password = window.sessionStorage['password']
+ console.warn('using password from memory:', password)
+ return password
+}
+
+// util
+
+function noop(){} \ No newline at end of file