diff options
Diffstat (limited to 'app/scripts/lib')
-rw-r--r-- | app/scripts/lib/account-tracker.js | 3 | ||||
-rw-r--r-- | app/scripts/lib/auto-reload.js | 6 | ||||
-rw-r--r-- | app/scripts/lib/config-manager.js | 254 | ||||
-rw-r--r-- | app/scripts/lib/ipfsContent.js | 4 | ||||
-rw-r--r-- | app/scripts/lib/message-manager.js | 2 | ||||
-rw-r--r-- | app/scripts/lib/personal-message-manager.js | 2 | ||||
-rw-r--r-- | app/scripts/lib/typed-message-manager.js | 74 |
7 files changed, 60 insertions, 285 deletions
diff --git a/app/scripts/lib/account-tracker.js b/app/scripts/lib/account-tracker.js index 3a52d5e8d..2e9340018 100644 --- a/app/scripts/lib/account-tracker.js +++ b/app/scripts/lib/account-tracker.js @@ -45,6 +45,9 @@ class AccountTracker { this._blockTracker = opts.blockTracker // blockTracker.currentBlock may be null this._currentBlockNumber = this._blockTracker.getCurrentBlock() + this._blockTracker.once('latest', blockNumber => { + this._currentBlockNumber = blockNumber + }) // bind function for easier listener syntax this._updateForBlock = this._updateForBlock.bind(this) } diff --git a/app/scripts/lib/auto-reload.js b/app/scripts/lib/auto-reload.js index cce31c3d2..558391a06 100644 --- a/app/scripts/lib/auto-reload.js +++ b/app/scripts/lib/auto-reload.js @@ -2,18 +2,12 @@ module.exports = setupDappAutoReload function setupDappAutoReload (web3, observable) { // export web3 as a global, checking for usage - let hasBeenWarned = false let reloadInProgress = false let lastTimeUsed let lastSeenNetwork global.web3 = new Proxy(web3, { get: (_web3, key) => { - // show warning once on web3 access - if (!hasBeenWarned && key !== 'currentProvider') { - console.warn('MetaMask: web3 will be deprecated in the near future in favor of the ethereumProvider \nhttps://github.com/MetaMask/faq/blob/master/detecting_metamask.md#web3-deprecation') - hasBeenWarned = true - } // get the time of use lastTimeUsed = Date.now() // return value normally diff --git a/app/scripts/lib/config-manager.js b/app/scripts/lib/config-manager.js deleted file mode 100644 index 221746467..000000000 --- a/app/scripts/lib/config-manager.js +++ /dev/null @@ -1,254 +0,0 @@ -const ethUtil = require('ethereumjs-util') -const normalize = require('eth-sig-util').normalize -const { - MAINNET_RPC_URL, - ROPSTEN_RPC_URL, - KOVAN_RPC_URL, - RINKEBY_RPC_URL, -} = require('../controllers/network/enums') - -/* The config-manager is a convenience object - * wrapping a pojo-migrator. - * - * It exists mostly to allow the creation of - * convenience methods to access and persist - * particular portions of the state. - */ -module.exports = ConfigManager -function ConfigManager (opts) { - // ConfigManager is observable and will emit updates - this._subs = [] - this.store = opts.store -} - -ConfigManager.prototype.setConfig = function (config) { - var data = this.getData() - data.config = config - this.setData(data) - this._emitUpdates(config) -} - -ConfigManager.prototype.getConfig = function () { - var data = this.getData() - return data.config -} - -ConfigManager.prototype.setData = function (data) { - this.store.putState(data) -} - -ConfigManager.prototype.getData = function () { - return this.store.getState() -} - -ConfigManager.prototype.setPasswordForgotten = function (passwordForgottenState) { - const data = this.getData() - data.forgottenPassword = passwordForgottenState - this.setData(data) -} - -ConfigManager.prototype.getPasswordForgotten = function (passwordForgottenState) { - const data = this.getData() - return data.forgottenPassword -} - -ConfigManager.prototype.setWallet = function (wallet) { - var data = this.getData() - data.wallet = wallet - this.setData(data) -} - -ConfigManager.prototype.setVault = function (encryptedString) { - var data = this.getData() - data.vault = encryptedString - this.setData(data) -} - -ConfigManager.prototype.getVault = function () { - var data = this.getData() - return data.vault -} - -ConfigManager.prototype.getKeychains = function () { - return this.getData().keychains || [] -} - -ConfigManager.prototype.setKeychains = function (keychains) { - var data = this.getData() - data.keychains = keychains - this.setData(data) -} - -ConfigManager.prototype.getSelectedAccount = function () { - var config = this.getConfig() - return config.selectedAccount -} - -ConfigManager.prototype.setSelectedAccount = function (address) { - var config = this.getConfig() - config.selectedAccount = ethUtil.addHexPrefix(address) - this.setConfig(config) -} - -ConfigManager.prototype.getWallet = function () { - return this.getData().wallet -} - -// Takes a boolean -ConfigManager.prototype.setShowSeedWords = function (should) { - var data = this.getData() - data.showSeedWords = should - this.setData(data) -} - - -ConfigManager.prototype.getShouldShowSeedWords = function () { - var data = this.getData() - return data.showSeedWords -} - -ConfigManager.prototype.setSeedWords = function (words) { - var data = this.getData() - data.seedWords = words - this.setData(data) -} - -ConfigManager.prototype.getSeedWords = function () { - var data = this.getData() - return data.seedWords -} -ConfigManager.prototype.setRpcTarget = function (rpcUrl) { - var config = this.getConfig() - config.provider = { - type: 'rpc', - rpcTarget: rpcUrl, - } - this.setConfig(config) -} - -ConfigManager.prototype.setProviderType = function (type) { - var config = this.getConfig() - config.provider = { - type: type, - } - this.setConfig(config) -} - -ConfigManager.prototype.useEtherscanProvider = function () { - var config = this.getConfig() - config.provider = { - type: 'etherscan', - } - this.setConfig(config) -} - -ConfigManager.prototype.getProvider = function () { - var config = this.getConfig() - return config.provider -} - -ConfigManager.prototype.getCurrentRpcAddress = function () { - var provider = this.getProvider() - if (!provider) return null - switch (provider.type) { - - case 'mainnet': - return MAINNET_RPC_URL - - case 'ropsten': - return ROPSTEN_RPC_URL - - case 'kovan': - return KOVAN_RPC_URL - - case 'rinkeby': - return RINKEBY_RPC_URL - - default: - return provider && provider.rpcTarget ? provider.rpcTarget : RINKEBY_RPC_URL - } -} - -// -// Tx -// - -ConfigManager.prototype.getTxList = function () { - var data = this.getData() - if (data.transactions !== undefined) { - return data.transactions - } else { - return [] - } -} - -ConfigManager.prototype.setTxList = function (txList) { - var data = this.getData() - data.transactions = txList - this.setData(data) -} - - -// wallet nickname methods - -ConfigManager.prototype.getWalletNicknames = function () { - var data = this.getData() - const nicknames = ('walletNicknames' in data) ? data.walletNicknames : {} - return nicknames -} - -ConfigManager.prototype.nicknameForWallet = function (account) { - const address = normalize(account) - const nicknames = this.getWalletNicknames() - return nicknames[address] -} - -ConfigManager.prototype.setNicknameForWallet = function (account, nickname) { - const address = normalize(account) - const nicknames = this.getWalletNicknames() - nicknames[address] = nickname - var data = this.getData() - data.walletNicknames = nicknames - this.setData(data) -} - -// observable - -ConfigManager.prototype.getSalt = function () { - var data = this.getData() - return data.salt -} - -ConfigManager.prototype.setSalt = function (salt) { - var data = this.getData() - data.salt = salt - this.setData(data) -} - -ConfigManager.prototype.subscribe = function (fn) { - this._subs.push(fn) - var unsubscribe = this.unsubscribe.bind(this, fn) - return unsubscribe -} - -ConfigManager.prototype.unsubscribe = function (fn) { - var index = this._subs.indexOf(fn) - if (index !== -1) this._subs.splice(index, 1) -} - -ConfigManager.prototype._emitUpdates = function (state) { - this._subs.forEach(function (handler) { - handler(state) - }) -} - -ConfigManager.prototype.setLostAccounts = function (lostAccounts) { - var data = this.getData() - data.lostAccounts = lostAccounts - this.setData(data) -} - -ConfigManager.prototype.getLostAccounts = function () { - var data = this.getData() - return data.lostAccounts || [] -} diff --git a/app/scripts/lib/ipfsContent.js b/app/scripts/lib/ipfsContent.js index 38682b916..8b08453c4 100644 --- a/app/scripts/lib/ipfsContent.js +++ b/app/scripts/lib/ipfsContent.js @@ -5,6 +5,8 @@ module.exports = function (provider) { function ipfsContent (details) { const name = details.url.substring(7, details.url.length - 1) let clearTime = null + if (/^.+\.eth$/.test(name) === false) return + extension.tabs.query({active: true}, tab => { extension.tabs.update(tab.id, { url: 'loading.html' }) @@ -34,7 +36,7 @@ module.exports = function (provider) { return { cancel: true } } - extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/']}) + extension.webRequest.onErrorOccurred.addListener(ipfsContent, {urls: ['*://*.eth/'], types: ['main_frame']}) return { remove () { diff --git a/app/scripts/lib/message-manager.js b/app/scripts/lib/message-manager.js index 47925b94b..e86629590 100644 --- a/app/scripts/lib/message-manager.js +++ b/app/scripts/lib/message-manager.js @@ -272,6 +272,6 @@ function normalizeMsgData (data) { return data } else { // data is unicode, convert to hex - return ethUtil.bufferToHex(new Buffer(data, 'utf8')) + return ethUtil.bufferToHex(Buffer.from(data, 'utf8')) } } diff --git a/app/scripts/lib/personal-message-manager.js b/app/scripts/lib/personal-message-manager.js index fc2cccdf1..fdb94f5ec 100644 --- a/app/scripts/lib/personal-message-manager.js +++ b/app/scripts/lib/personal-message-manager.js @@ -285,7 +285,7 @@ module.exports = class PersonalMessageManager extends EventEmitter { log.debug(`Message was not hex encoded, interpreting as utf8.`) } - return ethUtil.bufferToHex(new Buffer(data, 'utf8')) + return ethUtil.bufferToHex(Buffer.from(data, 'utf8')) } } diff --git a/app/scripts/lib/typed-message-manager.js b/app/scripts/lib/typed-message-manager.js index e5e1c94b3..b10145f3b 100644 --- a/app/scripts/lib/typed-message-manager.js +++ b/app/scripts/lib/typed-message-manager.js @@ -4,6 +4,7 @@ const createId = require('./random-id') const assert = require('assert') const sigUtil = require('eth-sig-util') const log = require('loglevel') +const jsonschema = require('jsonschema') /** * Represents, and contains data about, an 'eth_signTypedData' type signature request. These are created when a @@ -17,7 +18,7 @@ const log = require('loglevel') * @property {Object} msgParams.from The address that is making the signature request. * @property {string} msgParams.data A hex string conversion of the raw buffer data of the signature request * @property {number} time The epoch time at which the this message was created - * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed' or 'rejected' + * @property {string} status Indicates whether the signature request is 'unapproved', 'approved', 'signed', 'rejected', or 'errored' * @property {string} type The json-prc signing method for which a signature request has been made. A 'Message' will * always have a 'eth_signTypedData' type. * @@ -26,17 +27,10 @@ const log = require('loglevel') module.exports = class TypedMessageManager extends EventEmitter { /** * Controller in charge of managing - storing, adding, removing, updating - TypedMessage. - * - * @typedef {Object} TypedMessage - * @param {Object} opts @deprecated - * @property {Object} memStore The observable store where TypedMessage are saved. - * @property {Object} memStore.unapprovedTypedMessages A collection of all TypedMessages in the 'unapproved' state - * @property {number} memStore.unapprovedTypedMessagesCount The count of all TypedMessages in this.memStore.unapprobedMsgs - * @property {array} messages Holds all messages that have been created by this TypedMessage - * */ - constructor (opts) { + constructor ({ networkController }) { super() + this.networkController = networkController this.memStore = new ObservableStore({ unapprovedTypedMessages: {}, unapprovedTypedMessagesCount: 0, @@ -76,15 +70,17 @@ module.exports = class TypedMessageManager extends EventEmitter { * @returns {promise} When the message has been signed or rejected * */ - addUnapprovedMessageAsync (msgParams, req) { + addUnapprovedMessageAsync (msgParams, req, version) { return new Promise((resolve, reject) => { - const msgId = this.addUnapprovedMessage(msgParams, req) + const msgId = this.addUnapprovedMessage(msgParams, req, version) this.once(`${msgId}:finished`, (data) => { switch (data.status) { case 'signed': return resolve(data.rawSig) case 'rejected': return reject(new Error('MetaMask Message Signature: User denied message signature.')) + case 'errored': + return reject(new Error(`MetaMask Message Signature: ${data.error}`)) default: return reject(new Error(`MetaMask Message Signature: Unknown problem: ${JSON.stringify(msgParams)}`)) } @@ -102,7 +98,8 @@ module.exports = class TypedMessageManager extends EventEmitter { * @returns {number} The id of the newly created TypedMessage. * */ - addUnapprovedMessage (msgParams, req) { + addUnapprovedMessage (msgParams, req, version) { + msgParams.version = version this.validateParams(msgParams) // add origin from request if (req) msgParams.origin = req.origin @@ -132,14 +129,33 @@ module.exports = class TypedMessageManager extends EventEmitter { * */ validateParams (params) { - assert.equal(typeof params, 'object', 'Params should ben an object.') - assert.ok('data' in params, 'Params must include a data field.') - assert.ok('from' in params, 'Params must include a from field.') - assert.ok(Array.isArray(params.data), 'Data should be an array.') - assert.equal(typeof params.from, 'string', 'From field must be a string.') - assert.doesNotThrow(() => { - sigUtil.typedSignatureHash(params.data) - }, 'Expected EIP712 typed data') + switch (params.version) { + case 'V1': + assert.equal(typeof params, 'object', 'Params should ben an object.') + assert.ok('data' in params, 'Params must include a data field.') + assert.ok('from' in params, 'Params must include a from field.') + assert.ok(Array.isArray(params.data), 'Data should be an array.') + assert.equal(typeof params.from, 'string', 'From field must be a string.') + assert.doesNotThrow(() => { + sigUtil.typedSignatureHash(params.data) + }, 'Expected EIP712 typed data') + break + case 'V3': + let data + assert.equal(typeof params, 'object', 'Params should be an object.') + assert.ok('data' in params, 'Params must include a data field.') + assert.ok('from' in params, 'Params must include a from field.') + assert.equal(typeof params.from, 'string', 'From field must be a string.') + assert.equal(typeof params.data, 'string', 'Data must be passed as a valid JSON string.') + assert.doesNotThrow(() => { data = JSON.parse(params.data) }, 'Data must be passed as a valid JSON string.') + const validation = jsonschema.validate(data, sigUtil.TYPED_MESSAGE_SCHEMA) + assert.ok(data.primaryType in data.types, `Primary type of "${data.primaryType}" has no type definition.`) + assert.equal(validation.errors.length, 0, 'Data must conform to EIP-712 schema. See https://git.io/fNtcx.') + const chainId = data.domain.chainId + const activeChainId = parseInt(this.networkController.getNetworkState()) + chainId && assert.equal(chainId, activeChainId, `Provided chainId (${chainId}) must match the active chainId (${activeChainId})`) + break + } } /** @@ -214,6 +230,7 @@ module.exports = class TypedMessageManager extends EventEmitter { */ prepMsgForSigning (msgParams) { delete msgParams.metamaskId + delete msgParams.version return Promise.resolve(msgParams) } @@ -227,6 +244,19 @@ module.exports = class TypedMessageManager extends EventEmitter { this._setMsgStatus(msgId, 'rejected') } + /** + * Sets a TypedMessage status to 'errored' via a call to this._setMsgStatus. + * + * @param {number} msgId The id of the TypedMessage to error + * + */ + errorMessage (msgId, error) { + const msg = this.getMsg(msgId) + msg.error = error + this._updateMsg(msg) + this._setMsgStatus(msgId, 'errored') + } + // // PRIVATE METHODS // @@ -250,7 +280,7 @@ module.exports = class TypedMessageManager extends EventEmitter { msg.status = status this._updateMsg(msg) this.emit(`${msgId}:${status}`, msg) - if (status === 'rejected' || status === 'signed') { + if (status === 'rejected' || status === 'signed' || status === 'errored') { this.emit(`${msgId}:finished`, msg) } } |