From 2115cdd8b58be366b3b1675c92e0d697f83ff72b Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Fri, 22 Sep 2023 17:39:41 +0200 Subject: [PATCH 1/5] migrate `PhishingController` to BaseControllerV2 --- .../src/PhishingController.test.ts | 347 ++++++++++-------- .../src/PhishingController.ts | 208 +++++++---- 2 files changed, 319 insertions(+), 236 deletions(-) diff --git a/packages/phishing-controller/src/PhishingController.test.ts b/packages/phishing-controller/src/PhishingController.test.ts index 0950c77381..3af5c2b4d6 100644 --- a/packages/phishing-controller/src/PhishingController.test.ts +++ b/packages/phishing-controller/src/PhishingController.test.ts @@ -8,33 +8,62 @@ import { METAMASK_STALELIST_FILE, PhishingController, PHISHING_CONFIG_BASE_URL, + PhishingControllerActions, + PhishingControllerOptions, } from './PhishingController'; +import { ControllerMessenger } from '@metamask/base-controller'; const defaultHotlistRefreshInterval = 30 * 60; const defaultStalelistRefreshInterval = 4 * 24 * 60 * 60; +const controllerName = 'PhishingController'; + +function getRestrictedMessenger() { + const controllerMessenger = new ControllerMessenger< + PhishingControllerActions, + never + >(); + + const messenger = controllerMessenger.getRestricted< + typeof controllerName, + never, + never + >({ + name: 'PhishingController', + }); + + return messenger; +} + +function getPhishingController(options?: Partial) { + return new PhishingController({ + messenger: getRestrictedMessenger(), + ...options, + }); +} + describe('PhishingController', () => { afterEach(() => { sinon.restore(); }); it('should have no default phishing lists', () => { - const controller = new PhishingController(); + const controller = getPhishingController(); expect(controller.state.phishingLists).toStrictEqual([]); }); it('should default to an empty whitelist', () => { - const controller = new PhishingController(); + const controller = getPhishingController(); expect(controller.state.whitelist).toStrictEqual([]); }); - it('should use default stalelist & hotlist refresh intervals', () => { - const controller = new PhishingController(); - expect(controller.config).toStrictEqual({ - stalelistRefreshInterval: defaultStalelistRefreshInterval, - hotlistRefreshInterval: defaultHotlistRefreshInterval, - }); - }); + // it('should use default stalelist & hotlist refresh intervals', () => { + // const controller = getPhishingController(); + // expect(controller.config).toStrictEqual({ + // stalelistRefreshInterval: defaultStalelistRefreshInterval, + // hotlistRefreshInterval: defaultHotlistRefreshInterval, + // }); + // }); it('does not call update stalelist or hotlist upon construction', async () => { const nockScope = nock(PHISHING_CONFIG_BASE_URL) @@ -56,7 +85,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - new PhishingController({}); + getPhishingController(); expect(nockScope.isDone()).toBe(false); }); @@ -82,7 +111,7 @@ describe('PhishingController', () => { ], }); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -137,7 +166,7 @@ describe('PhishingController', () => { it('should not have stalelist be out of date immediately after maybeUpdateState is called', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -149,7 +178,7 @@ describe('PhishingController', () => { it('should not be out of date after maybeUpdateStalelist is called but before refresh interval has passed', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -162,7 +191,7 @@ describe('PhishingController', () => { it('should still be out of date while update is in progress', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -178,7 +207,7 @@ describe('PhishingController', () => { it('should call update only if it is out of date, otherwise it should not call update', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); expect(controller.isStalelistOutOfDate()).toBe(false); @@ -236,7 +265,7 @@ describe('PhishingController', () => { ], }); const clock = sinon.useFakeTimers(50); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, stalelistRefreshInterval: 50, }); @@ -250,7 +279,7 @@ describe('PhishingController', () => { describe('isStalelistOutOfDate', () => { it('should not be out of date upon construction', () => { sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); @@ -259,7 +288,7 @@ describe('PhishingController', () => { it('should not be out of date after some of the refresh interval has passed', () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 5); @@ -269,7 +298,7 @@ describe('PhishingController', () => { it('should be out of date after the refresh interval has passed', () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -279,7 +308,7 @@ describe('PhishingController', () => { it('should be out of date if the refresh interval has passed and an update is in progress', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -293,7 +322,7 @@ describe('PhishingController', () => { it('should not be out of date if the phishing lists were just updated', async () => { sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); await controller.updateStalelist(); @@ -303,7 +332,7 @@ describe('PhishingController', () => { it('should not be out of date if the phishing lists were recently updated', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); await controller.updateStalelist(); @@ -314,7 +343,7 @@ describe('PhishingController', () => { it('should be out of date if the time elapsed since the last update equals the refresh interval', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ stalelistRefreshInterval: 10, }); await controller.updateStalelist(); @@ -327,7 +356,7 @@ describe('PhishingController', () => { describe('isHotlistOutOfDate', () => { it('should not be out of date upon construction', () => { sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); @@ -336,7 +365,7 @@ describe('PhishingController', () => { it('should not be out of date after some of the refresh interval has passed', () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); clock.tick(1000 * 5); @@ -346,7 +375,7 @@ describe('PhishingController', () => { it('should be out of date after the refresh interval has passed', () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -356,7 +385,7 @@ describe('PhishingController', () => { it('should be out of date if the refresh interval has passed and an update is in progress', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); clock.tick(1000 * 10); @@ -370,7 +399,7 @@ describe('PhishingController', () => { it('should not be out of date if the phishing lists were just updated', async () => { sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); await controller.updateHotlist(); @@ -380,7 +409,7 @@ describe('PhishingController', () => { it('should not be out of date if the phishing lists were recently updated', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); await controller.updateHotlist(); @@ -391,7 +420,7 @@ describe('PhishingController', () => { it('should be out of date if the time elapsed since the last update equals the refresh interval', async () => { const clock = sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); await controller.updateHotlist(); @@ -403,7 +432,7 @@ describe('PhishingController', () => { it('should be able to change the stalelistRefreshInterval', async () => { sinon.useFakeTimers(); - const controller = new PhishingController({ stalelistRefreshInterval: 10 }); + const controller = getPhishingController({ stalelistRefreshInterval: 10 }); controller.setStalelistRefreshInterval(0); expect(controller.isStalelistOutOfDate()).toBe(true); @@ -411,7 +440,7 @@ describe('PhishingController', () => { it('should be able to change the hotlistRefreshInterval', async () => { sinon.useFakeTimers(); - const controller = new PhishingController({ + const controller = getPhishingController({ hotlistRefreshInterval: 10, }); controller.setHotlistRefreshInterval(0); @@ -439,7 +468,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('metamask.io')).toMatchObject({ result: false, @@ -469,7 +498,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('i❤.ws')).toMatchObject({ result: false, @@ -498,7 +527,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('xn--i-7iq.ws')).toMatchObject({ result: false, @@ -527,7 +556,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('etnerscan.io')).toMatchObject({ result: true, @@ -556,7 +585,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('myetherẉalletṭ.com')).toMatchObject({ result: true, @@ -586,7 +615,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('xn--myetherallet-4k5fwn.com')).toMatchObject({ result: true, @@ -624,7 +653,7 @@ describe('PhishingController', () => { ], }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect( controller.test('e4d600ab9141b7a9859511c77e63b9b3.com'), @@ -656,7 +685,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(500); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect( controller.test('e4d600ab9141b7a9859511c77e63b9b3.com'), @@ -686,7 +715,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('opensea.io')).toMatchObject({ result: false, @@ -715,7 +744,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.test('ohpensea.io')).toMatchObject({ result: true, @@ -744,7 +773,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect( controller.test('this-is-the-official-website-of-opensea.io'), @@ -774,7 +803,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); const unsafeDomain = 'electrum.mx'; assert.equal( @@ -809,7 +838,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); const unsafeDomain = 'electrum.mx'; assert.equal( @@ -845,7 +874,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); const unsafeDomain = 'myetherẉalletṭ.com'; assert.equal( @@ -880,7 +909,7 @@ describe('PhishingController', () => { }) .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); const unsafeDomain = 'xn--myetherallet-4k5fwn.com'; assert.equal( @@ -930,7 +959,7 @@ describe('PhishingController', () => { ], }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.state.phishingLists).toStrictEqual([ @@ -993,7 +1022,7 @@ describe('PhishingController', () => { ], }); - const controller = new PhishingController(); + const controller = getPhishingController(); await controller.updateStalelist(); expect(controller.state.phishingLists).toStrictEqual([ @@ -1018,10 +1047,79 @@ describe('PhishingController', () => { ]); }); - it('should not update stale list if disabled', async () => { - const controller = new PhishingController( - { disabled: true }, - { + // it('should not update stale list if disabled', async () => { + // const controller = getPhishingController( + // { disabled: true }, + // { + // phishingLists: [ + // { + // allowlist: [], + // blocklist: [], + // fuzzylist: [], + // tolerance: 3, + // version: 1, + // name: ListNames.MetaMask, + // lastUpdated: 0, + // }, + // ], + // }, + // ); + // await controller.updateStalelist(); + + // expect(controller.state.phishingLists).toStrictEqual([ + // { + // allowlist: [], + // blocklist: [], + // fuzzylist: [], + // tolerance: 3, + // version: 1, + // name: ListNames.MetaMask, + // lastUpdated: 0, + // }, + // ]); + // }); + + // it.todo('should not update hotlist lists if disabled', async () => { + // const controller = getPhishingController( + // { disabled: true }, + // { + // phishingLists: [ + // { + // allowlist: [], + // blocklist: [], + // fuzzylist: [], + // tolerance: 3, + // version: 1, + // name: ListNames.MetaMask, + // lastUpdated: 0, + // }, + // ], + // }, + // ); + // await controller.updateHotlist(); + + // expect(controller.state.phishingLists).toStrictEqual([ + // { + // allowlist: [], + // blocklist: [], + // fuzzylist: [], + // tolerance: 3, + // version: 1, + // name: ListNames.MetaMask, + // lastUpdated: 0, + // }, + // ]); + // }); + + it('should not update phishing lists if fetch returns 304', async () => { + nock(PHISHING_CONFIG_BASE_URL) + .get(METAMASK_STALELIST_FILE) + .reply(304) + .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) + .reply(304); + + const controller = getPhishingController({ + state: { phishingLists: [ { allowlist: [], @@ -1034,7 +1132,7 @@ describe('PhishingController', () => { }, ], }, - ); + }); await controller.updateStalelist(); expect(controller.state.phishingLists).toStrictEqual([ @@ -1050,10 +1148,15 @@ describe('PhishingController', () => { ]); }); - it('should not update hotlist lists if disabled', async () => { - const controller = new PhishingController( - { disabled: true }, - { + it('should not update phishing lists if fetch returns 500', async () => { + nock(PHISHING_CONFIG_BASE_URL) + .get(METAMASK_STALELIST_FILE) + .reply(500) + .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) + .reply(500); + + const controller = getPhishingController({ + state: { phishingLists: [ { allowlist: [], @@ -1066,76 +1169,6 @@ describe('PhishingController', () => { }, ], }, - ); - await controller.updateHotlist(); - - expect(controller.state.phishingLists).toStrictEqual([ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ]); - }); - - it('should not update phishing lists if fetch returns 304', async () => { - nock(PHISHING_CONFIG_BASE_URL) - .get(METAMASK_STALELIST_FILE) - .reply(304) - .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) - .reply(304); - - const controller = new PhishingController(undefined, { - phishingLists: [ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ], - }); - await controller.updateStalelist(); - - expect(controller.state.phishingLists).toStrictEqual([ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ]); - }); - - it('should not update phishing lists if fetch returns 500', async () => { - nock(PHISHING_CONFIG_BASE_URL) - .get(METAMASK_STALELIST_FILE) - .reply(500) - .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) - .reply(500); - - const controller = new PhishingController(undefined, { - phishingLists: [ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ], }); await controller.updateStalelist(); @@ -1159,7 +1192,7 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${1}`) .replyWithError('network error'); - const controller = new PhishingController(); + const controller = getPhishingController(); expect(await controller.updateStalelist()).toBeUndefined(); }); @@ -1189,7 +1222,7 @@ describe('PhishingController', () => { .delay(100) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); const firstPromise = controller.updateStalelist(); const secondPromise = controller.updateStalelist(); @@ -1227,7 +1260,7 @@ describe('PhishingController', () => { .delay(100) .reply(200, { data: [] }); - const controller = new PhishingController(); + const controller = getPhishingController(); const firstPromise = controller.updateStalelist(); const secondPromise = controller.updateStalelist(); clock.tick(1000 * 99); @@ -1255,18 +1288,20 @@ describe('PhishingController', () => { ], }); - const controller = new PhishingController(undefined, { - phishingLists: [ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ], + const controller = getPhishingController({ + state: { + phishingLists: [ + { + allowlist: [], + blocklist: [], + fuzzylist: [], + tolerance: 3, + version: 1, + name: ListNames.MetaMask, + lastUpdated: 0, + }, + ], + }, }); await controller.updateHotlist(); @@ -1287,18 +1322,20 @@ describe('PhishingController', () => { .get(`${METAMASK_HOTLIST_DIFF_FILE}/${0}`) .reply(404); - const controller = new PhishingController(undefined, { - phishingLists: [ - { - allowlist: [], - blocklist: [], - fuzzylist: [], - tolerance: 3, - version: 1, - name: ListNames.MetaMask, - lastUpdated: 0, - }, - ], + const controller = getPhishingController({ + state: { + phishingLists: [ + { + allowlist: [], + blocklist: [], + fuzzylist: [], + tolerance: 3, + version: 1, + name: ListNames.MetaMask, + lastUpdated: 0, + }, + ], + }, }); await controller.updateHotlist(); diff --git a/packages/phishing-controller/src/PhishingController.ts b/packages/phishing-controller/src/PhishingController.ts index 80ae1cd16c..d401e3e323 100644 --- a/packages/phishing-controller/src/PhishingController.ts +++ b/packages/phishing-controller/src/PhishingController.ts @@ -1,11 +1,33 @@ -import type { BaseConfig, BaseState } from '@metamask/base-controller'; -import { BaseController } from '@metamask/base-controller'; +import type { + BaseConfig, + BaseState, + RestrictedControllerMessenger, +} from '@metamask/base-controller'; +import { BaseControllerV2 as BaseController } from '@metamask/base-controller'; import { safelyExecute } from '@metamask/controller-utils'; import PhishingDetector from 'eth-phishing-detect/src/detector'; import { toASCII } from 'punycode/'; import { applyDiffs, fetchTimeNow } from './utils'; +const controllerName = 'PhishingController'; + +const stateMetadata = { + phishingLists: { persist: false, anonymous: false }, + whitelist: { persist: false, anonymous: false }, + hotlistLastFetched: { persist: false, anonymous: false }, + stalelistLastFetched: { persist: false, anonymous: false }, +}; + +const getDefaultState = (): PhishingControllerState => { + return { + phishingLists: [], + whitelist: [], + hotlistLastFetched: 0, + stalelistLastFetched: 0, + }; +}; + /** * @type ListTypes * @@ -24,36 +46,36 @@ export type ListTypes = 'fuzzylist' | 'blocklist' | 'allowlist'; * @property version - Version number of this configuration * @property whitelist - List of approved origins */ -export interface EthPhishingResponse { +export type EthPhishingResponse = { blacklist: string[]; fuzzylist: string[]; tolerance: number; version: number; whitelist: string[]; -} +}; /** * @type PhishingStalelist * - * Interface defining expected type of the stalelist.json file. + * type defining expected type of the stalelist.json file. * @property eth_phishing_detect_config - Stale list sourced from eth-phishing-detect's config.json. * @property phishfort_hotlist - Stale list sourced from phishfort's hotlist.json. Only includes blocklist. Deduplicated entries from eth_phishing_detect_config. * @property tolerance - Fuzzy match tolerance level * @property lastUpdated - Timestamp of last update. * @property version - Stalelist data structure iteration. */ -export interface PhishingStalelist { +export type PhishingStalelist = { eth_phishing_detect_config: Record; phishfort_hotlist: Record; tolerance: number; version: number; lastUpdated: number; -} +}; /** * @type PhishingListState * - * Interface defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`. + * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`. * @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 @@ -62,7 +84,7 @@ export interface PhishingStalelist { * @property version - Version of the phishing list state. * @property name - Name of the list. Used for attribution. */ -export interface PhishingListState { +export type PhishingListState = { allowlist: string[]; blocklist: string[]; fuzzylist: string[]; @@ -70,45 +92,45 @@ export interface PhishingListState { version: number; lastUpdated: number; name: ListNames; -} +}; /** * @type EthPhishingDetectResult * - * Interface that describes the result of the `test` method. + * type 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. */ -export interface EthPhishingDetectResult { +export type EthPhishingDetectResult = { name?: string; version?: string; result: boolean; match?: string; // Returned as undefined for non-fuzzy true results. type: 'all' | 'fuzzy' | 'blocklist' | 'allowlist'; -} +}; /** * @type HotlistDiff * - * Interface defining the expected type of the diffs in hotlist.json file. + * type defining the expected type of the diffs in hotlist.json file. * @property url - Url of the diff entry. * @property timestamp - Timestamp at which the diff was identified. * @property targetList - The list name where the diff was identified. * @property isRemoval - Was the diff identified a removal type. */ -export interface HotlistDiff { +export type HotlistDiff = { url: string; timestamp: number; targetList: `${ListKeys}.${ListTypes}`; isRemoval?: boolean; -} +}; -export interface DataResultWrapper { +export type DataResultWrapper = { data: T; -} +}; /** * @type Hotlist @@ -121,18 +143,6 @@ export interface DataResultWrapper { */ export type Hotlist = HotlistDiff[]; -/** - * @type PhishingConfig - * - * Phishing controller configuration - * @property stalelistRefreshInterval - Polling interval used to fetch stale list. - * @property hotlistRefreshInterval - Polling interval used to fetch hotlist diff list. - */ -export interface PhishingConfig extends BaseConfig { - stalelistRefreshInterval: number; - hotlistRefreshInterval: number; -} - /** * @type PhishingState * @@ -140,12 +150,12 @@ export interface PhishingConfig extends BaseConfig { * @property phishing - eth-phishing-detect configuration * @property whitelist - array of temporarily-approved origins */ -export interface PhishingState extends BaseState { +export type PhishingControllerState = { phishingLists: PhishingListState[]; whitelist: string[]; hotlistLastFetched: number; stalelistLastFetched: number; -} +}; export const PHISHING_CONFIG_BASE_URL = 'https://phishing-detection.metafi.codefi.network'; @@ -195,56 +205,97 @@ export const phishingListKeyNameMap = { [ListKeys.PhishfortHotlist]: ListNames.Phishfort, }; +/** + * @type PhishingControllerOptions + * + * Phishing controller options + * @property stalelistRefreshInterval - Polling interval used to fetch stale list. + * @property hotlistRefreshInterval - Polling interval used to fetch hotlist diff list. + */ +export type PhishingControllerOptions = { + stalelistRefreshInterval?: number; + hotlistRefreshInterval?: number; + messenger: PhishingControllerMessenger; + state?: Partial; +}; + +export type MaybeUpdateState = { + type: `${typeof controllerName}:maybeUpdateState`; + handler: PhishingController['maybeUpdateState']; +}; + +export type PhishingControllerActions = MaybeUpdateState; + +export type PhishingControllerMessenger = RestrictedControllerMessenger< + typeof controllerName, + PhishingControllerActions, + never, + never, + never +>; + /** * Controller that manages community-maintained lists of approved and unapproved website origins. */ export class PhishingController extends BaseController< - PhishingConfig, - PhishingState + typeof controllerName, + PhishingControllerState, + PhishingControllerMessenger > { - private detector: any; + #detector: any; - #inProgressHotlistUpdate: Promise | undefined; + #stalelistRefreshInterval: number; - #inProgressStalelistUpdate: Promise | undefined; + #hotlistRefreshInterval: number; - /** - * Name of this controller used during composition - */ - override name = 'PhishingController'; + #inProgressHotlistUpdate?: Promise; + #inProgressStalelistUpdate?: Promise; /** - * Creates a PhishingController instance. + * Construct a Phishing Controller. * * @param config - Initial options used to configure this controller. * @param state - Initial state to set on this controller. */ - constructor( - config?: Partial, - state?: Partial, - ) { - super(config, state); - this.defaultConfig = { - stalelistRefreshInterval: STALELIST_REFRESH_INTERVAL, - hotlistRefreshInterval: HOTLIST_REFRESH_INTERVAL, - }; + constructor({ + stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL, + hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL, + messenger, + state = {}, + }: PhishingControllerOptions) { + super({ + name: controllerName, + metadata: stateMetadata, + messenger, + state: { + ...getDefaultState(), + ...state, + }, + }); - this.defaultState = { - phishingLists: [], - whitelist: [], - hotlistLastFetched: 0, - stalelistLastFetched: 0, - }; + this.#stalelistRefreshInterval = stalelistRefreshInterval; + this.#hotlistRefreshInterval = hotlistRefreshInterval; + this.#registerMessageHandlers(); - this.initialize(); this.updatePhishingDetector(); } + /** + * Constructor helper for registering this controller's messaging system + * actions. + */ + #registerMessageHandlers(): void { + this.messagingSystem.registerActionHandler( + `${controllerName}:maybeUpdateState` as const, + this.maybeUpdateState.bind(this), + ); + } + /** * Updates this.detector with an instance of PhishingDetector using the current state. */ updatePhishingDetector() { - this.detector = new PhishingDetector(this.state.phishingLists); + this.#detector = new PhishingDetector(this.state.phishingLists); } /** @@ -255,7 +306,7 @@ export class PhishingController extends BaseController< * @param interval - the new interval, in ms. */ setStalelistRefreshInterval(interval: number) { - this.configure({ stalelistRefreshInterval: interval }, false, false); + this.#stalelistRefreshInterval = interval; } /** @@ -266,7 +317,7 @@ export class PhishingController extends BaseController< * @param interval - the new interval, in ms. */ setHotlistRefreshInterval(interval: number) { - this.configure({ hotlistRefreshInterval: interval }, false, false); + this.#hotlistRefreshInterval = interval; } /** @@ -277,7 +328,7 @@ export class PhishingController extends BaseController< isStalelistOutOfDate() { return ( fetchTimeNow() - this.state.stalelistLastFetched >= - this.config.stalelistRefreshInterval + this.#stalelistRefreshInterval ); } @@ -289,7 +340,7 @@ export class PhishingController extends BaseController< isHotlistOutOfDate() { return ( fetchTimeNow() - this.state.hotlistLastFetched >= - this.config.hotlistRefreshInterval + this.#hotlistRefreshInterval ); } @@ -328,7 +379,7 @@ export class PhishingController extends BaseController< if (this.state.whitelist.includes(punycodeOrigin)) { return { result: false, type: 'all' }; // Same as whitelisted match returned by detector.check(...). } - return this.detector.check(punycodeOrigin); + return this.#detector.check(punycodeOrigin); } /** @@ -342,7 +393,9 @@ export class PhishingController extends BaseController< if (whitelist.includes(punycodeOrigin)) { return; } - this.update({ whitelist: [...whitelist, punycodeOrigin] }); + this.update((draftState) => { + draftState.whitelist.push(punycodeOrigin); + }); } /** @@ -392,10 +445,6 @@ export class PhishingController extends BaseController< * this function that prevents redundant configuration updates. */ async #updateStalelist() { - if (this.disabled) { - return; - } - let stalelistResponse; let hotlistDiffsResponse; try { @@ -414,9 +463,9 @@ export class PhishingController extends BaseController< // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server // from being overwhelmed with traffic after a network disruption. const timeNow = fetchTimeNow(); - this.update({ - stalelistLastFetched: timeNow, - hotlistLastFetched: timeNow, + this.update((draftState) => { + draftState.stalelistLastFetched = timeNow; + draftState.hotlistLastFetched = timeNow; }); } @@ -451,8 +500,8 @@ export class PhishingController extends BaseController< ListKeys.EthPhishingDetectConfig, ); - this.update({ - phishingLists: [newMetaMaskListState, newPhishfortListState], + this.update((draftState) => { + draftState.phishingLists = [newMetaMaskListState, newPhishfortListState]; }); this.updatePhishingDetector(); } @@ -464,9 +513,6 @@ export class PhishingController extends BaseController< * this function that prevents redundant configuration updates. */ async #updateHotlist() { - if (this.disabled) { - return; - } const lastDiffTimestamp = Math.max( ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated), ); @@ -479,8 +525,8 @@ export class PhishingController extends BaseController< } finally { // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with // traffic after a network disruption. - this.update({ - hotlistLastFetched: fetchTimeNow(), + this.update((draftState) => { + draftState.hotlistLastFetched = fetchTimeNow(); }); } @@ -496,8 +542,8 @@ export class PhishingController extends BaseController< ), ); - this.update({ - phishingLists: newPhishingLists, + this.update((draftState) => { + draftState.phishingLists = newPhishingLists; }); this.updatePhishingDetector(); } From 9ab2277f60425ccc254bd3f31f61d2beb073f827 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Fri, 22 Sep 2023 17:52:10 +0200 Subject: [PATCH 2/5] add `TestOrigin` action --- packages/phishing-controller/src/PhishingController.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/phishing-controller/src/PhishingController.ts b/packages/phishing-controller/src/PhishingController.ts index d401e3e323..ef5365d6b7 100644 --- a/packages/phishing-controller/src/PhishingController.ts +++ b/packages/phishing-controller/src/PhishingController.ts @@ -224,7 +224,12 @@ export type MaybeUpdateState = { handler: PhishingController['maybeUpdateState']; }; -export type PhishingControllerActions = MaybeUpdateState; +export type TestOrigin = { + type: `${typeof controllerName}:testOrigin`; + handler: PhishingController['test']; +}; + +export type PhishingControllerActions = MaybeUpdateState | TestOrigin; export type PhishingControllerMessenger = RestrictedControllerMessenger< typeof controllerName, From bef0f8d3a4061d9f86aef99e35287bdee68450b4 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Fri, 22 Sep 2023 18:41:56 +0200 Subject: [PATCH 3/5] lint and fix some errors --- .../src/PhishingController.test.ts | 88 ++--------------- .../src/PhishingController.ts | 95 ++++++++++--------- 2 files changed, 58 insertions(+), 125 deletions(-) diff --git a/packages/phishing-controller/src/PhishingController.test.ts b/packages/phishing-controller/src/PhishingController.test.ts index 3af5c2b4d6..6e92528b7f 100644 --- a/packages/phishing-controller/src/PhishingController.test.ts +++ b/packages/phishing-controller/src/PhishingController.test.ts @@ -1,3 +1,4 @@ +import { ControllerMessenger } from '@metamask/base-controller'; import { strict as assert } from 'assert'; import nock from 'nock'; import * as sinon from 'sinon'; @@ -8,16 +9,15 @@ import { METAMASK_STALELIST_FILE, PhishingController, PHISHING_CONFIG_BASE_URL, - PhishingControllerActions, - PhishingControllerOptions, + type PhishingControllerActions, + type PhishingControllerOptions, } from './PhishingController'; -import { ControllerMessenger } from '@metamask/base-controller'; - -const defaultHotlistRefreshInterval = 30 * 60; -const defaultStalelistRefreshInterval = 4 * 24 * 60 * 60; const controllerName = 'PhishingController'; +/** + * + */ function getRestrictedMessenger() { const controllerMessenger = new ControllerMessenger< PhishingControllerActions, @@ -35,6 +35,10 @@ function getRestrictedMessenger() { return messenger; } +/** + * + * @param options + */ function getPhishingController(options?: Partial) { return new PhishingController({ messenger: getRestrictedMessenger(), @@ -57,14 +61,6 @@ describe('PhishingController', () => { expect(controller.state.whitelist).toStrictEqual([]); }); - // it('should use default stalelist & hotlist refresh intervals', () => { - // const controller = getPhishingController(); - // expect(controller.config).toStrictEqual({ - // stalelistRefreshInterval: defaultStalelistRefreshInterval, - // hotlistRefreshInterval: defaultHotlistRefreshInterval, - // }); - // }); - it('does not call update stalelist or hotlist upon construction', async () => { const nockScope = nock(PHISHING_CONFIG_BASE_URL) .get(METAMASK_STALELIST_FILE) @@ -1047,70 +1043,6 @@ describe('PhishingController', () => { ]); }); - // it('should not update stale list if disabled', async () => { - // const controller = getPhishingController( - // { disabled: true }, - // { - // phishingLists: [ - // { - // allowlist: [], - // blocklist: [], - // fuzzylist: [], - // tolerance: 3, - // version: 1, - // name: ListNames.MetaMask, - // lastUpdated: 0, - // }, - // ], - // }, - // ); - // await controller.updateStalelist(); - - // expect(controller.state.phishingLists).toStrictEqual([ - // { - // allowlist: [], - // blocklist: [], - // fuzzylist: [], - // tolerance: 3, - // version: 1, - // name: ListNames.MetaMask, - // lastUpdated: 0, - // }, - // ]); - // }); - - // it.todo('should not update hotlist lists if disabled', async () => { - // const controller = getPhishingController( - // { disabled: true }, - // { - // phishingLists: [ - // { - // allowlist: [], - // blocklist: [], - // fuzzylist: [], - // tolerance: 3, - // version: 1, - // name: ListNames.MetaMask, - // lastUpdated: 0, - // }, - // ], - // }, - // ); - // await controller.updateHotlist(); - - // expect(controller.state.phishingLists).toStrictEqual([ - // { - // allowlist: [], - // blocklist: [], - // fuzzylist: [], - // tolerance: 3, - // version: 1, - // name: ListNames.MetaMask, - // lastUpdated: 0, - // }, - // ]); - // }); - it('should not update phishing lists if fetch returns 304', async () => { nock(PHISHING_CONFIG_BASE_URL) .get(METAMASK_STALELIST_FILE) diff --git a/packages/phishing-controller/src/PhishingController.ts b/packages/phishing-controller/src/PhishingController.ts index ef5365d6b7..8b9c13d78a 100644 --- a/packages/phishing-controller/src/PhishingController.ts +++ b/packages/phishing-controller/src/PhishingController.ts @@ -1,8 +1,4 @@ -import type { - BaseConfig, - BaseState, - RestrictedControllerMessenger, -} from '@metamask/base-controller'; +import type { RestrictedControllerMessenger } from '@metamask/base-controller'; import { BaseControllerV2 as BaseController } from '@metamask/base-controller'; import { safelyExecute } from '@metamask/controller-utils'; import PhishingDetector from 'eth-phishing-detect/src/detector'; @@ -10,23 +6,18 @@ import { toASCII } from 'punycode/'; import { applyDiffs, fetchTimeNow } from './utils'; -const controllerName = 'PhishingController'; +export const PHISHING_CONFIG_BASE_URL = + 'https://phishing-detection.metafi.codefi.network'; -const stateMetadata = { - phishingLists: { persist: false, anonymous: false }, - whitelist: { persist: false, anonymous: false }, - hotlistLastFetched: { persist: false, anonymous: false }, - stalelistLastFetched: { persist: false, anonymous: false }, -}; +export const METAMASK_STALELIST_FILE = '/v1/stalelist'; -const getDefaultState = (): PhishingControllerState => { - return { - phishingLists: [], - whitelist: [], - hotlistLastFetched: 0, - stalelistLastFetched: 0, - }; -}; +export const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince'; + +export const HOTLIST_REFRESH_INTERVAL = 30 * 60; // 30 mins in seconds +export const STALELIST_REFRESH_INTERVAL = 4 * 24 * 60 * 60; // 4 days in seconds + +export const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`; +export const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`; /** * @type ListTypes @@ -143,33 +134,6 @@ export type DataResultWrapper = { */ export type Hotlist = HotlistDiff[]; -/** - * @type PhishingState - * - * Phishing controller state - * @property phishing - eth-phishing-detect configuration - * @property whitelist - array of temporarily-approved origins - */ -export type PhishingControllerState = { - phishingLists: PhishingListState[]; - whitelist: string[]; - hotlistLastFetched: number; - stalelistLastFetched: number; -}; - -export const PHISHING_CONFIG_BASE_URL = - 'https://phishing-detection.metafi.codefi.network'; - -export const METAMASK_STALELIST_FILE = '/v1/stalelist'; - -export const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince'; - -export const HOTLIST_REFRESH_INTERVAL = 30 * 60; // 30 mins in seconds -export const STALELIST_REFRESH_INTERVAL = 4 * 24 * 60 * 60; // 4 days in seconds - -export const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`; -export const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`; - /** * Enum containing upstream data provider source list keys. * These are the keys denoting lists consumed by the upstream data provider. @@ -205,6 +169,38 @@ export const phishingListKeyNameMap = { [ListKeys.PhishfortHotlist]: ListNames.Phishfort, }; +const controllerName = 'PhishingController'; + +const stateMetadata = { + phishingLists: { persist: false, anonymous: false }, + whitelist: { persist: false, anonymous: false }, + hotlistLastFetched: { persist: false, anonymous: false }, + stalelistLastFetched: { persist: false, anonymous: false }, +}; + +const getDefaultState = (): PhishingControllerState => { + return { + phishingLists: [], + whitelist: [], + hotlistLastFetched: 0, + stalelistLastFetched: 0, + }; +}; + +/** + * @type PhishingControllerState + * + * Phishing controller state + * @property phishing - eth-phishing-detect configuration + * @property whitelist - array of temporarily-approved origins + */ +export type PhishingControllerState = { + phishingLists: PhishingListState[]; + whitelist: string[]; + hotlistLastFetched: number; + stalelistLastFetched: number; +}; + /** * @type PhishingControllerOptions * @@ -256,11 +252,16 @@ export class PhishingController extends BaseController< #inProgressHotlistUpdate?: Promise; #inProgressStalelistUpdate?: Promise; + /** * Construct a Phishing Controller. * * @param config - Initial options used to configure this controller. + * @param config.stalelistRefreshInterval * @param state - Initial state to set on this controller. + * @param config.hotlistRefreshInterval + * @param config.messenger + * @param config.state */ constructor({ stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL, From c3da729e7bc60f0240b092821f0ea4c35d2b7210 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Fri, 22 Sep 2023 18:51:16 +0200 Subject: [PATCH 4/5] Fix linting --- .../src/PhishingController.test.ts | 7 +++++-- .../src/PhishingController.ts | 17 ++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/packages/phishing-controller/src/PhishingController.test.ts b/packages/phishing-controller/src/PhishingController.test.ts index 6e92528b7f..82b06908c9 100644 --- a/packages/phishing-controller/src/PhishingController.test.ts +++ b/packages/phishing-controller/src/PhishingController.test.ts @@ -16,7 +16,9 @@ import { const controllerName = 'PhishingController'; /** + * Constructs a restricted controller messenger. * + * @returns A restricted controller messenger. */ function getRestrictedMessenger() { const controllerMessenger = new ControllerMessenger< @@ -36,8 +38,9 @@ function getRestrictedMessenger() { } /** - * - * @param options + * Contruct a Phishing Controller with the given options if any. + * @param options - The Phishing Controller options. + * @returns The contstructed Phishing Controller. */ function getPhishingController(options?: Partial) { return new PhishingController({ diff --git a/packages/phishing-controller/src/PhishingController.ts b/packages/phishing-controller/src/PhishingController.ts index 8b9c13d78a..2d743806e9 100644 --- a/packages/phishing-controller/src/PhishingController.ts +++ b/packages/phishing-controller/src/PhishingController.ts @@ -171,13 +171,17 @@ export const phishingListKeyNameMap = { const controllerName = 'PhishingController'; -const stateMetadata = { +const metadata = { phishingLists: { persist: false, anonymous: false }, whitelist: { persist: false, anonymous: false }, hotlistLastFetched: { persist: false, anonymous: false }, stalelistLastFetched: { persist: false, anonymous: false }, }; +/** + * Get a default empty state for the controller. + * @returns The default empty state. + */ const getDefaultState = (): PhishingControllerState => { return { phishingLists: [], @@ -257,11 +261,10 @@ export class PhishingController extends BaseController< * Construct a Phishing Controller. * * @param config - Initial options used to configure this controller. - * @param config.stalelistRefreshInterval - * @param state - Initial state to set on this controller. - * @param config.hotlistRefreshInterval - * @param config.messenger - * @param config.state + * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list. + * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list. + * @param config.messenger - The controller restricted messenger. + * @param config.state - Initial state to set on this controller. */ constructor({ stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL, @@ -271,7 +274,7 @@ export class PhishingController extends BaseController< }: PhishingControllerOptions) { super({ name: controllerName, - metadata: stateMetadata, + metadata, messenger, state: { ...getDefaultState(), From b339160131d83790ed3bc8445d8af5c3204792c9 Mon Sep 17 00:00:00 2001 From: Guillaume Roux Date: Mon, 25 Sep 2023 12:58:27 +0200 Subject: [PATCH 5/5] remove useless await and register the `test` method to the messenger --- .../src/PhishingController.test.ts | 4 ++-- .../src/PhishingController.ts | 21 ++++++++++++------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/packages/phishing-controller/src/PhishingController.test.ts b/packages/phishing-controller/src/PhishingController.test.ts index 82b06908c9..be3888ad20 100644 --- a/packages/phishing-controller/src/PhishingController.test.ts +++ b/packages/phishing-controller/src/PhishingController.test.ts @@ -335,7 +335,7 @@ describe('PhishingController', () => { stalelistRefreshInterval: 10, }); await controller.updateStalelist(); - await clock.tick(1000 * 5); + clock.tick(1000 * 5); expect(controller.isStalelistOutOfDate()).toBe(false); }); @@ -412,7 +412,7 @@ describe('PhishingController', () => { hotlistRefreshInterval: 10, }); await controller.updateHotlist(); - await clock.tick(1000 * 5); + clock.tick(1000 * 5); expect(controller.isHotlistOutOfDate()).toBe(false); }); diff --git a/packages/phishing-controller/src/PhishingController.ts b/packages/phishing-controller/src/PhishingController.ts index 2d743806e9..2c95e86587 100644 --- a/packages/phishing-controller/src/PhishingController.ts +++ b/packages/phishing-controller/src/PhishingController.ts @@ -172,10 +172,10 @@ export const phishingListKeyNameMap = { const controllerName = 'PhishingController'; const metadata = { - phishingLists: { persist: false, anonymous: false }, - whitelist: { persist: false, anonymous: false }, - hotlistLastFetched: { persist: false, anonymous: false }, - stalelistLastFetched: { persist: false, anonymous: false }, + phishingLists: { persist: true, anonymous: false }, + whitelist: { persist: true, anonymous: false }, + hotlistLastFetched: { persist: true, anonymous: false }, + stalelistLastFetched: { persist: true, anonymous: false }, }; /** @@ -298,6 +298,11 @@ export class PhishingController extends BaseController< `${controllerName}:maybeUpdateState` as const, this.maybeUpdateState.bind(this), ); + + this.messagingSystem.registerActionHandler( + `${controllerName}:testOrigin` as const, + this.test.bind(this), + ); } /** @@ -457,14 +462,14 @@ export class PhishingController extends BaseController< let stalelistResponse; let hotlistDiffsResponse; try { - stalelistResponse = await this.queryConfig< + stalelistResponse = await this.#queryConfig< DataResultWrapper >(METAMASK_STALELIST_URL).then((d) => d); // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`, // so it doesn't make sense to call if there is not a timestamp to begin with. if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) { - hotlistDiffsResponse = await this.queryConfig< + hotlistDiffsResponse = await this.#queryConfig< DataResultWrapper >(`${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`); } @@ -528,7 +533,7 @@ export class PhishingController extends BaseController< let hotlistResponse: DataResultWrapper | null; try { - hotlistResponse = await this.queryConfig>( + hotlistResponse = await this.#queryConfig>( `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`, ); } finally { @@ -557,7 +562,7 @@ export class PhishingController extends BaseController< this.updatePhishingDetector(); } - private async queryConfig( + async #queryConfig( input: RequestInfo, ): Promise { const response = await safelyExecute(