commit
89a4fef1e4
@ -1,14 +0,0 @@ |
|||||||
const extension = require('extensionizer') |
|
||||||
|
|
||||||
var port = extension.runtime.connect({name: 'blacklister'}) |
|
||||||
port.postMessage({ 'pageLoaded': window.location.hostname }) |
|
||||||
port.onMessage.addListener(redirectIfBlacklisted) |
|
||||||
|
|
||||||
function redirectIfBlacklisted (response) { |
|
||||||
const { blacklist } = response |
|
||||||
const host = window.location.hostname |
|
||||||
if (blacklist && blacklist === host) { |
|
||||||
window.location.href = 'https://metamask.io/phishing.html' |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
@ -0,0 +1,58 @@ |
|||||||
|
const ObservableStore = require('obs-store') |
||||||
|
const extend = require('xtend') |
||||||
|
const PhishingDetector = require('eth-phishing-detect/src/detector') |
||||||
|
|
||||||
|
// compute phishing lists
|
||||||
|
const PHISHING_DETECTION_CONFIG = require('eth-phishing-detect/src/config.json') |
||||||
|
// every ten minutes
|
||||||
|
const POLLING_INTERVAL = 10 * 60 * 1000 |
||||||
|
|
||||||
|
class BlacklistController { |
||||||
|
|
||||||
|
constructor (opts = {}) { |
||||||
|
const initState = extend({ |
||||||
|
phishing: PHISHING_DETECTION_CONFIG, |
||||||
|
}, opts.initState) |
||||||
|
this.store = new ObservableStore(initState) |
||||||
|
// phishing detector
|
||||||
|
this._phishingDetector = null |
||||||
|
this._setupPhishingDetector(initState.phishing) |
||||||
|
// polling references
|
||||||
|
this._phishingUpdateIntervalRef = null |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// PUBLIC METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
checkForPhishing (hostname) { |
||||||
|
if (!hostname) return false |
||||||
|
const { result } = this._phishingDetector.check(hostname) |
||||||
|
return result |
||||||
|
} |
||||||
|
|
||||||
|
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 |
||||||
|
} |
||||||
|
|
||||||
|
scheduleUpdates () { |
||||||
|
if (this._phishingUpdateIntervalRef) return |
||||||
|
this._phishingUpdateIntervalRef = setInterval(() => { |
||||||
|
this.updatePhishingList() |
||||||
|
}, POLLING_INTERVAL) |
||||||
|
} |
||||||
|
|
||||||
|
//
|
||||||
|
// PRIVATE METHODS
|
||||||
|
//
|
||||||
|
|
||||||
|
_setupPhishingDetector (config) { |
||||||
|
this._phishingDetector = new PhishingDetector(config) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = BlacklistController |
@ -1,38 +0,0 @@ |
|||||||
const levenshtein = require('fast-levenshtein') |
|
||||||
const blacklistedMetaMaskDomains = ['metamask.com'] |
|
||||||
let 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'] |
|
||||||
|
|
||||||
|
|
||||||
// credit to @sogoiii and @409H for their help!
|
|
||||||
// Return a boolean on whether or not a phish is detected.
|
|
||||||
function isPhish({ hostname, updatedBlacklist = null }) { |
|
||||||
var strCurrentTab = hostname |
|
||||||
|
|
||||||
// check if the domain is part of the whitelist.
|
|
||||||
if (whitelistedDomains && whitelistedDomains.includes(strCurrentTab)) { return false } |
|
||||||
|
|
||||||
// Allow updating of blacklist:
|
|
||||||
if (updatedBlacklist) { |
|
||||||
blacklistedDomains = blacklistedDomains.concat(updatedBlacklist) |
|
||||||
} |
|
||||||
|
|
||||||
// check if the domain is part of the blacklist.
|
|
||||||
const isBlacklisted = blacklistedDomains && blacklistedDomains.includes(strCurrentTab) |
|
||||||
|
|
||||||
// check for similar values.
|
|
||||||
let levenshteinMatched = false |
|
||||||
var levenshteinForm = strCurrentTab.replace(/\./g, '') |
|
||||||
LEVENSHTEIN_CHECKS.forEach((element) => { |
|
||||||
if (levenshtein.get(element, levenshteinForm) <= LEVENSHTEIN_TOLERANCE) { |
|
||||||
levenshteinMatched = true |
|
||||||
} |
|
||||||
}) |
|
||||||
|
|
||||||
return isBlacklisted || levenshteinMatched |
|
||||||
} |
|
||||||
|
|
||||||
module.exports = isPhish |
|
@ -1,9 +1,10 @@ |
|||||||
const promiseToCallback = require('promise-to-callback') |
const promiseToCallback = require('promise-to-callback') |
||||||
|
|
||||||
module.exports = function(fn, context) { |
module.exports = function nodeify (fn, context) { |
||||||
return function(){ |
return function(){ |
||||||
const args = [].slice.call(arguments) |
const args = [].slice.call(arguments) |
||||||
const callback = args.pop() |
const callback = args.pop() |
||||||
|
if (typeof callback !== 'function') throw new Error('callback is not a function') |
||||||
promiseToCallback(fn.apply(context, args))(callback) |
promiseToCallback(fn.apply(context, args))(callback) |
||||||
} |
} |
||||||
} |
} |
||||||
|
@ -0,0 +1,41 @@ |
|||||||
|
const assert = require('assert') |
||||||
|
const BlacklistController = require('../../app/scripts/controllers/blacklist') |
||||||
|
|
||||||
|
describe('blacklist controller', function () { |
||||||
|
let blacklistController |
||||||
|
|
||||||
|
before(() => { |
||||||
|
blacklistController = new BlacklistController() |
||||||
|
}) |
||||||
|
|
||||||
|
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) |
||||||
|
}) |
||||||
|
}) |
||||||
|
}) |
@ -1,24 +0,0 @@ |
|||||||
const assert = require('assert') |
|
||||||
const isPhish = require('../../app/scripts/lib/is-phish') |
|
||||||
|
|
||||||
describe('blacklister', function () { |
|
||||||
describe('#isPhish', function () { |
|
||||||
it('should not flag whitelisted values', function () { |
|
||||||
var result = isPhish({ hostname: 'www.metamask.io' }) |
|
||||||
assert(!result) |
|
||||||
}) |
|
||||||
it('should flag explicit values', function () { |
|
||||||
var result = isPhish({ hostname: 'metamask.com' }) |
|
||||||
assert(result) |
|
||||||
}) |
|
||||||
it('should flag levenshtein values', function () { |
|
||||||
var result = isPhish({ hostname: 'metmask.com' }) |
|
||||||
assert(result) |
|
||||||
}) |
|
||||||
it('should not flag not-even-close values', function () { |
|
||||||
var result = isPhish({ hostname: 'example.com' }) |
|
||||||
assert(!result) |
|
||||||
}) |
|
||||||
}) |
|
||||||
}) |
|
||||||
|
|
Loading…
Reference in new issue