Merge pull request #323 from MetaMask/RefactorBackground
Refactored background.js controller apart from chrome + transportfeature/default_network_editable
commit
52518a5efc
@ -1,3 +0,0 @@ |
|||||||
var ConfigManager = require('./config-manager') |
|
||||||
|
|
||||||
module.exports = new ConfigManager() |
|
@ -0,0 +1,257 @@ |
|||||||
|
const extend = require('xtend') |
||||||
|
const EthStore = require('eth-store') |
||||||
|
const MetaMaskProvider = require('web3-provider-engine/zero.js') |
||||||
|
const IdentityStore = require('./lib/idStore') |
||||||
|
const messageManager = require('./lib/message-manager') |
||||||
|
const HostStore = require('./lib/remote-store.js').HostStore |
||||||
|
const Web3 = require('web3') |
||||||
|
const ConfigManager = require('./lib/config-manager') |
||||||
|
|
||||||
|
module.exports = class MetamaskController { |
||||||
|
|
||||||
|
constructor (opts) { |
||||||
|
this.opts = opts |
||||||
|
this.configManager = new ConfigManager(opts) |
||||||
|
this.idStore = new IdentityStore({ |
||||||
|
configManager: this.configManager, |
||||||
|
}) |
||||||
|
this.provider = this.initializeProvider(opts) |
||||||
|
this.ethStore = new EthStore(this.provider) |
||||||
|
this.idStore.setStore(this.ethStore) |
||||||
|
this.messageManager = messageManager |
||||||
|
this.publicConfigStore = this.initPublicConfigStore() |
||||||
|
} |
||||||
|
|
||||||
|
getState () { |
||||||
|
return extend( |
||||||
|
this.ethStore.getState(), |
||||||
|
this.idStore.getState(), |
||||||
|
this.configManager.getConfig() |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
getApi () { |
||||||
|
const idStore = this.idStore |
||||||
|
|
||||||
|
return { |
||||||
|
getState: (cb) => { cb(null, this.getState()) }, |
||||||
|
setRpcTarget: this.setRpcTarget.bind(this), |
||||||
|
setProviderType: this.setProviderType.bind(this), |
||||||
|
useEtherscanProvider: this.useEtherscanProvider.bind(this), |
||||||
|
agreeToDisclaimer: this.agreeToDisclaimer.bind(this), |
||||||
|
// forward directly to idStore
|
||||||
|
createNewVault: idStore.createNewVault.bind(idStore), |
||||||
|
recoverFromSeed: idStore.recoverFromSeed.bind(idStore), |
||||||
|
submitPassword: idStore.submitPassword.bind(idStore), |
||||||
|
setSelectedAddress: idStore.setSelectedAddress.bind(idStore), |
||||||
|
approveTransaction: idStore.approveTransaction.bind(idStore), |
||||||
|
cancelTransaction: idStore.cancelTransaction.bind(idStore), |
||||||
|
signMessage: idStore.signMessage.bind(idStore), |
||||||
|
cancelMessage: idStore.cancelMessage.bind(idStore), |
||||||
|
setLocked: idStore.setLocked.bind(idStore), |
||||||
|
clearSeedWordCache: idStore.clearSeedWordCache.bind(idStore), |
||||||
|
exportAccount: idStore.exportAccount.bind(idStore), |
||||||
|
revealAccount: idStore.revealAccount.bind(idStore), |
||||||
|
saveAccountLabel: idStore.saveAccountLabel.bind(idStore), |
||||||
|
tryPassword: idStore.tryPassword.bind(idStore), |
||||||
|
recoverSeed: idStore.recoverSeed.bind(idStore), |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
setupProviderConnection (stream, originDomain) { |
||||||
|
stream.on('data', this.onRpcRequest.bind(this, stream, originDomain)) |
||||||
|
} |
||||||
|
|
||||||
|
onRpcRequest (stream, originDomain, request) { |
||||||
|
var payloads = Array.isArray(request) ? request : [request] |
||||||
|
payloads.forEach(function (payload) { |
||||||
|
// Append origin to rpc payload
|
||||||
|
payload.origin = originDomain |
||||||
|
// Append origin to signature request
|
||||||
|
if (payload.method === 'eth_sendTransaction') { |
||||||
|
payload.params[0].origin = originDomain |
||||||
|
} else if (payload.method === 'eth_sign') { |
||||||
|
payload.params.push({ origin: originDomain }) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
// handle rpc request
|
||||||
|
this.provider.sendAsync(request, function onPayloadHandled (err, response) { |
||||||
|
if (err) { |
||||||
|
return logger(err) |
||||||
|
} |
||||||
|
logger(null, request, response) |
||||||
|
try { |
||||||
|
stream.write(response) |
||||||
|
} catch (err) { |
||||||
|
logger(err) |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
function logger (err, request, response) { |
||||||
|
if (err) return console.error(err.stack) |
||||||
|
if (!request.isMetamaskInternal) { |
||||||
|
console.log(`RPC (${originDomain}):`, request, '->', response) |
||||||
|
if (response.error) console.error('Error in RPC response:\n' + response.error.message) |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
sendUpdate () { |
||||||
|
if (this.remote) { |
||||||
|
this.remote.sendUpdate(this.getState()) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
initializeProvider (opts) { |
||||||
|
const idStore = this.idStore |
||||||
|
|
||||||
|
var providerOpts = { |
||||||
|
rpcUrl: this.configManager.getCurrentRpcAddress(), |
||||||
|
// account mgmt
|
||||||
|
getAccounts: (cb) => { |
||||||
|
var selectedAddress = idStore.getSelectedAddress() |
||||||
|
var result = selectedAddress ? [selectedAddress] : [] |
||||||
|
cb(null, result) |
||||||
|
}, |
||||||
|
// tx signing
|
||||||
|
approveTransaction: this.newUnsignedTransaction.bind(this), |
||||||
|
signTransaction: idStore.signTransaction.bind(idStore), |
||||||
|
// msg signing
|
||||||
|
approveMessage: this.newUnsignedMessage.bind(this), |
||||||
|
signMessage: idStore.signMessage.bind(idStore), |
||||||
|
} |
||||||
|
|
||||||
|
var provider = MetaMaskProvider(providerOpts) |
||||||
|
var web3 = new Web3(provider) |
||||||
|
idStore.web3 = web3 |
||||||
|
idStore.getNetwork() |
||||||
|
|
||||||
|
provider.on('block', this.processBlock.bind(this)) |
||||||
|
provider.on('error', idStore.getNetwork.bind(idStore)) |
||||||
|
|
||||||
|
return provider |
||||||
|
} |
||||||
|
|
||||||
|
initPublicConfigStore () { |
||||||
|
// get init state
|
||||||
|
var initPublicState = extend( |
||||||
|
idStoreToPublic(this.idStore.getState()), |
||||||
|
configToPublic(this.configManager.getConfig()) |
||||||
|
) |
||||||
|
|
||||||
|
var publicConfigStore = new HostStore(initPublicState) |
||||||
|
|
||||||
|
// subscribe to changes
|
||||||
|
this.configManager.subscribe(function (state) { |
||||||
|
storeSetFromObj(publicConfigStore, configToPublic(state)) |
||||||
|
}) |
||||||
|
this.idStore.on('update', function (state) { |
||||||
|
storeSetFromObj(publicConfigStore, idStoreToPublic(state)) |
||||||
|
}) |
||||||
|
|
||||||
|
// idStore substate
|
||||||
|
function idStoreToPublic (state) { |
||||||
|
return { |
||||||
|
selectedAddress: state.selectedAddress, |
||||||
|
} |
||||||
|
} |
||||||
|
// config substate
|
||||||
|
function configToPublic (state) { |
||||||
|
return { |
||||||
|
provider: state.provider, |
||||||
|
} |
||||||
|
} |
||||||
|
// dump obj into store
|
||||||
|
function storeSetFromObj (store, obj) { |
||||||
|
Object.keys(obj).forEach(function (key) { |
||||||
|
store.set(key, obj[key]) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
return publicConfigStore |
||||||
|
} |
||||||
|
|
||||||
|
newUnsignedTransaction (txParams, onTxDoneCb) { |
||||||
|
const idStore = this.idStore |
||||||
|
var state = idStore.getState() |
||||||
|
|
||||||
|
// It's locked
|
||||||
|
if (!state.isUnlocked) { |
||||||
|
this.opts.unlockAccountMessage() |
||||||
|
idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, noop) |
||||||
|
|
||||||
|
// It's unlocked
|
||||||
|
} else { |
||||||
|
idStore.addUnconfirmedTransaction(txParams, onTxDoneCb, (err, txData) => { |
||||||
|
if (err) return onTxDoneCb(err) |
||||||
|
this.opts.showUnconfirmedTx(txParams, txData, onTxDoneCb) |
||||||
|
}) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
newUnsignedMessage (msgParams, cb) { |
||||||
|
var state = this.idStore.getState() |
||||||
|
if (!state.isUnlocked) { |
||||||
|
this.opts.unlockAccountMessage() |
||||||
|
} else { |
||||||
|
this.addUnconfirmedMsg(msgParams, cb) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
addUnconfirmedMessage (msgParams, cb) { |
||||||
|
const idStore = this.idStore |
||||||
|
const msgId = idStore.addUnconfirmedMessage(msgParams, cb) |
||||||
|
this.opts.showUnconfirmedMessage(msgParams, msgId) |
||||||
|
} |
||||||
|
|
||||||
|
setupPublicConfig (stream) { |
||||||
|
var storeStream = this.publicConfigStore.createStream() |
||||||
|
stream.pipe(storeStream).pipe(stream) |
||||||
|
} |
||||||
|
|
||||||
|
// Log blocks
|
||||||
|
processBlock (block) { |
||||||
|
console.log(`BLOCK CHANGED: #${block.number.toString('hex')} 0x${block.hash.toString('hex')}`) |
||||||
|
this.verifyNetwork() |
||||||
|
} |
||||||
|
|
||||||
|
verifyNetwork () { |
||||||
|
// Check network when restoring connectivity:
|
||||||
|
if (this.idStore._currentState.network === 'loading') { |
||||||
|
this.idStore.getNetwork() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// config
|
||||||
|
//
|
||||||
|
|
||||||
|
agreeToDisclaimer (cb) { |
||||||
|
try { |
||||||
|
this.configManager.setConfirmed(true) |
||||||
|
cb() |
||||||
|
} catch (e) { |
||||||
|
cb(e) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// called from popup
|
||||||
|
setRpcTarget (rpcTarget) { |
||||||
|
this.configManager.setRpcTarget(rpcTarget) |
||||||
|
chrome.runtime.reload() |
||||||
|
this.idStore.getNetwork() |
||||||
|
} |
||||||
|
|
||||||
|
setProviderType (type) { |
||||||
|
this.configManager.setProviderType(type) |
||||||
|
chrome.runtime.reload() |
||||||
|
this.idStore.getNetwork() |
||||||
|
} |
||||||
|
|
||||||
|
useEtherscanProvider () { |
||||||
|
this.configManager.useEtherscanProvider() |
||||||
|
chrome.runtime.reload() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function noop () {} |
@ -0,0 +1,57 @@ |
|||||||
|
var ConfigManager = require('../../app/scripts/lib/config-manager') |
||||||
|
const STORAGE_KEY = 'metamask-persistance-key' |
||||||
|
const extend = require('xtend') |
||||||
|
|
||||||
|
module.exports = function() { |
||||||
|
return new ConfigManager({ loadData, setData }) |
||||||
|
} |
||||||
|
|
||||||
|
function loadData () { |
||||||
|
var oldData = getOldStyleData() |
||||||
|
var newData |
||||||
|
try { |
||||||
|
newData = JSON.parse(window.localStorage[STORAGE_KEY]) |
||||||
|
} catch (e) {} |
||||||
|
|
||||||
|
var data = extend({ |
||||||
|
meta: { |
||||||
|
version: 0, |
||||||
|
}, |
||||||
|
data: { |
||||||
|
config: { |
||||||
|
provider: { |
||||||
|
type: 'testnet', |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, |
||||||
|
}, oldData || null, newData || null) |
||||||
|
return data |
||||||
|
} |
||||||
|
|
||||||
|
function getOldStyleData () { |
||||||
|
var config, wallet, seedWords |
||||||
|
|
||||||
|
var result = { |
||||||
|
meta: { version: 0 }, |
||||||
|
data: {}, |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
config = JSON.parse(window.localStorage['config']) |
||||||
|
result.data.config = config |
||||||
|
} catch (e) {} |
||||||
|
try { |
||||||
|
wallet = JSON.parse(window.localStorage['lightwallet']) |
||||||
|
result.data.wallet = wallet |
||||||
|
} catch (e) {} |
||||||
|
try { |
||||||
|
seedWords = window.localStorage['seedWords'] |
||||||
|
result.data.seedWords = seedWords |
||||||
|
} catch (e) {} |
||||||
|
|
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
function setData (data) { |
||||||
|
window.localStorage[STORAGE_KEY] = JSON.stringify(data) |
||||||
|
} |
Loading…
Reference in new issue