You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
136 lines
4.5 KiB
136 lines
4.5 KiB
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
|
|
|