From f16802e2d4f7e917e894e3ec38a716255f6b0942 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 10:15:35 -0700 Subject: nonce-tracker - validation - add validation failing value to error message --- app/scripts/lib/nonce-tracker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index b76dac4e8..4bba1f1a8 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -31,12 +31,12 @@ class NonceTracker { const currentBlock = await this._getCurrentBlock() const pendingTransactions = this.getPendingTransactions(address) const pendingCount = pendingTransactions.length - assert(Number.isInteger(pendingCount), 'nonce-tracker - pendingCount is an integer') + assert(Number.isInteger(pendingCount), `nonce-tracker - pendingCount is not an integer - got: "${pendingCount}"`) const baseCountHex = await this._getTxCount(address, currentBlock) const baseCount = parseInt(baseCountHex, 16) - assert(Number.isInteger(baseCount), 'nonce-tracker - baseCount is an integer') + assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: "${baseCount}"`) const nextNonce = baseCount + pendingCount - assert(Number.isInteger(nextNonce), 'nonce-tracker - nextNonce is an integer') + assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: "${nextNonce}"`) // return next nonce and release cb return { nextNonce, releaseLock } } -- cgit v1.2.3 From 39d28922de31fa26b50eca5c7719ae9feefae770 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 10:16:08 -0700 Subject: nonce-tracker - validation - add validation failing value type to error message --- app/scripts/lib/nonce-tracker.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index 4bba1f1a8..81b500550 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -31,12 +31,12 @@ class NonceTracker { const currentBlock = await this._getCurrentBlock() const pendingTransactions = this.getPendingTransactions(address) const pendingCount = pendingTransactions.length - assert(Number.isInteger(pendingCount), `nonce-tracker - pendingCount is not an integer - got: "${pendingCount}"`) + assert(Number.isInteger(pendingCount), `nonce-tracker - pendingCount is not an integer - got: (${typeof pendingCount}) "${pendingCount}"`) const baseCountHex = await this._getTxCount(address, currentBlock) const baseCount = parseInt(baseCountHex, 16) - assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: "${baseCount}"`) + assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) const nextNonce = baseCount + pendingCount - assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: "${nextNonce}"`) + assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) // return next nonce and release cb return { nextNonce, releaseLock } } -- cgit v1.2.3 From 0ef90fb1f0f1a1bf4a7efd90df7b8f8c66fc07d5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 10:40:08 -0700 Subject: tx controller + nonce tracker - record nonce components on txMeta --- app/scripts/controllers/transactions.js | 4 ++++ app/scripts/lib/nonce-tracker.js | 7 +++++-- 2 files changed, 9 insertions(+), 2 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 7b2e4e314..32795a9f2 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -200,8 +200,12 @@ module.exports = class TransactionController extends EventEmitter { // get next nonce const txMeta = this.getTx(txId) const fromAddress = txMeta.txParams.from + // wait for a nonce nonceLock = await this.nonceTracker.getNonceLock(fromAddress) + // add nonce to txParams txMeta.txParams.nonce = nonceLock.nextNonce + // add nonce debugging information to txMeta + txMeta.nonceDetails = nonceLock.nonceDetails this.updateTx(txMeta) // sign transaction const rawTx = await this.signTransaction(txId) diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index 81b500550..c0746bd87 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -37,8 +37,11 @@ class NonceTracker { assert(Number.isInteger(baseCount), `nonce-tracker - baseCount is not an integer - got: (${typeof baseCount}) "${baseCount}"`) const nextNonce = baseCount + pendingCount assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) - // return next nonce and release cb - return { nextNonce, releaseLock } + // collect the numbers used to calculate the nonce for debugging + const blockNumber = currentBlock.number + const nonceDetails = { blockNumber, baseCount, pendingCount } + // return nonce and release cb + return { nextNonce, nonceDetails, releaseLock } } async _getCurrentBlock () { -- cgit v1.2.3 From 7e2e4948a6ce5856338406de49cbad6a9931d72b Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 10:57:47 -0700 Subject: tx cont - dont recursively store history --- app/scripts/controllers/transactions.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index d6b2b555e..8f53ffa8c 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -119,14 +119,20 @@ module.exports = class TransactionController extends EventEmitter { // updateTx (txMeta) { + // create txMeta snapshot for history const txMetaForHistory = clone(txMeta) + // dont include previous history in this snapshot + delete txMetaForHistory.history + // add stack to help understand why tx was updated txMetaForHistory.stack = getStack() - var txId = txMeta.id - var txList = this.getFullTxList() - var index = txList.findIndex(txData => txData.id === txId) + // add snapshot to tx history if (!txMeta.history) txMeta.history = [] txMeta.history.push(txMetaForHistory) + // update the tx + var txId = txMeta.id + var txList = this.getFullTxList() + var index = txList.findIndex(txData => txData.id === txId) txList[index] = txMeta this._saveTxList(txList) this.emit('update') -- cgit v1.2.3 From b15a2baaf3cf7b4850c427857e935b238d1e5cc2 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 11:09:02 -0700 Subject: nonce-tracker - add raw baseNonceHex to nonceDetails --- app/scripts/lib/nonce-tracker.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index c0746bd87..e33073ac1 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -39,7 +39,7 @@ class NonceTracker { assert(Number.isInteger(nextNonce), `nonce-tracker - nextNonce is not an integer - got: (${typeof nextNonce}) "${nextNonce}"`) // collect the numbers used to calculate the nonce for debugging const blockNumber = currentBlock.number - const nonceDetails = { blockNumber, baseCount, pendingCount } + const nonceDetails = { blockNumber, baseCount, baseCountHex, pendingCount } // return nonce and release cb return { nextNonce, nonceDetails, releaseLock } } -- cgit v1.2.3 From 35a128db1e6ecba9076ec145c9d2334f623703b7 Mon Sep 17 00:00:00 2001 From: kumavis Date: Wed, 26 Jul 2017 11:37:00 -0700 Subject: nonce-tracker - hotfix for provider proxying --- app/scripts/controllers/transactions.js | 1 - app/scripts/lib/nonce-tracker.js | 15 +++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) (limited to 'app') diff --git a/app/scripts/controllers/transactions.js b/app/scripts/controllers/transactions.js index 8f53ffa8c..f71659042 100644 --- a/app/scripts/controllers/transactions.js +++ b/app/scripts/controllers/transactions.js @@ -24,7 +24,6 @@ module.exports = class TransactionController extends EventEmitter { this.blockTracker = opts.blockTracker this.nonceTracker = new NonceTracker({ provider: this.provider, - blockTracker: this.provider._blockTracker, getPendingTransactions: (address) => { return this.getFilteredTxList({ from: address, diff --git a/app/scripts/lib/nonce-tracker.js b/app/scripts/lib/nonce-tracker.js index e33073ac1..8328e81ec 100644 --- a/app/scripts/lib/nonce-tracker.js +++ b/app/scripts/lib/nonce-tracker.js @@ -4,8 +4,8 @@ const Mutex = require('await-semaphore').Mutex class NonceTracker { - constructor ({ blockTracker, provider, getPendingTransactions }) { - this.blockTracker = blockTracker + constructor ({ provider, getPendingTransactions }) { + this.provider = provider this.ethQuery = new EthQuery(provider) this.getPendingTransactions = getPendingTransactions this.lockMap = {} @@ -45,10 +45,11 @@ class NonceTracker { } async _getCurrentBlock () { - const currentBlock = this.blockTracker.getCurrentBlock() + const blockTracker = this._getBlockTracker() + const currentBlock = blockTracker.getCurrentBlock() if (currentBlock) return currentBlock return await Promise((reject, resolve) => { - this.blockTracker.once('latest', resolve) + blockTracker.once('latest', resolve) }) } @@ -82,6 +83,12 @@ class NonceTracker { return mutex } + // this is a hotfix for the fact that the blockTracker will + // change when the network changes + _getBlockTracker () { + return this.provider._blockTracker + } + } module.exports = NonceTracker -- cgit v1.2.3 From 3d8ebf2265d167923f3b913bac3b9cc4d37fa052 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 26 Jul 2017 12:10:42 -0700 Subject: Begin implementing live-updating blacklist, not working yet --- app/scripts/background.js | 27 +++++++++++++++++++++++++++ app/scripts/blacklister.js | 19 +++++++++++-------- app/scripts/controllers/infura.js | 14 ++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/scripts/background.js b/app/scripts/background.js index e8987394f..c9505b237 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -90,6 +90,10 @@ function setupController (initState) { extension.runtime.onConnect.addListener(connectRemote) function connectRemote (remotePort) { + if (remotePort.name === 'blacklister') { + return setupBlacklist(connectRemote) + } + var isMetaMaskInternalProcess = remotePort.name === 'popup' || remotePort.name === 'notification' var portStream = new PortStream(remotePort) if (isMetaMaskInternalProcess) { @@ -135,6 +139,29 @@ function setupController (initState) { return Promise.resolve() } +// Listen for new pages and return if blacklisted: +function setupBlacklist (port) { + console.log('Blacklist connection established') + const handler = handleNewPageLoad.bind(port) + port.onMessage.addListener(handler) + setTimeout(() => { + port.onMessage.removeListener(handler) + }, 30000) +} + +function handleNewPageLoad (message) { + const { pageLoaded } = message + console.log('blaclist message received', message.pageLoaded) + if (!pageLoaded || !global.metamaskController) return + + const state = global.metamaskController.getState() + const { blacklist } = state.metamask + + if (blacklist && blacklist.includes(pageLoaded)) { + this.postMessage({ 'blacklist': pageLoaded }) + } +} + // // Etc... // diff --git a/app/scripts/blacklister.js b/app/scripts/blacklister.js index a45265a75..f5572c11a 100644 --- a/app/scripts/blacklister.js +++ b/app/scripts/blacklister.js @@ -1,13 +1,16 @@ -const blacklistedDomains = require('etheraddresslookup/blacklists/domains.json') +const extension = require('extensionizer') +console.log('blacklister content script loaded.') -function detectBlacklistedDomain() { - var strCurrentTab = window.location.hostname - if (blacklistedDomains && blacklistedDomains.includes(strCurrentTab)) { +const port = extension.runtime.connect({ name: 'blacklister' }) +port.postMessage({ 'pageLoaded': window.location.hostname }) +port.onMessage.addListener(redirectIfBlacklisted) + +function redirectIfBlacklisted (response) { + const { blacklist } = response + console.log('blacklister contentscript received blacklist response') + const host = window.location.hostname + if (blacklist && blacklist === host) { window.location.href = 'https://metamask.io/phishing.html' } } -window.addEventListener('load', function() { - detectBlacklistedDomain() -}) - diff --git a/app/scripts/controllers/infura.js b/app/scripts/controllers/infura.js index b34b0bc03..97b2ab7e3 100644 --- a/app/scripts/controllers/infura.js +++ b/app/scripts/controllers/infura.js @@ -1,5 +1,6 @@ const ObservableStore = require('obs-store') const extend = require('xtend') +const recentBlacklist = require('etheraddresslookup/blacklists/domains.json') // every ten minutes const POLLING_INTERVAL = 300000 @@ -9,6 +10,7 @@ class InfuraController { constructor (opts = {}) { const initState = extend({ infuraNetworkStatus: {}, + blacklist: recentBlacklist, }, opts.initState) this.store = new ObservableStore(initState) } @@ -30,12 +32,24 @@ class InfuraController { }) } + updateLocalBlacklist () { + return fetch('https://api.infura.io/v1/blacklist') + .then(response => response.json()) + .then((parsedResponse) => { + this.store.updateState({ + blacklist: parsedResponse, + }) + return parsedResponse + }) + } + scheduleInfuraNetworkCheck () { if (this.conversionInterval) { clearInterval(this.conversionInterval) } this.conversionInterval = setInterval(() => { this.checkInfuraNetworkStatus() + this.updateLocalBlacklist() }, POLLING_INTERVAL) } } -- cgit v1.2.3 From b50c10f373c30642e083fb87724fc5db2ffff1e9 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 26 Jul 2017 14:15:24 -0700 Subject: Version 3.9.2 --- app/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index eadd99590..55e1eb5b1 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -1,7 +1,7 @@ { "name": "MetaMask", "short_name": "Metamask", - "version": "3.9.1", + "version": "3.9.2", "manifest_version": 2, "author": "https://metamask.io", "description": "Ethereum Browser Extension", -- cgit v1.2.3 From 66f6d5a4e06c6938ae22bd2cb4696f6ade900df2 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 26 Jul 2017 15:25:30 -0700 Subject: Add levenshtein logic to blacklister. --- app/scripts/blacklister.js | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) (limited to 'app') diff --git a/app/scripts/blacklister.js b/app/scripts/blacklister.js index a45265a75..f4b95a31f 100644 --- a/app/scripts/blacklister.js +++ b/app/scripts/blacklister.js @@ -1,13 +1,37 @@ -const blacklistedDomains = require('etheraddresslookup/blacklists/domains.json') +const levenshtein = require('fast-levenshtein') +const blacklistedMetaMaskDomains = ['metamask.com'] +const blacklistedDomains = require('etheraddresslookup/blacklists/domains.json').concat(blacklistedMetaMaskDomains) +const whitelistedMetaMaskDomains = ['metamask.io', 'www.metamask.io'] +const whitelistedDomains = require('etheraddresslookup/whitelists/domains.json').concat(whitelistedMetaMaskDomains) +const LEVENSHTEIN_TOLERANCE = 4 +const LEVENSHTEIN_CHECKS = ['myetherwallet', 'myetheroll', 'ledgerwallet', 'metamask'] -function detectBlacklistedDomain() { - var strCurrentTab = window.location.hostname - if (blacklistedDomains && blacklistedDomains.includes(strCurrentTab)) { - window.location.href = 'https://metamask.io/phishing.html' - } +function isPhish(hostname) { + var strCurrentTab = hostname + + // check if the domain is part of the whitelist. + if (whitelistedDomains && whitelistedDomains.includes(strCurrentTab)) { return false } + + // check if the domain is part of the blacklist. + var isBlacklisted = blacklistedDomains && blacklistedDomains.includes(strCurrentTab) + + // check for similar values. + var levenshteinMatched = false + var levenshteinForm = strCurrentTab.replace(/\./g, '') + LEVENSHTEIN_CHECKS.forEach((element) => { + if (levenshtein.get(element, levenshteinForm) < LEVENSHTEIN_TOLERANCE) { + levenshteinMatched = true + } + }) + + return isBlacklisted || levenshteinMatched } -window.addEventListener('load', function() { - detectBlacklistedDomain() +window.addEventListener('load', function () { + var hostnameToCheck = window.location.hostname + if (isPhish(hostnameToCheck)) { + window.location.href = 'https://metamask.io/phishing.html' + } }) +module.exports = isPhish -- cgit v1.2.3 From aa282b4e3a55d090f27e37cacf850aa5298cfe27 Mon Sep 17 00:00:00 2001 From: Kevin Serrano Date: Wed, 26 Jul 2017 15:31:16 -0700 Subject: Give credit where it is due --- app/scripts/blacklister.js | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'app') diff --git a/app/scripts/blacklister.js b/app/scripts/blacklister.js index f4b95a31f..9337599cc 100644 --- a/app/scripts/blacklister.js +++ b/app/scripts/blacklister.js @@ -6,6 +6,9 @@ const whitelistedDomains = require('etheraddresslookup/whitelists/domains.json') const LEVENSHTEIN_TOLERANCE = 4 const LEVENSHTEIN_CHECKS = ['myetherwallet', 'myetheroll', 'ledgerwallet', 'metamask'] + +// credit to @sogoiii and @409H for their help! +// Return a boolean on whether or not a phish is detected. function isPhish(hostname) { var strCurrentTab = hostname @@ -30,6 +33,7 @@ function isPhish(hostname) { window.addEventListener('load', function () { var hostnameToCheck = window.location.hostname if (isPhish(hostnameToCheck)) { + // redirect to our phishing warning page. window.location.href = 'https://metamask.io/phishing.html' } }) -- cgit v1.2.3 From 8b1726cc550d4a5b142a2a525ce6b94713dc04e0 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Wed, 26 Jul 2017 16:30:54 -0700 Subject: Live update blacklist from Infura --- app/manifest.json | 9 +++++++-- app/scripts/background.js | 14 ++++++-------- app/scripts/blacklister.js | 4 +--- app/scripts/inpage.js | 1 + 4 files changed, 15 insertions(+), 13 deletions(-) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index 55e1eb5b1..edc4d7162 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -55,8 +55,13 @@ }, { "run_at": "document_start", - "matches": ["http://*/*", "https://*/*"], - "js": ["scripts/blacklister.js"] + "matches": [ + "file://*/*", + "http://*/*", + "https://*/*" + ], + "js": ["scripts/blacklister.js"], + "all_frames": true } ], "permissions": [ diff --git a/app/scripts/background.js b/app/scripts/background.js index c9505b237..01bb39186 100644 --- a/app/scripts/background.js +++ b/app/scripts/background.js @@ -91,7 +91,7 @@ function setupController (initState) { extension.runtime.onConnect.addListener(connectRemote) function connectRemote (remotePort) { if (remotePort.name === 'blacklister') { - return setupBlacklist(connectRemote) + return checkBlacklist(remotePort) } var isMetaMaskInternalProcess = remotePort.name === 'popup' || remotePort.name === 'notification' @@ -140,25 +140,23 @@ function setupController (initState) { } // Listen for new pages and return if blacklisted: -function setupBlacklist (port) { - console.log('Blacklist connection established') - const handler = handleNewPageLoad.bind(port) +function checkBlacklist (port) { + const handler = handleNewPageLoad.bind(null, port) port.onMessage.addListener(handler) setTimeout(() => { port.onMessage.removeListener(handler) }, 30000) } -function handleNewPageLoad (message) { +function handleNewPageLoad (port, message) { const { pageLoaded } = message - console.log('blaclist message received', message.pageLoaded) if (!pageLoaded || !global.metamaskController) return const state = global.metamaskController.getState() - const { blacklist } = state.metamask + const { blacklist } = state if (blacklist && blacklist.includes(pageLoaded)) { - this.postMessage({ 'blacklist': pageLoaded }) + port.postMessage({ 'blacklist': pageLoaded }) } } diff --git a/app/scripts/blacklister.js b/app/scripts/blacklister.js index f5572c11a..37751b595 100644 --- a/app/scripts/blacklister.js +++ b/app/scripts/blacklister.js @@ -1,13 +1,11 @@ const extension = require('extensionizer') -console.log('blacklister content script loaded.') -const port = extension.runtime.connect({ name: 'blacklister' }) +var port = extension.runtime.connect({name: 'blacklister'}) port.postMessage({ 'pageLoaded': window.location.hostname }) port.onMessage.addListener(redirectIfBlacklisted) function redirectIfBlacklisted (response) { const { blacklist } = response - console.log('blacklister contentscript received blacklist response') const host = window.location.hostname if (blacklist && blacklist === host) { window.location.href = 'https://metamask.io/phishing.html' diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js index ec764535e..9e98c044b 100644 --- a/app/scripts/inpage.js +++ b/app/scripts/inpage.js @@ -65,3 +65,4 @@ function restoreContextAfterImports () { console.warn('MetaMask - global.define could not be overwritten.') } } + -- cgit v1.2.3 From 7c71ee1babcaad19dbe7db6c5abfefe2f9654781 Mon Sep 17 00:00:00 2001 From: Dan Finlay Date: Thu, 27 Jul 2017 15:16:42 -0700 Subject: Do not blacklist files --- app/manifest.json | 1 - 1 file changed, 1 deletion(-) (limited to 'app') diff --git a/app/manifest.json b/app/manifest.json index edc4d7162..591a07d0d 100644 --- a/app/manifest.json +++ b/app/manifest.json @@ -56,7 +56,6 @@ { "run_at": "document_start", "matches": [ - "file://*/*", "http://*/*", "https://*/*" ], -- cgit v1.2.3