From 9c44ea7dff2986b66a5ef5aa510b62f32940bb0a Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Wed, 2 Mar 2022 16:43:45 +0200 Subject: [PATCH 01/16] Append PhishFort blacklist, whitelist to detection --- src/third-party/PhishingController.test.ts | 20 ++++++++++++++++++-- src/third-party/PhishingController.ts | 21 +++++++++++++++++---- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 78a62858975..33639fccc7f 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -108,6 +108,22 @@ describe('PhishingController', () => { expect(controller.test('xn--myetherallet-4k5fwn.com')).toBe(true); }); + it('should return positive result for unsafe unicode domain from the PhishFort blacklist', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('pancakeswop.net')).toBe(true); + }); + + it('should return negative result for unsafe unicode domain if the PhishFort blacklist returns 304', async () => { + nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) + .get('/gh/phishfort/phishfort-lists@master/blacklists/domains.json') + .reply(304) + .persist(); + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('pancakeswop.net')).toBe(false); + }); + it('should bypass a given domain', () => { const controller = new PhishingController(); const unsafeDomain = 'electrum.mx'; @@ -158,7 +174,7 @@ describe('PhishingController', () => { }); it('should not update phishing lists if fetch returns 304', async () => { - nock('https://cdn.jsdelivr.net') + nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') .reply(304) .persist(); @@ -171,7 +187,7 @@ describe('PhishingController', () => { }); it('should not update phishing lists if fetch returns error', async () => { - nock('https://cdn.jsdelivr.net') + nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') .reply(500) .persist(); diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 83910c172f7..39235fb0846 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -52,8 +52,12 @@ export class PhishingController extends BaseController< PhishingConfig, PhishingState > { - private configUrl = + private configUrlMetaMask = 'https://cdn.jsdelivr.net/gh/MetaMask/eth-phishing-detect@master/src/config.json'; + private configPhishFort = { + whitelistUrl: `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/whitelists/domains.json`, + blacklistUrl: `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/domains.json`, + }; private detector: any; @@ -135,8 +139,17 @@ export class PhishingController extends BaseController< return; } - const phishingOpts = await this.queryConfig(this.configUrl); + const [ phishingOpts, pfWhilelist, pfBlacklist] = await Promise.all([ + this.queryConfig(this.configUrlMetaMask), + this.queryConfig(this.configPhishFort.whitelistUrl), + this.queryConfig(this.configPhishFort.blacklistUrl) + ]).catch(error => { throw error; }); + if (phishingOpts) { + + if (pfWhilelist) phishingOpts.whitelist.push(...pfWhilelist); + if (pfBlacklist) phishingOpts.blacklist.push(...pfBlacklist); + this.detector = new PhishingDetector(phishingOpts); this.update({ phishing: phishingOpts, @@ -144,9 +157,9 @@ export class PhishingController extends BaseController< } } - private async queryConfig( + private async queryConfig( input: RequestInfo, - ): Promise { + ): Promise { const response = await fetch(input, { cache: 'no-cache' }); switch (response.status) { From 07c45c7028e9498a22067c7a9c182a36da1a68c4 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Wed, 2 Mar 2022 16:53:44 +0200 Subject: [PATCH 02/16] Typo fix --- src/third-party/PhishingController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 39235fb0846..33f52e9a336 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -139,7 +139,7 @@ export class PhishingController extends BaseController< return; } - const [ phishingOpts, pfWhilelist, pfBlacklist] = await Promise.all([ + const [ phishingOpts, pfWhitelist, pfBlacklist] = await Promise.all([ this.queryConfig(this.configUrlMetaMask), this.queryConfig(this.configPhishFort.whitelistUrl), this.queryConfig(this.configPhishFort.blacklistUrl) @@ -147,7 +147,7 @@ export class PhishingController extends BaseController< if (phishingOpts) { - if (pfWhilelist) phishingOpts.whitelist.push(...pfWhilelist); + if (pfWhitelist) phishingOpts.whitelist.push(...pfWhitelist); if (pfBlacklist) phishingOpts.blacklist.push(...pfBlacklist); this.detector = new PhishingDetector(phishingOpts); From f98385780ff9dd3aca6f4c21c33f9e081a9c351a Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Mon, 7 Mar 2022 09:40:49 +0200 Subject: [PATCH 03/16] Removed unnecessary list --- src/third-party/PhishingController.ts | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 33f52e9a336..45214a0ce36 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -54,10 +54,8 @@ export class PhishingController extends BaseController< > { private configUrlMetaMask = 'https://cdn.jsdelivr.net/gh/MetaMask/eth-phishing-detect@master/src/config.json'; - private configPhishFort = { - whitelistUrl: `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/whitelists/domains.json`, - blacklistUrl: `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/domains.json`, - }; + + private configUrlPhishFortBlacklist = `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/domains.json`; private detector: any; @@ -139,16 +137,17 @@ export class PhishingController extends BaseController< return; } - const [ phishingOpts, pfWhitelist, pfBlacklist] = await Promise.all([ - this.queryConfig(this.configUrlMetaMask), - this.queryConfig(this.configPhishFort.whitelistUrl), - this.queryConfig(this.configPhishFort.blacklistUrl) - ]).catch(error => { throw error; }); + const phishingOpts = await this.queryConfig( + this.configUrlMetaMask, + ); + const pfBlacklist = await this.queryConfig( + this.configUrlPhishFortBlacklist, + ); if (phishingOpts) { - - if (pfWhitelist) phishingOpts.whitelist.push(...pfWhitelist); - if (pfBlacklist) phishingOpts.blacklist.push(...pfBlacklist); + if (pfBlacklist) { + phishingOpts.blacklist.push(...pfBlacklist); + } this.detector = new PhishingDetector(phishingOpts); this.update({ From c15144b4776006f7ee18e132bb3abacaa20d9bb2 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Tue, 8 Mar 2022 13:57:18 +0200 Subject: [PATCH 04/16] Swapped out blacklist with lighter "hotlist" --- src/third-party/PhishingController.test.ts | 6 +++--- src/third-party/PhishingController.ts | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 33639fccc7f..eab8fbf5ebf 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -111,17 +111,17 @@ describe('PhishingController', () => { it('should return positive result for unsafe unicode domain from the PhishFort blacklist', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('pancakeswop.net')).toBe(true); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toBe(true); }); it('should return negative result for unsafe unicode domain if the PhishFort blacklist returns 304', async () => { nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) - .get('/gh/phishfort/phishfort-lists@master/blacklists/domains.json') + .get('/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json') .reply(304) .persist(); const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('pancakeswop.net')).toBe(false); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toBe(false); }); it('should bypass a given domain', () => { diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 45214a0ce36..98684606941 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -55,7 +55,8 @@ export class PhishingController extends BaseController< private configUrlMetaMask = 'https://cdn.jsdelivr.net/gh/MetaMask/eth-phishing-detect@master/src/config.json'; - private configUrlPhishFortBlacklist = `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/domains.json`; + private configUrlPhishFortHotlist = + `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json`; private detector: any; @@ -141,7 +142,7 @@ export class PhishingController extends BaseController< this.configUrlMetaMask, ); const pfBlacklist = await this.queryConfig( - this.configUrlPhishFortBlacklist, + this.configUrlPhishFortHotlist, ); if (phishingOpts) { From 4b9b38341a451657154d3d2f4d33a3bbfdcf8f35 Mon Sep 17 00:00:00 2001 From: korn101 Date: Tue, 8 Mar 2022 18:01:15 +0200 Subject: [PATCH 05/16] collapse sequential queries --- src/third-party/PhishingController.ts | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 98684606941..b4f8d720f59 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -55,8 +55,7 @@ export class PhishingController extends BaseController< private configUrlMetaMask = 'https://cdn.jsdelivr.net/gh/MetaMask/eth-phishing-detect@master/src/config.json'; - private configUrlPhishFortHotlist = - `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json`; + private configUrlPhishFortHotlist = `https://cdn.jsdelivr.net/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json`; private detector: any; @@ -138,12 +137,10 @@ export class PhishingController extends BaseController< return; } - const phishingOpts = await this.queryConfig( - this.configUrlMetaMask, - ); - const pfBlacklist = await this.queryConfig( - this.configUrlPhishFortHotlist, - ); + const [phishingOpts, pfBlacklist] = await Promise.all([ + await this.queryConfig(this.configUrlMetaMask), + await this.queryConfig(this.configUrlPhishFortHotlist), + ]); if (phishingOpts) { if (pfBlacklist) { From 06c57a9f8604b9b3ebfe82a5e05cbc3c9fd28377 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Thu, 24 Mar 2022 14:31:36 +0200 Subject: [PATCH 06/16] Updated queryConfig, graceful failure of one list. --- src/third-party/PhishingController.test.ts | 13 ++++--- src/third-party/PhishingController.ts | 42 +++++++++++++--------- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index eab8fbf5ebf..a4270354f8f 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -177,6 +177,8 @@ describe('PhishingController', () => { nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') .reply(304) + .get('/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json') + .reply(304) .persist(); const controller = new PhishingController(); const oldState = controller.state.phishing; @@ -186,16 +188,19 @@ describe('PhishingController', () => { expect(controller.state.phishing).toBe(oldState); }); - it('should not update phishing lists if fetch returns error', async () => { + it('should not update phishing lists if fetch returns 500', async () => { nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') .reply(500) + .get('/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json') + .reply(500) .persist(); const controller = new PhishingController(); + const oldState = controller.state.phishing; - await expect(controller.updatePhishingLists()).rejects.toThrow( - /Fetch failed with status '500'/u, - ); + await controller.updatePhishingLists(); + + expect(controller.state.phishing).toBe(oldState); }); }); diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index b4f8d720f59..439f22b9730 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -137,21 +137,37 @@ export class PhishingController extends BaseController< return; } - const [phishingOpts, pfBlacklist] = await Promise.all([ + const [metamaskConfig, phishfortHotlist] = await Promise.all([ await this.queryConfig(this.configUrlMetaMask), await this.queryConfig(this.configUrlPhishFortHotlist), ]); - if (phishingOpts) { - if (pfBlacklist) { - phishingOpts.blacklist.push(...pfBlacklist); - } - this.detector = new PhishingDetector(phishingOpts); - this.update({ - phishing: phishingOpts, - }); + if (!metamaskConfig && !phishfortHotlist) { + return; + } + + // Default config populated with values from eth-phishing-detect@master on 2022/03/24. + const phishingOpts: EthPhishingResponse = metamaskConfig || { + version: 2, + tolerance: 2, + blacklist: [], + fuzzylist: [], + whitelist: [] + }; + + if (phishfortHotlist) { + // Removal of duplicates. + const phishfortHotlistUnique = phishfortHotlist.filter( + (hotlistItem) => !phishingOpts.blacklist.includes(hotlistItem), + ); + phishingOpts.blacklist.push(...phishfortHotlistUnique); } + + this.detector = new PhishingDetector(phishingOpts); + this.update({ + phishing: phishingOpts, + }); } private async queryConfig( @@ -163,15 +179,9 @@ export class PhishingController extends BaseController< case 200: { return await response.json(); } - case 304: - case 403: { - return null; - } default: { - throw new Error( - `Fetch failed with status '${response.status}' for request '${input}'`, - ); + return null; } } } From 6b761b8954580fe35153210d0f25acc731ed4f4d Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Thu, 21 Apr 2022 08:59:30 +0200 Subject: [PATCH 07/16] Updated eth-phishing-detect to v1.2 --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 1adfcc30947..839d2bbd9b5 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "eth-json-rpc-infura": "^5.1.0", "eth-keyring-controller": "^6.2.1", "eth-method-registry": "1.1.0", - "eth-phishing-detect": "^1.1.16", + "eth-phishing-detect": "^1.2.0", "eth-query": "^2.1.2", "eth-rpc-errors": "^4.0.0", "eth-sig-util": "^3.0.0", diff --git a/yarn.lock b/yarn.lock index d85e4ccf2ac..7a4c711a7a1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3375,10 +3375,10 @@ eth-method-registry@1.1.0: dependencies: ethjs "^0.3.0" -eth-phishing-detect@^1.1.16: - version "1.1.16" - resolved "https://registry.yarnpkg.com/eth-phishing-detect/-/eth-phishing-detect-1.1.16.tgz#637158d5774819e1a861f6d169e6d77d076a47fd" - integrity sha512-/o9arK5qFOKVdfZK9hJVAQP0eKXjAvImIKNBMfF9Nj1HGicD3wfsVuXDu1OHrxuEi6+4kYtD9wyAn/3G7g7VrA== +eth-phishing-detect@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eth-phishing-detect/-/eth-phishing-detect-1.2.0.tgz#11b357776b2d1b98a9ac594a1343e5184fc26bf0" + integrity sha512-+M7D4dhu5tkSA9b5eiBwDeJCjwy+7Lv49nuTEw8fNZIZUAVZC3d2XHatBq1MOW7J8kxNGbBdgBuIf65opI7Tkg== dependencies: fast-levenshtein "^2.0.6" From 249f7e80fce2068a6eb6701a7214fa174e19bc24 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Thu, 21 Apr 2022 09:53:54 +0200 Subject: [PATCH 08/16] Add config interface, shaping of configs. --- src/third-party/PhishingController.ts | 67 +++++++++++++++++++-------- 1 file changed, 48 insertions(+), 19 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 88de2d62813..51d1d385e33 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -23,6 +23,24 @@ export interface EthPhishingResponse { whitelist: string[]; } +/** + * @type EthPhishingDetectConfig + * + * Interface defining expected input to PhishingDetector. + * @property allowlist - List of approved origins (legacy naming "whitelist") + * @property blocklist - List of unapproved origins (legacy naming "blacklist") + * @property fuzzylist - List of fuzzy-matched unapproved origins + * @property tolerance - Fuzzy match tolerance level + */ +export interface EthPhishingDetectConfig { + allowlist: string[]; + blocklist: string[]; + fuzzylist: string[]; + tolerance: number; + name: string; + version: number; +} + /** * @type PhishingConfig * @@ -41,7 +59,7 @@ export interface PhishingConfig extends BaseConfig { * @property whitelist - array of temporarily-approved origins */ export interface PhishingState extends BaseState { - phishing: EthPhishingResponse; + phishing: EthPhishingDetectConfig[]; whitelist: string[]; } @@ -137,36 +155,47 @@ export class PhishingController extends BaseController< return; } - const [metamaskConfig, phishfortHotlist] = await Promise.all([ + const configs: EthPhishingDetectConfig[] = []; + + const [metamaskConfigLegacy, phishfortHotlist] = await Promise.all([ await this.queryConfig(this.configUrlMetaMask), await this.queryConfig(this.configUrlPhishFortHotlist), ]); - - if (!metamaskConfig && !phishfortHotlist) { - return; + // Correctly shaping MetaMask config. + const metamaskConfig: EthPhishingDetectConfig = { + allowlist: metamaskConfigLegacy ? metamaskConfigLegacy.whitelist : [], + blocklist: metamaskConfigLegacy ? metamaskConfigLegacy.blacklist : [], + fuzzylist: metamaskConfigLegacy ? metamaskConfigLegacy.fuzzylist : [], + tolerance: metamaskConfigLegacy ? metamaskConfigLegacy.tolerance : 0, + name: `MetaMask`, + version: metamaskConfigLegacy ? metamaskConfigLegacy.version : 0, + }; + if (metamaskConfigLegacy) { + configs.push(metamaskConfig); } - // Default config populated with values from eth-phishing-detect@master on 2022/03/24. - const phishingOpts: EthPhishingResponse = metamaskConfig || { - version: 2, - tolerance: 2, - blacklist: [], + // Correctly shaping PhishFort config. + const phishfortConfig: EthPhishingDetectConfig = { + allowlist: [], + blocklist: (phishfortHotlist || []).filter(i => !metamaskConfig.blocklist.includes(i)), // Removal of duplicates. fuzzylist: [], - whitelist: [] + tolerance: 0, + name: `PhishFort`, + version: 1 }; - if (phishfortHotlist) { - // Removal of duplicates. - const phishfortHotlistUnique = phishfortHotlist.filter( - (hotlistItem) => !phishingOpts.blacklist.includes(hotlistItem), - ); - phishingOpts.blacklist.push(...phishfortHotlistUnique); + configs.push(phishfortConfig); + } + + // Do not update if all configs are unavailable. + if (!configs.length) { + return; } - this.detector = new PhishingDetector(phishingOpts); + this.detector = new PhishingDetector(configs); this.update({ - phishing: phishingOpts, + phishing: configs, }); } From 5fa6859e7c39d77b93344ee599d7759bdca0f125 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Thu, 21 Apr 2022 09:54:20 +0200 Subject: [PATCH 09/16] Updated tests for multiple configs --- src/third-party/PhishingController.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index a4270354f8f..407e86dda07 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -52,10 +52,14 @@ describe('PhishingController', () => { const controller = new PhishingController(); controller.update({}, true); await controller.updatePhishingLists(); - expect(controller.state.phishing).toHaveProperty('blacklist'); - expect(controller.state.phishing).toHaveProperty('fuzzylist'); - expect(controller.state.phishing).toHaveProperty('version'); - expect(controller.state.phishing).toHaveProperty('whitelist'); + controller.state.phishing.forEach((config) => { + expect(config).toHaveProperty('allowlist'); + expect(config).toHaveProperty('blocklist'); + expect(config).toHaveProperty('fuzzylist'); + expect(config).toHaveProperty('tolerance'); + expect(config).toHaveProperty('name'); + expect(config).toHaveProperty('version'); + }); }); it('should not update infura rate if disabled', async () => { From ba7a50831fed18f3091c66f0db490b324d780604 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Fri, 22 Apr 2022 18:58:20 +0200 Subject: [PATCH 10/16] Return EthPhishingDetectResult from check(...) --- src/third-party/PhishingController.test.ts | 32 +++++++++++----------- src/third-party/PhishingController.ts | 27 +++++++++++++++--- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 407e86dda07..5652ce70572 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -84,38 +84,38 @@ describe('PhishingController', () => { it('should return negative result for safe domain', () => { const controller = new PhishingController(); - expect(controller.test('metamask.io')).toBe(false); + expect(controller.test('metamask.io').result).toBe(false); }); it('should return negative result for safe unicode domain', () => { const controller = new PhishingController(); - expect(controller.test('i❤.ws')).toBe(false); + expect(controller.test('i❤.ws').result).toBe(false); }); it('should return negative result for safe punycode domain', () => { const controller = new PhishingController(); - expect(controller.test('xn--i-7iq.ws')).toBe(false); + expect(controller.test('xn--i-7iq.ws').result).toBe(false); }); it('should return positive result for unsafe domain', () => { const controller = new PhishingController(); - expect(controller.test('etnerscan.io')).toBe(true); + expect(controller.test('etnerscan.io').result).toBe(true); }); it('should return positive result for unsafe unicode domain', () => { const controller = new PhishingController(); - expect(controller.test('myetherẉalletṭ.com')).toBe(true); + expect(controller.test('myetherẉalletṭ.com').result).toBe(true); }); it('should return positive result for unsafe punycode domain', () => { const controller = new PhishingController(); - expect(controller.test('xn--myetherallet-4k5fwn.com')).toBe(true); + expect(controller.test('xn--myetherallet-4k5fwn.com').result).toBe(true); }); it('should return positive result for unsafe unicode domain from the PhishFort blacklist', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toBe(true); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com').result).toBe(true); }); it('should return negative result for unsafe unicode domain if the PhishFort blacklist returns 304', async () => { @@ -125,56 +125,56 @@ describe('PhishingController', () => { .persist(); const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toBe(false); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com').result).toBe(false); }); it('should bypass a given domain', () => { const controller = new PhishingController(); const unsafeDomain = 'electrum.mx'; assert.equal( - controller.test(unsafeDomain), + controller.test(unsafeDomain).result, true, 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toBe(false); + expect(controller.test(unsafeDomain).result).toBe(false); }); it('should ignore second attempt to bypass a domain', () => { const controller = new PhishingController(); const unsafeDomain = 'electrum.mx'; assert.equal( - controller.test(unsafeDomain), + controller.test(unsafeDomain).result, true, 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toBe(false); + expect(controller.test(unsafeDomain).result).toBe(false); }); it('should bypass a given unicode domain', () => { const controller = new PhishingController(); const unsafeDomain = 'myetherẉalletṭ.com'; assert.equal( - controller.test(unsafeDomain), + controller.test(unsafeDomain).result, true, 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toBe(false); + expect(controller.test(unsafeDomain).result).toBe(false); }); it('should bypass a given punycode domain', () => { const controller = new PhishingController(); const unsafeDomain = 'xn--myetherallet-4k5fwn.com'; assert.equal( - controller.test(unsafeDomain), + controller.test(unsafeDomain).result, true, 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toBe(false); + expect(controller.test(unsafeDomain).result).toBe(false); }); it('should not update phishing lists if fetch returns 304', async () => { diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 51d1d385e33..cdf8b737f41 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -41,6 +41,23 @@ export interface EthPhishingDetectConfig { version: number; } +/** + * @type EthPhishingDetectResult + * + * Interface that describes the result of . + * @property name - Name of the config on which a match was found. Not returned when using legacy config. + * @property version - Version of the config on which a match was found. Not returned when using legacy config. + * @property result - Whether a domain was detected as a phishing domain. True means an unsafe domain. + * @property type - The field of the config on which a match was found. 'whitelist' and 'blacklist' can be returned when using legacy config. + */ +export interface EthPhishingDetectResult { + name?: string; // Not returned for legacy config. + version?: string; // Not returned for legacy config. + result: boolean; + type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist' | 'whitelist' | 'blacklist'; +} + + /** * @type PhishingConfig * @@ -125,12 +142,12 @@ export class PhishingController extends BaseController< * @param origin - Domain origin of a website. * @returns Whether the origin is an unapproved origin. */ - test(origin: string): boolean { + test(origin: string): EthPhishingDetectResult { const punycodeOrigin = toASCII(origin); if (this.state.whitelist.indexOf(punycodeOrigin) !== -1) { - return false; + return { result: false, type: 'all' }; // Same as whitelisted match returned by detector.check(...). } - return this.detector.check(punycodeOrigin).result; + return this.detector.check(punycodeOrigin); } /** @@ -178,7 +195,9 @@ export class PhishingController extends BaseController< // Correctly shaping PhishFort config. const phishfortConfig: EthPhishingDetectConfig = { allowlist: [], - blocklist: (phishfortHotlist || []).filter(i => !metamaskConfig.blocklist.includes(i)), // Removal of duplicates. + blocklist: (phishfortHotlist || []).filter( + (i) => !metamaskConfig.blocklist.includes(i), + ), // Removal of duplicates. fuzzylist: [], tolerance: 0, name: `PhishFort`, From 259e3fd35aeb42dbe972945675ad4731f903f75b Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Mon, 25 Apr 2022 13:29:19 +0200 Subject: [PATCH 11/16] Tests: 'type' & 'name' checks, fuzzy & legacy cnf. --- src/third-party/PhishingController.test.ts | 203 ++++++++++++++++++--- src/third-party/PhishingController.ts | 2 + 2 files changed, 179 insertions(+), 26 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 5652ce70572..5ad6dcf461b 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -1,7 +1,7 @@ import { strict as assert } from 'assert'; import { stub } from 'sinon'; import nock from 'nock'; -import { PhishingController } from './PhishingController'; +import { EthPhishingDetectResult, PhishingController } from './PhishingController'; describe('PhishingController', () => { afterEach(() => { @@ -82,53 +82,192 @@ describe('PhishingController', () => { expect(async () => await controller.updatePhishingLists()).not.toThrow(); }); - it('should return negative result for safe domain', () => { + it('should return negative result for safe domain from legacy config', () => { const controller = new PhishingController(); - expect(controller.test('metamask.io').result).toBe(false); + expect(controller.test('metamask.io')).toMatchObject({ + result: false, + type: 'whitelist', + }); + }); + + it('should return negative result for safe unicode domain from legacy config', () => { + const controller = new PhishingController(); + expect(controller.test('i❤.ws')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return negative result for safe punycode domain from legacy config', () => { + const controller = new PhishingController(); + expect(controller.test('xn--i-7iq.ws')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return positive result for unsafe domain from legacy config', () => { + const controller = new PhishingController(); + expect(controller.test('etnerscan.io')).toMatchObject({ + result: true, + type: 'blacklist', + }); }); - it('should return negative result for safe unicode domain', () => { + it('should return positive result for unsafe unicode domain from legacy config', () => { const controller = new PhishingController(); - expect(controller.test('i❤.ws').result).toBe(false); + expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + result: true, + type: 'blacklist', + }); }); - it('should return negative result for safe punycode domain', () => { + it('should return positive result for unsafe punycode domain from legacy config', () => { const controller = new PhishingController(); - expect(controller.test('xn--i-7iq.ws').result).toBe(false); + expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ + result: true, + type: 'blacklist', + }); }); - it('should return positive result for unsafe domain', () => { + it('should return negative result for safe domain from MetaMask config', async () => { const controller = new PhishingController(); - expect(controller.test('etnerscan.io').result).toBe(true); + await controller.updatePhishingLists(); + expect(controller.test('metamask.io')).toMatchObject({ + result: false, + type: 'allowlist', + name: 'MetaMask', + }); }); - it('should return positive result for unsafe unicode domain', () => { + it('should return negative result for safe unicode domain from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('i❤.ws')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return negative result for safe punycode domain from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('xn--i-7iq.ws')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return positive result for unsafe domain from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('etnerscan.io')).toMatchObject({ + result: true, + type: 'blocklist', + name: 'MetaMask', + }); + }); + + it('should return positive result for unsafe unicode domain from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + result: true, + type: 'blocklist', + name: 'MetaMask', + }); + }); + + it('should return negative result for unsafe unicode domain if the MetaMask config returns 500', async () => { + nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) + .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') + .reply(500) + .persist(); const controller = new PhishingController(); - expect(controller.test('myetherẉalletṭ.com').result).toBe(true); + await controller.updatePhishingLists(); + expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + result: false, + type: 'all', + }); }); - it('should return positive result for unsafe punycode domain', () => { + it('should return positive result for unsafe punycode domain from MetaMask config', async () => { const controller = new PhishingController(); - expect(controller.test('xn--myetherallet-4k5fwn.com').result).toBe(true); + await controller.updatePhishingLists(); + expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ + result: true, + type: 'blocklist', + name: 'MetaMask', + }); }); - it('should return positive result for unsafe unicode domain from the PhishFort blacklist', async () => { + it('should return positive result for unsafe unicode domain from the PhishFort hotlist (blocklist)', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com').result).toBe(true); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toMatchObject({ + result: true, + type: 'blocklist', + name: 'PhishFort', + }); }); - it('should return negative result for unsafe unicode domain if the PhishFort blacklist returns 304', async () => { + it('should return negative result for unsafe unicode domain if the PhishFort hotlist (blocklist) returns 500', async () => { nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) .get('/gh/phishfort/phishfort-lists@master/blacklists/hotlist.json') - .reply(304) + .reply(500) .persist(); const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com').result).toBe(false); + expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return negative result for safe fuzzylist domain from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('opensea.io')).toMatchObject({ + result: false, + type: 'allowlist', + name: 'MetaMask', + }); }); - it('should bypass a given domain', () => { + it('should return positive result for domain very close to fuzzylist from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('ohpensea.io')).toMatchObject({ + result: true, + type: 'fuzzy', + name: 'MetaMask', + }); + }); + + it('should return negative result for domain very close to fuzzylist if MetaMask config returns 500', async () => { + nock('https://cdn.jsdelivr.net', { allowUnmocked: true }) + .get('/gh/MetaMask/eth-phishing-detect@master/src/config.json') + .reply(500) + .persist(); + + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('ohpensea.io')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should return negative result for domain not very close to fuzzylist from MetaMask config', async () => { + const controller = new PhishingController(); + await controller.updatePhishingLists(); + expect(controller.test('this-is-the-official-website-of-opensea.io')).toMatchObject({ + result: false, + type: 'all', + }); + }); + + it('should bypass a given domain, and return a negative result', () => { const controller = new PhishingController(); const unsafeDomain = 'electrum.mx'; assert.equal( @@ -137,10 +276,13 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain).result).toBe(false); + expect(controller.test(unsafeDomain)).toMatchObject({ + result: false, + type: 'all', + }); }); - it('should ignore second attempt to bypass a domain', () => { + it('should ignore second attempt to bypass a domain, and still return a negative result', () => { const controller = new PhishingController(); const unsafeDomain = 'electrum.mx'; assert.equal( @@ -150,10 +292,13 @@ describe('PhishingController', () => { ); controller.bypass(unsafeDomain); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain).result).toBe(false); + expect(controller.test(unsafeDomain)).toMatchObject({ + result: false, + type: 'all', + }); }); - it('should bypass a given unicode domain', () => { + it('should bypass a given unicode domain, and return a negative result', () => { const controller = new PhishingController(); const unsafeDomain = 'myetherẉalletṭ.com'; assert.equal( @@ -162,10 +307,13 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain).result).toBe(false); + expect(controller.test(unsafeDomain)).toMatchObject({ + result: false, + type: 'all', + }); }); - it('should bypass a given punycode domain', () => { + it('should bypass a given punycode domain, and return a negative result', () => { const controller = new PhishingController(); const unsafeDomain = 'xn--myetherallet-4k5fwn.com'; assert.equal( @@ -174,7 +322,10 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain).result).toBe(false); + expect(controller.test(unsafeDomain)).toMatchObject({ + result: false, + type: 'all', + }); }); it('should not update phishing lists if fetch returns 304', async () => { diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index cdf8b737f41..b73e111db5a 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -48,12 +48,14 @@ export interface EthPhishingDetectConfig { * @property name - Name of the config on which a match was found. Not returned when using legacy config. * @property version - Version of the config on which a match was found. Not returned when using legacy config. * @property result - Whether a domain was detected as a phishing domain. True means an unsafe domain. + * @property match - A string containing the fuzzylist detection. Returned sa undefined for non-fuzzy true results. * @property type - The field of the config on which a match was found. 'whitelist' and 'blacklist' can be returned when using legacy config. */ export interface EthPhishingDetectResult { name?: string; // Not returned for legacy config. version?: string; // Not returned for legacy config. result: boolean; + match?: string; // Returned as undefined for non-fuzzy true results. type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist' | 'whitelist' | 'blacklist'; } From fe99e5dddbb705e82209252fde83b29055b2a0e0 Mon Sep 17 00:00:00 2001 From: moosthuizen42 <36568323+moosthuizen42@users.noreply.github.com> Date: Mon, 25 Apr 2022 18:46:43 +0200 Subject: [PATCH 12/16] Update src/third-party/PhishingController.ts Co-authored-by: Mark Stacey --- src/third-party/PhishingController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index b73e111db5a..4f8a9286487 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -48,7 +48,7 @@ export interface EthPhishingDetectConfig { * @property name - Name of the config on which a match was found. Not returned when using legacy config. * @property version - Version of the config on which a match was found. Not returned when using legacy config. * @property result - Whether a domain was detected as a phishing domain. True means an unsafe domain. - * @property match - A string containing the fuzzylist detection. Returned sa undefined for non-fuzzy true results. + * @property match - The matching fuzzylist origin when a fuzzylist match is found. Returned as undefined for non-fuzzy true results. * @property type - The field of the config on which a match was found. 'whitelist' and 'blacklist' can be returned when using legacy config. */ export interface EthPhishingDetectResult { From d29e6c73c59ac682460e042098e7b6e89e52e650 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Mon, 25 Apr 2022 19:07:40 +0200 Subject: [PATCH 13/16] Updated default config & related tests --- src/third-party/PhishingController.test.ts | 36 +++++++++++++--------- src/third-party/PhishingController.ts | 10 +++++- 2 files changed, 31 insertions(+), 15 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 5ad6dcf461b..294b118b5d8 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -10,10 +10,14 @@ describe('PhishingController', () => { it('should set default state', () => { const controller = new PhishingController(); - expect(controller.state.phishing).toHaveProperty('blacklist'); - expect(controller.state.phishing).toHaveProperty('fuzzylist'); - expect(controller.state.phishing).toHaveProperty('version'); - expect(controller.state.phishing).toHaveProperty('whitelist'); + controller.state.phishing.forEach((i) => { + expect(i).toHaveProperty('allowlist'); + expect(i).toHaveProperty('blocklist'); + expect(i).toHaveProperty('fuzzylist'); + expect(i).toHaveProperty('tolerance'); + expect(i).toHaveProperty('name'); + expect(i).toHaveProperty('version'); + }); }); it('should set default config', () => { @@ -82,15 +86,16 @@ describe('PhishingController', () => { expect(async () => await controller.updatePhishingLists()).not.toThrow(); }); - it('should return negative result for safe domain from legacy config', () => { + it('should return negative result for safe domain from default config', () => { const controller = new PhishingController(); expect(controller.test('metamask.io')).toMatchObject({ result: false, - type: 'whitelist', + type: 'allowlist', + name: 'MetaMask', }); }); - it('should return negative result for safe unicode domain from legacy config', () => { + it('should return negative result for safe unicode domain from default config', () => { const controller = new PhishingController(); expect(controller.test('i❤.ws')).toMatchObject({ result: false, @@ -98,7 +103,7 @@ describe('PhishingController', () => { }); }); - it('should return negative result for safe punycode domain from legacy config', () => { + it('should return negative result for safe punycode domain from default config', () => { const controller = new PhishingController(); expect(controller.test('xn--i-7iq.ws')).toMatchObject({ result: false, @@ -106,27 +111,30 @@ describe('PhishingController', () => { }); }); - it('should return positive result for unsafe domain from legacy config', () => { + it('should return positive result for unsafe domain from default config', () => { const controller = new PhishingController(); expect(controller.test('etnerscan.io')).toMatchObject({ result: true, - type: 'blacklist', + type: 'blocklist', + name: 'MetaMask', }); }); - it('should return positive result for unsafe unicode domain from legacy config', () => { + it('should return positive result for unsafe unicode domain from default config', () => { const controller = new PhishingController(); expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ result: true, - type: 'blacklist', + type: 'blocklist', + name: 'MetaMask', }); }); - it('should return positive result for unsafe punycode domain from legacy config', () => { + it('should return positive result for unsafe punycode domain from default config', () => { const controller = new PhishingController(); expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ result: true, - type: 'blacklist', + type: 'blocklist', + name: `MetaMask`, }); }); diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index 4f8a9286487..a9b8682db93 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -113,10 +113,18 @@ export class PhishingController extends BaseController< config?: Partial, state?: Partial, ) { + super(config, state); this.defaultConfig = { interval: 60 * 60 * 1000 }; this.defaultState = { - phishing: DEFAULT_PHISHING_RESPONSE, + phishing: [{ + allowlist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).whitelist, + blocklist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).blacklist, + fuzzylist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).fuzzylist, + tolerance: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).tolerance, + name: `MetaMask`, + version: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).version + }], whitelist: [], }; this.detector = new PhishingDetector(this.defaultState.phishing); From f90d7e7485b62eb84b02823f6b0b12a6d6095edf Mon Sep 17 00:00:00 2001 From: moosthuizen42 <36568323+moosthuizen42@users.noreply.github.com> Date: Tue, 26 Apr 2022 10:08:27 +0200 Subject: [PATCH 14/16] Update src/third-party/PhishingController.ts Co-authored-by: Mark Stacey --- src/third-party/PhishingController.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index a9b8682db93..b1e3f86799c 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -44,19 +44,19 @@ export interface EthPhishingDetectConfig { /** * @type EthPhishingDetectResult * - * Interface that describes the result of . - * @property name - Name of the config on which a match was found. Not returned when using legacy config. - * @property version - Version of the config on which a match was found. Not returned when using legacy config. + * Interface that describes the result of the `test` method. + * @property name - Name of the config on which a match was found. + * @property version - Version of the config on which a match was found. * @property result - Whether a domain was detected as a phishing domain. True means an unsafe domain. * @property match - The matching fuzzylist origin when a fuzzylist match is found. Returned as undefined for non-fuzzy true results. - * @property type - The field of the config on which a match was found. 'whitelist' and 'blacklist' can be returned when using legacy config. + * @property type - The field of the config on which a match was found. */ export interface EthPhishingDetectResult { - name?: string; // Not returned for legacy config. - version?: string; // Not returned for legacy config. + name: string; + version: string; result: boolean; match?: string; // Returned as undefined for non-fuzzy true results. - type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist' | 'whitelist' | 'blacklist'; + type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist'; } From f33c835a379d1d2654f9de83e99b128b3968bb57 Mon Sep 17 00:00:00 2001 From: moosthuizen42 <36568323+moosthuizen42@users.noreply.github.com> Date: Tue, 26 Apr 2022 16:56:42 +0200 Subject: [PATCH 15/16] Update src/third-party/PhishingController.ts Co-authored-by: Mark Stacey --- src/third-party/PhishingController.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index b1e3f86799c..ac77d13eeba 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -52,8 +52,8 @@ export interface EthPhishingDetectConfig { * @property type - The field of the config on which a match was found. */ export interface EthPhishingDetectResult { - name: string; - version: string; + name?: string; + version?: string; result: boolean; match?: string; // Returned as undefined for non-fuzzy true results. type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist'; From f6a62a9a13997b65327e8bc9fe97b81aef6a5024 Mon Sep 17 00:00:00 2001 From: Michael Oosthuizen Date: Thu, 28 Apr 2022 14:46:51 +0200 Subject: [PATCH 16/16] Linting --- src/third-party/PhishingController.test.ts | 89 ++++++++++++++++------ src/third-party/PhishingController.ts | 28 ++++--- 2 files changed, 83 insertions(+), 34 deletions(-) diff --git a/src/third-party/PhishingController.test.ts b/src/third-party/PhishingController.test.ts index 844c0c4f0d5..a1a9f9ab06f 100644 --- a/src/third-party/PhishingController.test.ts +++ b/src/third-party/PhishingController.test.ts @@ -1,7 +1,10 @@ import { strict as assert } from 'assert'; import sinon from 'sinon'; import nock from 'nock'; -import { EthPhishingDetectResult, PhishingController } from './PhishingController'; +import { + EthPhishingDetectResult, + PhishingController, +} from './PhishingController'; describe('PhishingController', () => { afterEach(() => { @@ -90,7 +93,9 @@ describe('PhishingController', () => { it('should return negative result for safe domain from default config', () => { const controller = new PhishingController(); - expect(controller.test('metamask.io')).toMatchObject({ + expect( + controller.test('metamask.io'), + ).toMatchObject({ result: false, type: 'allowlist', name: 'MetaMask', @@ -107,7 +112,9 @@ describe('PhishingController', () => { it('should return negative result for safe punycode domain from default config', () => { const controller = new PhishingController(); - expect(controller.test('xn--i-7iq.ws')).toMatchObject({ + expect( + controller.test('xn--i-7iq.ws'), + ).toMatchObject({ result: false, type: 'all', }); @@ -115,7 +122,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe domain from default config', () => { const controller = new PhishingController(); - expect(controller.test('etnerscan.io')).toMatchObject({ + expect( + controller.test('etnerscan.io'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'MetaMask', @@ -124,7 +133,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe unicode domain from default config', () => { const controller = new PhishingController(); - expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + expect( + controller.test('myetherẉalletṭ.com'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'MetaMask', @@ -133,7 +144,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe punycode domain from default config', () => { const controller = new PhishingController(); - expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ + expect( + controller.test('xn--myetherallet-4k5fwn.com'), + ).toMatchObject({ result: true, type: 'blocklist', name: `MetaMask`, @@ -143,7 +156,9 @@ describe('PhishingController', () => { it('should return negative result for safe domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('metamask.io')).toMatchObject({ + expect( + controller.test('metamask.io'), + ).toMatchObject({ result: false, type: 'allowlist', name: 'MetaMask', @@ -162,7 +177,9 @@ describe('PhishingController', () => { it('should return negative result for safe punycode domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('xn--i-7iq.ws')).toMatchObject({ + expect( + controller.test('xn--i-7iq.ws'), + ).toMatchObject({ result: false, type: 'all', }); @@ -171,7 +188,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('etnerscan.io')).toMatchObject({ + expect( + controller.test('etnerscan.io'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'MetaMask', @@ -181,7 +200,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe unicode domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + expect( + controller.test('myetherẉalletṭ.com'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'MetaMask', @@ -195,7 +216,9 @@ describe('PhishingController', () => { .persist(); const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ + expect( + controller.test('myetherẉalletṭ.com'), + ).toMatchObject({ result: false, type: 'all', }); @@ -204,7 +227,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe punycode domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ + expect( + controller.test('xn--myetherallet-4k5fwn.com'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'MetaMask', @@ -214,7 +239,9 @@ describe('PhishingController', () => { it('should return positive result for unsafe unicode domain from the PhishFort hotlist (blocklist)', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toMatchObject({ + expect( + controller.test('e4d600ab9141b7a9859511c77e63b9b3.com'), + ).toMatchObject({ result: true, type: 'blocklist', name: 'PhishFort', @@ -228,7 +255,9 @@ describe('PhishingController', () => { .persist(); const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('e4d600ab9141b7a9859511c77e63b9b3.com')).toMatchObject({ + expect( + controller.test('e4d600ab9141b7a9859511c77e63b9b3.com'), + ).toMatchObject({ result: false, type: 'all', }); @@ -237,7 +266,9 @@ describe('PhishingController', () => { it('should return negative result for safe fuzzylist domain from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('opensea.io')).toMatchObject({ + expect( + controller.test('opensea.io'), + ).toMatchObject({ result: false, type: 'allowlist', name: 'MetaMask', @@ -247,7 +278,9 @@ describe('PhishingController', () => { it('should return positive result for domain very close to fuzzylist from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('ohpensea.io')).toMatchObject({ + expect( + controller.test('ohpensea.io'), + ).toMatchObject({ result: true, type: 'fuzzy', name: 'MetaMask', @@ -262,7 +295,9 @@ describe('PhishingController', () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('ohpensea.io')).toMatchObject({ + expect( + controller.test('ohpensea.io'), + ).toMatchObject({ result: false, type: 'all', }); @@ -271,7 +306,9 @@ describe('PhishingController', () => { it('should return negative result for domain not very close to fuzzylist from MetaMask config', async () => { const controller = new PhishingController(); await controller.updatePhishingLists(); - expect(controller.test('this-is-the-official-website-of-opensea.io')).toMatchObject({ + expect( + controller.test('this-is-the-official-website-of-opensea.io'), + ).toMatchObject({ result: false, type: 'all', }); @@ -286,7 +323,9 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toMatchObject({ + expect( + controller.test(unsafeDomain), + ).toMatchObject({ result: false, type: 'all', }); @@ -302,7 +341,9 @@ describe('PhishingController', () => { ); controller.bypass(unsafeDomain); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toMatchObject({ + expect( + controller.test(unsafeDomain), + ).toMatchObject({ result: false, type: 'all', }); @@ -317,7 +358,9 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toMatchObject({ + expect( + controller.test(unsafeDomain), + ).toMatchObject({ result: false, type: 'all', }); @@ -332,7 +375,9 @@ describe('PhishingController', () => { 'Example unsafe domain seems to be safe', ); controller.bypass(unsafeDomain); - expect(controller.test(unsafeDomain)).toMatchObject({ + expect( + controller.test(unsafeDomain), + ).toMatchObject({ result: false, type: 'all', }); diff --git a/src/third-party/PhishingController.ts b/src/third-party/PhishingController.ts index ac77d13eeba..980d14bd2bc 100644 --- a/src/third-party/PhishingController.ts +++ b/src/third-party/PhishingController.ts @@ -55,11 +55,10 @@ export interface EthPhishingDetectResult { name?: string; version?: string; result: boolean; - match?: string; // Returned as undefined for non-fuzzy true results. + match?: string; // Returned as undefined for non-fuzzy true results. type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist'; } - /** * @type PhishingConfig * @@ -113,18 +112,23 @@ export class PhishingController extends BaseController< config?: Partial, state?: Partial, ) { - super(config, state); this.defaultConfig = { interval: 60 * 60 * 1000 }; this.defaultState = { - phishing: [{ - allowlist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).whitelist, - blocklist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).blacklist, - fuzzylist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).fuzzylist, - tolerance: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).tolerance, - name: `MetaMask`, - version: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).version - }], + phishing: [ + { + allowlist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse) + .whitelist, + blocklist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse) + .blacklist, + fuzzylist: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse) + .fuzzylist, + tolerance: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse) + .tolerance, + name: `MetaMask`, + version: (DEFAULT_PHISHING_RESPONSE as EthPhishingResponse).version, + }, + ], whitelist: [], }; this.detector = new PhishingDetector(this.defaultState.phishing); @@ -211,7 +215,7 @@ export class PhishingController extends BaseController< fuzzylist: [], tolerance: 0, name: `PhishFort`, - version: 1 + version: 1, }; if (phishfortHotlist) { configs.push(phishfortConfig);