aboutsummaryrefslogtreecommitdiffstats
path: root/app/scripts/controllers/blacklist.js
blob: 89c7cc888652ffdd35b1869f8f129e0be0518766 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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 () {
    const response = await fetch('https://api.infura.io/v2/blacklist')
    const phishing = await response.json()
    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().catch(log.warn)
    this._phishingUpdateIntervalRef = setInterval(() => {
      this.updatePhishingList().catch(log.warn)
    }, 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