mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Merge pull request #6568 from MetaMask/feature/gaba-phishing-controller
feature: integrate gaba/PhishingController
This commit is contained in:
commit
08e8fb21dc
@ -1,136 +0,0 @@
|
|||||||
const ObservableStore = require('obs-store')
|
|
||||||
const extend = require('xtend')
|
|
||||||
const PhishingDetector = require('eth-phishing-detect/src/detector')
|
|
||||||
const log = require('loglevel')
|
|
||||||
|
|
||||||
// compute phishing lists
|
|
||||||
const PHISHING_DETECTION_CONFIG = require('eth-phishing-detect/src/config.json')
|
|
||||||
// every four minutes
|
|
||||||
const POLLING_INTERVAL = 4 * 60 * 1000
|
|
||||||
|
|
||||||
class BlacklistController {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Responsible for polling for and storing an up to date 'eth-phishing-detect' config.json file, while
|
|
||||||
* exposing a method that can check whether a given url is a phishing attempt. The 'eth-phishing-detect'
|
|
||||||
* config.json file contains a fuzzylist, whitelist and blacklist.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @typedef {Object} BlacklistController
|
|
||||||
* @param {object} opts Overrides the defaults for the initial state of this.store
|
|
||||||
* @property {object} store The the store of the current phishing config
|
|
||||||
* @property {object} store.phishing Contains fuzzylist, whitelist and blacklist arrays. @see
|
|
||||||
* {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json}
|
|
||||||
* @property {object} _phishingDetector The PhishingDetector instantiated by passing store.phishing to
|
|
||||||
* PhishingDetector.
|
|
||||||
* @property {object} _phishingUpdateIntervalRef Id of the interval created to periodically update the blacklist
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
constructor (opts = {}) {
|
|
||||||
const initState = extend({
|
|
||||||
phishing: PHISHING_DETECTION_CONFIG,
|
|
||||||
whitelist: [],
|
|
||||||
}, opts.initState)
|
|
||||||
this.store = new ObservableStore(initState)
|
|
||||||
// phishing detector
|
|
||||||
this._phishingDetector = null
|
|
||||||
this._setupPhishingDetector(initState.phishing)
|
|
||||||
// polling references
|
|
||||||
this._phishingUpdateIntervalRef = null
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adds the given hostname to the runtime whitelist
|
|
||||||
* @param {string} hostname the hostname to whitelist
|
|
||||||
*/
|
|
||||||
whitelistDomain (hostname) {
|
|
||||||
if (!hostname) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const { whitelist } = this.store.getState()
|
|
||||||
this.store.updateState({
|
|
||||||
whitelist: [...new Set([hostname, ...whitelist])],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given a url, returns the result of checking if that url is in the store.phishing blacklist
|
|
||||||
*
|
|
||||||
* @param {string} hostname The hostname portion of a url; the one that will be checked against the white and
|
|
||||||
* blacklists of store.phishing
|
|
||||||
* @returns {boolean} Whether or not the passed hostname is on our phishing blacklist
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
checkForPhishing (hostname) {
|
|
||||||
if (!hostname) return false
|
|
||||||
|
|
||||||
const { whitelist } = this.store.getState()
|
|
||||||
if (whitelist.some((e) => e === hostname)) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
const { result } = this._phishingDetector.check(hostname)
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Queries `https://api.infura.io/v2/blacklist` for an updated blacklist config. This is passed to this._phishingDetector
|
|
||||||
* to update our phishing detector instance, and is updated in the store. The new phishing config is returned
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* @returns {Promise<object>} Promises the updated blacklist config for the phishingDetector
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
async updatePhishingList () {
|
|
||||||
// make request
|
|
||||||
let response
|
|
||||||
try {
|
|
||||||
response = await fetch('https://api.infura.io/v2/blacklist')
|
|
||||||
} catch (err) {
|
|
||||||
log.error(new Error(`BlacklistController - failed to fetch blacklist:\n${err.stack}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// parse response
|
|
||||||
let rawResponse
|
|
||||||
let phishing
|
|
||||||
try {
|
|
||||||
const rawResponse = await response.text()
|
|
||||||
phishing = JSON.parse(rawResponse)
|
|
||||||
} catch (err) {
|
|
||||||
log.error(new Error(`BlacklistController - failed to parse blacklist:\n${rawResponse}`))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// update current blacklist
|
|
||||||
this.store.updateState({ phishing })
|
|
||||||
this._setupPhishingDetector(phishing)
|
|
||||||
return phishing
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initiates the updating of the local blacklist at a set interval. The update is done via this.updatePhishingList().
|
|
||||||
* Also, this method store a reference to that interval at this._phishingUpdateIntervalRef
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
scheduleUpdates () {
|
|
||||||
if (this._phishingUpdateIntervalRef) return
|
|
||||||
this.updatePhishingList()
|
|
||||||
this._phishingUpdateIntervalRef = setInterval(() => {
|
|
||||||
this.updatePhishingList()
|
|
||||||
}, POLLING_INTERVAL)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Sets this._phishingDetector to a new PhishingDetector instance.
|
|
||||||
* @see {@link https://github.com/MetaMask/eth-phishing-detect}
|
|
||||||
*
|
|
||||||
* @private
|
|
||||||
* @param {object} config A config object like that found at {@link https://github.com/MetaMask/eth-phishing-detect/blob/master/src/config.json}
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
_setupPhishingDetector (config) {
|
|
||||||
this._phishingDetector = new PhishingDetector(config)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = BlacklistController
|
|
@ -28,7 +28,6 @@ const PreferencesController = require('./controllers/preferences')
|
|||||||
const CurrencyController = require('./controllers/currency')
|
const CurrencyController = require('./controllers/currency')
|
||||||
const ShapeShiftController = require('./controllers/shapeshift')
|
const ShapeShiftController = require('./controllers/shapeshift')
|
||||||
const InfuraController = require('./controllers/infura')
|
const InfuraController = require('./controllers/infura')
|
||||||
const BlacklistController = require('./controllers/blacklist')
|
|
||||||
const CachedBalancesController = require('./controllers/cached-balances')
|
const CachedBalancesController = require('./controllers/cached-balances')
|
||||||
const RecentBlocksController = require('./controllers/recent-blocks')
|
const RecentBlocksController = require('./controllers/recent-blocks')
|
||||||
const MessageManager = require('./lib/message-manager')
|
const MessageManager = require('./lib/message-manager')
|
||||||
@ -55,7 +54,10 @@ const HW_WALLETS_KEYRINGS = [TrezorKeyring.type, LedgerBridgeKeyring.type]
|
|||||||
const EthQuery = require('eth-query')
|
const EthQuery = require('eth-query')
|
||||||
const ethUtil = require('ethereumjs-util')
|
const ethUtil = require('ethereumjs-util')
|
||||||
const sigUtil = require('eth-sig-util')
|
const sigUtil = require('eth-sig-util')
|
||||||
const { AddressBookController } = require('gaba')
|
const {
|
||||||
|
AddressBookController,
|
||||||
|
PhishingController,
|
||||||
|
} = require('gaba')
|
||||||
const backEndMetaMetricsEvent = require('./lib/backend-metametrics')
|
const backEndMetaMetricsEvent = require('./lib/backend-metametrics')
|
||||||
|
|
||||||
|
|
||||||
@ -112,8 +114,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
})
|
})
|
||||||
this.infuraController.scheduleInfuraNetworkCheck()
|
this.infuraController.scheduleInfuraNetworkCheck()
|
||||||
|
|
||||||
this.blacklistController = new BlacklistController()
|
this.phishingController = new PhishingController()
|
||||||
this.blacklistController.scheduleUpdates()
|
|
||||||
|
|
||||||
// rpc provider
|
// rpc provider
|
||||||
this.initializeProvider()
|
this.initializeProvider()
|
||||||
@ -1301,7 +1302,7 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
setupUntrustedCommunication (connectionStream, originDomain) {
|
setupUntrustedCommunication (connectionStream, originDomain) {
|
||||||
// Check if new connection is blacklisted
|
// Check if new connection is blacklisted
|
||||||
if (this.blacklistController.checkForPhishing(originDomain)) {
|
if (this.phishingController.test(originDomain)) {
|
||||||
log.debug('MetaMask - sending phishing warning for', originDomain)
|
log.debug('MetaMask - sending phishing warning for', originDomain)
|
||||||
this.sendPhishingWarning(connectionStream, originDomain)
|
this.sendPhishingWarning(connectionStream, originDomain)
|
||||||
return
|
return
|
||||||
@ -1781,11 +1782,11 @@ module.exports = class MetamaskController extends EventEmitter {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds a domain to the {@link BlacklistController} whitelist
|
* Adds a domain to the PhishingController whitelist
|
||||||
* @param {string} hostname the domain to whitelist
|
* @param {string} hostname the domain to whitelist
|
||||||
*/
|
*/
|
||||||
whitelistPhishingDomain (hostname) {
|
whitelistPhishingDomain (hostname) {
|
||||||
return this.blacklistController.whitelistDomain(hostname)
|
return this.phishingController.bypass(hostname)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
877
package-lock.json
generated
877
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -228,7 +228,7 @@
|
|||||||
"file-loader": "^1.1.11",
|
"file-loader": "^1.1.11",
|
||||||
"fs-extra": "^6.0.1",
|
"fs-extra": "^6.0.1",
|
||||||
"fs-promise": "^2.0.3",
|
"fs-promise": "^2.0.3",
|
||||||
"gaba": "1.0.0-beta.65",
|
"gaba": "^1.0.1",
|
||||||
"ganache-cli": "^6.1.0",
|
"ganache-cli": "^6.1.0",
|
||||||
"ganache-core": "^2.5.3",
|
"ganache-core": "^2.5.3",
|
||||||
"geckodriver": "^1.14.1",
|
"geckodriver": "^1.14.1",
|
||||||
|
@ -1,56 +0,0 @@
|
|||||||
const assert = require('assert')
|
|
||||||
const BlacklistController = require('../../../../app/scripts/controllers/blacklist')
|
|
||||||
|
|
||||||
describe('blacklist controller', function () {
|
|
||||||
let blacklistController
|
|
||||||
|
|
||||||
before(() => {
|
|
||||||
blacklistController = new BlacklistController()
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('whitelistDomain', function () {
|
|
||||||
it('should add hostname to the runtime whitelist', function () {
|
|
||||||
blacklistController.whitelistDomain('foo.com')
|
|
||||||
assert.deepEqual(blacklistController.store.getState().whitelist, ['foo.com'])
|
|
||||||
|
|
||||||
blacklistController.whitelistDomain('bar.com')
|
|
||||||
assert.deepEqual(blacklistController.store.getState().whitelist, ['bar.com', 'foo.com'])
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
describe('checkForPhishing', function () {
|
|
||||||
it('should not flag whitelisted values', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('www.metamask.io')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
it('should flag explicit values', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('metamask.com')
|
|
||||||
assert.equal(result, true)
|
|
||||||
})
|
|
||||||
it('should flag levenshtein values', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('metmask.io')
|
|
||||||
assert.equal(result, true)
|
|
||||||
})
|
|
||||||
it('should not flag not-even-close values', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('example.com')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
it('should not flag the ropsten faucet domains', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('faucet.metamask.io')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
it('should not flag the mascara domain', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('zero.metamask.io')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
it('should not flag the mascara-faucet domain', function () {
|
|
||||||
const result = blacklistController.checkForPhishing('zero-faucet.metamask.io')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
it('should not flag whitelisted domain', function () {
|
|
||||||
blacklistController.whitelistDomain('metamask.com')
|
|
||||||
const result = blacklistController.checkForPhishing('metamask.com')
|
|
||||||
assert.equal(result, false)
|
|
||||||
})
|
|
||||||
})
|
|
||||||
})
|
|
@ -752,8 +752,7 @@ describe('MetaMaskController', function () {
|
|||||||
})
|
})
|
||||||
|
|
||||||
it('sets up phishing stream for untrusted communication ', async () => {
|
it('sets up phishing stream for untrusted communication ', async () => {
|
||||||
await metamaskController.blacklistController.updatePhishingList()
|
await metamaskController.phishingController.updatePhishingLists()
|
||||||
console.log(blacklistJSON.blacklist.includes(phishingUrl))
|
|
||||||
|
|
||||||
const { promise, resolve } = deferredPromise()
|
const { promise, resolve } = deferredPromise()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user