Socket
Socket
Sign inDemoInstall

@metamask/phishing-controller

Package Overview
Dependencies
Maintainers
8
Versions
29
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@metamask/phishing-controller - npm Package Compare versions

Comparing version 1.1.2 to 2.0.0

dist/utils.d.ts

22

CHANGELOG.md

@@ -9,2 +9,21 @@ # Changelog

## [2.0.0]
### Changed
- **BREAKING:** Refactor to Cost-Optimized Phishing List Data Architecture. ([#1080](https://github.com/MetaMask/core/pull/1080))
- Rather than periodically downloading two separate configurations (MetaMask and Phishfort), we now download a combined "stalelist" and "hotlist". The stalelist is downloaded every 4 days, and the hotlist is downloaded every 30 minutes. The hotlist only includes data from the last 8 days, which should dramatically reduce the required network traffic for phishing config updates.
- When a site is blocked, we no longer know which list is responsible due to the combined format. We will need to come up with another way to attribute blocks to a specific list; this controller will no longer be responsible for that.
- This change includes the removal of the exports:
- `METAMASK_CONFIG_FILE` and `PHISHFORT_HOTLIST_FILE` (replaced by `METAMASK_STALELIST_FILE` and `METAMASK_HOTLIST_DIFF_FILE`)
- `METAMASK_CONFIG_URL` and `PHISHFORT_HOTLIST_URL` (replaced by `METAMASK_STALELIST_URL` and `METAMASK_HOTLIST_DIFF_URL`)
- `EthPhishingResponse` (replaced by `PhishingStalelist` for the API response and `PhishingListState` for the list in controller state, as they're now different)
- The configuration has changed:
- Instead of accepting a `refreshInterval`, we now accept a separate interval for the stalelist and hotlist (`stalelistRefreshInterval` and `hotlistRefreshInterval`)
- The controller state has been updated:
- The phishing list itself has been renamed from `phishing` to `listState`, and the shape has changed. Removing the old `phishing` state would be advised, as it will get replaced by an updated configuration immediately anyway.
- `lastFetched` has been replaced by `hotlistLastFetched` and `stalelistLastFetched`. The old `lastFetched` state can be removed as well (it never needed to be persisted anyway).
- The `setRefreshInterval` method has been replaced by `setStalelistRefreshInterval` and `setHotlistRefreshInterval`
- The `isOutOfDate` method has been replaced by `isStalelistOutOfDate` and `isHotlistOutOfDate`
- The `maybeUpdatePhishingLists` method has been replaced by `maybeUpdateState`
- The `updatePhishingLists` method has been replaced by `updateStalelist` and `updateHotlist`
## [1.1.2]

@@ -37,3 +56,4 @@ ### Fixed

[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@1.1.2...HEAD
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@2.0.0...HEAD
[2.0.0]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@1.1.2...@metamask/phishing-controller@2.0.0
[1.1.2]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@1.1.1...@metamask/phishing-controller@1.1.2

@@ -40,0 +60,0 @@ [1.1.1]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@1.1.0...@metamask/phishing-controller@1.1.1

@@ -21,5 +21,5 @@ import { BaseController, BaseConfig, BaseState } from '@metamask/base-controller';

/**
* @type EthPhishingDetectConfig
* @type PhishingStalelist
*
* Interface defining expected input to PhishingDetector.
* Interface defining expected type of the stalelist.json file.
* @property allowlist - List of approved origins (legacy naming "whitelist")

@@ -29,4 +29,6 @@ * @property blocklist - List of unapproved origins (legacy naming "blacklist")

* @property tolerance - Fuzzy match tolerance level
* @property lastUpdated - Timestamp of last update.
* @property version - Stalelist data structure iteration.
*/
export interface EthPhishingDetectConfig {
export interface PhishingStalelist {
allowlist: string[];

@@ -36,6 +38,26 @@ blocklist: string[];

tolerance: number;
name: string;
version: number;
lastUpdated: number;
}
/**
* @type PhishingListState
*
* Interface 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
* @property tolerance - Fuzzy match tolerance level
* @property lastUpdated - Timestamp of last update.
* @property version - Version of the phishing list state.
*/
export interface PhishingListState {
allowlist: string[];
blocklist: string[];
fuzzylist: string[];
tolerance: number;
version: number;
lastUpdated: number;
name: string;
}
/**
* @type EthPhishingDetectResult

@@ -58,9 +80,36 @@ *

/**
* @type HotlistDiff
*
* Interface 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 {
url: string;
timestamp: number;
targetList: 'fuzzylist' | 'blocklist' | 'allowlist';
isRemoval?: boolean;
}
/**
* @type Hotlist
*
* Type defining expected 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 declare type Hotlist = HotlistDiff[];
/**
* @type PhishingConfig
*
* Phishing controller configuration
* @property interval - Polling interval used to fetch new block / approve lists
* @property stalelistRefreshInterval - Polling interval used to fetch stale list.
* @property hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.
*/
export interface PhishingConfig extends BaseConfig {
refreshInterval: number;
stalelistRefreshInterval: number;
hotlistRefreshInterval: number;
}

@@ -75,11 +124,14 @@ /**

export interface PhishingState extends BaseState {
phishing: EthPhishingDetectConfig[];
listState: PhishingListState;
whitelist: string[];
lastFetched: number;
hotlistLastFetched: number;
stalelistLastFetched: number;
}
export declare const PHISHING_CONFIG_BASE_URL = "https://static.metafi.codefi.network/api/v1/lists";
export declare const METAMASK_CONFIG_FILE = "/eth_phishing_detect_config.json";
export declare const PHISHFORT_HOTLIST_FILE = "/phishfort_hotlist.json";
export declare const METAMASK_CONFIG_URL: string;
export declare const PHISHFORT_HOTLIST_URL: string;
export declare const METAMASK_STALELIST_FILE = "/stalelist.json";
export declare const METAMASK_HOTLIST_DIFF_FILE = "/hotlist.json";
export declare const HOTLIST_REFRESH_INTERVAL: number;
export declare const STALELIST_REFRESH_INTERVAL: number;
export declare const METAMASK_STALELIST_URL: string;
export declare const METAMASK_HOTLIST_DIFF_URL: string;
/**

@@ -103,19 +155,48 @@ * Controller that manages community-maintained lists of approved and unapproved website origins.

/**
* Set the interval at which the phishing list will be refetched. Fetching will only occur on the next call to test/bypass. For immediate update to the phishing list, call updatePhishingLists directly.
* Updates this.detector with an instance of PhishingDetector using the current state.
*/
updatePhishingDetector(): void;
/**
* Set the interval at which the stale phishing list will be refetched.
* Fetching will only occur on the next call to test/bypass.
* For immediate update to the phishing list, call {@link updateStalelist} directly.
*
* @param interval - the new interval, in ms.
*/
setRefreshInterval(interval: number): void;
setStalelistRefreshInterval(interval: number): void;
/**
* Determine if an update to the phishing configuration is needed.
* Set the interval at which the hot list will be refetched.
* Fetching will only occur on the next call to test/bypass.
* For immediate update to the phishing list, call {@link updateHotlist} directly.
*
* @param interval - the new interval, in ms.
*/
setHotlistRefreshInterval(interval: number): void;
/**
* Determine if an update to the stalelist configuration is needed.
*
* @returns Whether an update is needed
*/
isOutOfDate(): boolean;
isStalelistOutOfDate(): boolean;
/**
* Determine if an update to the hotlist configuration is needed.
*
* @returns Whether an update is needed
*/
isHotlistOutOfDate(): boolean;
/**
* Conditionally update the phishing configuration.
*
* If the stalelist configuration is out of date, this function will call `updateStalelist`
* to update the configuration. This will automatically grab the hotlist,
* so it isn't necessary to continue on to download the hotlist.
*
*/
maybeUpdateState(): Promise<void>;
/**
* Determines if a given origin is unapproved.
*
* It is strongly recommended that you call {@link isOutOfDate} before calling this,
* to check whether the phishing configuration is up-to-date. It can be
* updated by calling {@link updatePhishingLists}.
* It is strongly recommended that you call {@link maybeUpdateState} before calling this,
* to check whether the phishing configuration is up-to-date. It will be updated if necessary
* by calling {@link updateStalelist} or {@link updateHotlist}.
*

@@ -133,3 +214,3 @@ * @param origin - Domain origin of a website.

/**
* Update the phishing configuration.
* Update the hotlist.
*

@@ -139,12 +220,12 @@ * If an update is in progress, no additional update will be made. Instead this will wait until

*/
updatePhishingLists(): Promise<void>;
updateHotlist(): Promise<void>;
/**
* Conditionally update the phishing configuration.
* Update the stalelist.
*
* If the phishing configuration is out of date, this function will call `updatePhishingLists`
* to update the configuration.
* If an update is in progress, no additional update will be made. Instead this will wait until
* the in-progress update has finished.
*/
maybeUpdatePhishingLists(): Promise<void>;
updateStalelist(): Promise<void>;
private queryConfig;
}
export default PhishingController;

234

dist/PhishingController.js

@@ -25,5 +25,5 @@ "use strict";

};
var _PhishingController_instances, _PhishingController_inProgressUpdate, _PhishingController_updatePhishingLists;
var _PhishingController_instances, _PhishingController_inProgressHotlistUpdate, _PhishingController_inProgressStalelistUpdate, _PhishingController_updateStalelist, _PhishingController_updateHotlist;
Object.defineProperty(exports, "__esModule", { value: true });
exports.PhishingController = exports.PHISHFORT_HOTLIST_URL = exports.METAMASK_CONFIG_URL = exports.PHISHFORT_HOTLIST_FILE = exports.METAMASK_CONFIG_FILE = exports.PHISHING_CONFIG_BASE_URL = void 0;
exports.PhishingController = exports.METAMASK_HOTLIST_DIFF_URL = exports.METAMASK_STALELIST_URL = exports.STALELIST_REFRESH_INTERVAL = exports.HOTLIST_REFRESH_INTERVAL = exports.METAMASK_HOTLIST_DIFF_FILE = exports.METAMASK_STALELIST_FILE = exports.PHISHING_CONFIG_BASE_URL = void 0;
const punycode_1 = require("punycode/");

@@ -34,7 +34,10 @@ const config_json_1 = __importDefault(require("eth-phishing-detect/src/config.json"));

const controller_utils_1 = require("@metamask/controller-utils");
const utils_1 = require("./utils");
exports.PHISHING_CONFIG_BASE_URL = 'https://static.metafi.codefi.network/api/v1/lists';
exports.METAMASK_CONFIG_FILE = '/eth_phishing_detect_config.json';
exports.PHISHFORT_HOTLIST_FILE = '/phishfort_hotlist.json';
exports.METAMASK_CONFIG_URL = `${exports.PHISHING_CONFIG_BASE_URL}${exports.METAMASK_CONFIG_FILE}`;
exports.PHISHFORT_HOTLIST_URL = `${exports.PHISHING_CONFIG_BASE_URL}${exports.PHISHFORT_HOTLIST_FILE}`;
exports.METAMASK_STALELIST_FILE = '/stalelist.json';
exports.METAMASK_HOTLIST_DIFF_FILE = '/hotlist.json';
exports.HOTLIST_REFRESH_INTERVAL = 30 * 60; // 30 mins in seconds
exports.STALELIST_REFRESH_INTERVAL = 4 * 24 * 60 * 60; // 4 days in seconds
exports.METAMASK_STALELIST_URL = `${exports.PHISHING_CONFIG_BASE_URL}${exports.METAMASK_STALELIST_FILE}`;
exports.METAMASK_HOTLIST_DIFF_URL = `${exports.PHISHING_CONFIG_BASE_URL}${exports.METAMASK_HOTLIST_DIFF_FILE}`;
/**

@@ -53,3 +56,4 @@ * Controller that manages community-maintained lists of approved and unapproved website origins.

_PhishingController_instances.add(this);
_PhishingController_inProgressUpdate.set(this, void 0);
_PhishingController_inProgressHotlistUpdate.set(this, void 0);
_PhishingController_inProgressStalelistUpdate.set(this, void 0);
/**

@@ -60,43 +64,102 @@ * Name of this controller used during composition

this.defaultConfig = {
refreshInterval: 60 * 60 * 1000,
stalelistRefreshInterval: exports.STALELIST_REFRESH_INTERVAL,
hotlistRefreshInterval: exports.HOTLIST_REFRESH_INTERVAL,
};
this.defaultState = {
phishing: [
{
allowlist: config_json_1.default.whitelist,
blocklist: config_json_1.default.blacklist,
fuzzylist: config_json_1.default.fuzzylist,
tolerance: config_json_1.default.tolerance,
name: `MetaMask`,
version: config_json_1.default.version,
},
],
listState: {
allowlist: config_json_1.default.whitelist,
blocklist: config_json_1.default.blacklist,
fuzzylist: config_json_1.default.fuzzylist,
tolerance: config_json_1.default.tolerance,
version: config_json_1.default.version,
name: 'MetaMask',
lastUpdated: 0,
},
whitelist: [],
lastFetched: 0,
hotlistLastFetched: 0,
stalelistLastFetched: 0,
};
this.initialize();
this.detector = new detector_1.default(this.state.phishing);
this.updatePhishingDetector();
}
/**
* Set the interval at which the phishing list will be refetched. Fetching will only occur on the next call to test/bypass. For immediate update to the phishing list, call updatePhishingLists directly.
* Updates this.detector with an instance of PhishingDetector using the current state.
*/
updatePhishingDetector() {
this.detector = new detector_1.default([
{
allowlist: this.state.listState.allowlist,
blocklist: this.state.listState.blocklist,
fuzzylist: this.state.listState.fuzzylist,
tolerance: this.state.listState.tolerance,
name: `MetaMask`,
version: this.state.listState.version,
},
]);
}
/**
* Set the interval at which the stale phishing list will be refetched.
* Fetching will only occur on the next call to test/bypass.
* For immediate update to the phishing list, call {@link updateStalelist} directly.
*
* @param interval - the new interval, in ms.
*/
setRefreshInterval(interval) {
this.configure({ refreshInterval: interval }, false, false);
setStalelistRefreshInterval(interval) {
this.configure({ stalelistRefreshInterval: interval }, false, false);
}
/**
* Determine if an update to the phishing configuration is needed.
* Set the interval at which the hot list will be refetched.
* Fetching will only occur on the next call to test/bypass.
* For immediate update to the phishing list, call {@link updateHotlist} directly.
*
* @param interval - the new interval, in ms.
*/
setHotlistRefreshInterval(interval) {
this.configure({ hotlistRefreshInterval: interval }, false, false);
}
/**
* Determine if an update to the stalelist configuration is needed.
*
* @returns Whether an update is needed
*/
isOutOfDate() {
return Date.now() - this.state.lastFetched >= this.config.refreshInterval;
isStalelistOutOfDate() {
return ((0, utils_1.fetchTimeNow)() - this.state.stalelistLastFetched >=
this.config.stalelistRefreshInterval);
}
/**
* Determine if an update to the hotlist configuration is needed.
*
* @returns Whether an update is needed
*/
isHotlistOutOfDate() {
return ((0, utils_1.fetchTimeNow)() - this.state.hotlistLastFetched >=
this.config.hotlistRefreshInterval);
}
/**
* Conditionally update the phishing configuration.
*
* If the stalelist configuration is out of date, this function will call `updateStalelist`
* to update the configuration. This will automatically grab the hotlist,
* so it isn't necessary to continue on to download the hotlist.
*
*/
maybeUpdateState() {
return __awaiter(this, void 0, void 0, function* () {
const staleListOutOfDate = this.isStalelistOutOfDate();
if (staleListOutOfDate) {
yield this.updateStalelist();
return;
}
const hotlistOutOfDate = this.isHotlistOutOfDate();
if (hotlistOutOfDate) {
yield this.updateHotlist();
}
});
}
/**
* Determines if a given origin is unapproved.
*
* It is strongly recommended that you call {@link isOutOfDate} before calling this,
* to check whether the phishing configuration is up-to-date. It can be
* updated by calling {@link updatePhishingLists}.
* It is strongly recommended that you call {@link maybeUpdateState} before calling this,
* to check whether the phishing configuration is up-to-date. It will be updated if necessary
* by calling {@link updateStalelist} or {@link updateHotlist}.
*

@@ -127,3 +190,3 @@ * @param origin - Domain origin of a website.

/**
* Update the phishing configuration.
* Update the hotlist.
*

@@ -133,14 +196,14 @@ * If an update is in progress, no additional update will be made. Instead this will wait until

*/
updatePhishingLists() {
updateHotlist() {
return __awaiter(this, void 0, void 0, function* () {
if (__classPrivateFieldGet(this, _PhishingController_inProgressUpdate, "f")) {
yield __classPrivateFieldGet(this, _PhishingController_inProgressUpdate, "f");
if (__classPrivateFieldGet(this, _PhishingController_inProgressHotlistUpdate, "f")) {
yield __classPrivateFieldGet(this, _PhishingController_inProgressHotlistUpdate, "f");
return;
}
try {
__classPrivateFieldSet(this, _PhishingController_inProgressUpdate, __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_updatePhishingLists).call(this), "f");
yield __classPrivateFieldGet(this, _PhishingController_inProgressUpdate, "f");
__classPrivateFieldSet(this, _PhishingController_inProgressHotlistUpdate, __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_updateHotlist).call(this), "f");
yield __classPrivateFieldGet(this, _PhishingController_inProgressHotlistUpdate, "f");
}
finally {
__classPrivateFieldSet(this, _PhishingController_inProgressUpdate, undefined, "f");
__classPrivateFieldSet(this, _PhishingController_inProgressHotlistUpdate, undefined, "f");
}

@@ -150,13 +213,20 @@ });

/**
* Conditionally update the phishing configuration.
* Update the stalelist.
*
* If the phishing configuration is out of date, this function will call `updatePhishingLists`
* to update the configuration.
* If an update is in progress, no additional update will be made. Instead this will wait until
* the in-progress update has finished.
*/
maybeUpdatePhishingLists() {
updateStalelist() {
return __awaiter(this, void 0, void 0, function* () {
const phishingListsAreOutOfDate = this.isOutOfDate();
if (phishingListsAreOutOfDate) {
yield this.updatePhishingLists();
if (__classPrivateFieldGet(this, _PhishingController_inProgressStalelistUpdate, "f")) {
yield __classPrivateFieldGet(this, _PhishingController_inProgressStalelistUpdate, "f");
return;
}
try {
__classPrivateFieldSet(this, _PhishingController_inProgressStalelistUpdate, __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_updateStalelist).call(this), "f");
yield __classPrivateFieldGet(this, _PhishingController_inProgressStalelistUpdate, "f");
}
finally {
__classPrivateFieldSet(this, _PhishingController_inProgressStalelistUpdate, undefined, "f");
}
});

@@ -179,3 +249,3 @@ }

exports.PhishingController = PhishingController;
_PhishingController_inProgressUpdate = new WeakMap(), _PhishingController_instances = new WeakSet(), _PhishingController_updatePhishingLists = function _PhishingController_updatePhishingLists() {
_PhishingController_inProgressHotlistUpdate = new WeakMap(), _PhishingController_inProgressStalelistUpdate = new WeakMap(), _PhishingController_instances = new WeakSet(), _PhishingController_updateStalelist = function _PhishingController_updateStalelist() {
return __awaiter(this, void 0, void 0, function* () {

@@ -185,52 +255,54 @@ if (this.disabled) {

}
const configs = [];
let metamaskConfigLegacy;
let phishfortHotlist;
let stalelist;
let hotlistDiffs;
try {
[metamaskConfigLegacy, phishfortHotlist] = yield Promise.all([
this.queryConfig(exports.METAMASK_CONFIG_URL),
this.queryConfig(exports.PHISHFORT_HOTLIST_URL),
[stalelist, hotlistDiffs] = yield Promise.all([
this.queryConfig(exports.METAMASK_STALELIST_URL),
this.queryConfig(exports.METAMASK_HOTLIST_DIFF_URL),
]);
}
finally {
// Set `lastFetched` even for failed requests to prevent server from being overwhelmed with
// traffic after a network disruption.
// Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server
// from being overwhelmed with traffic after a network disruption.
const timeNow = (0, utils_1.fetchTimeNow)();
this.update({
lastFetched: Date.now(),
stalelistLastFetched: timeNow,
hotlistLastFetched: timeNow,
});
}
// Correctly shaping MetaMask config.
const metamaskConfig = {
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);
if (!stalelist || !hotlistDiffs) {
return;
}
// Create Set from metamaskConfig.blocklist to improve look up performance when used within filter.
const mmConfigBlocklist = new Set(metamaskConfig.blocklist);
// Correctly shaping PhishFort config.
const phishfortConfig = {
allowlist: [],
blocklist: (phishfortHotlist || []).filter((i) => !mmConfigBlocklist.has(i)),
fuzzylist: [],
tolerance: 0,
name: `PhishFort`,
version: 1,
};
if (phishfortHotlist) {
configs.push(phishfortConfig);
// Correctly shaping eth-phishing-detect state by applying hotlist diffs to the stalelist.
const newListState = (0, utils_1.applyDiffs)(stalelist, hotlistDiffs);
this.update({
listState: newListState,
});
this.updatePhishingDetector();
});
}, _PhishingController_updateHotlist = function _PhishingController_updateHotlist() {
return __awaiter(this, void 0, void 0, function* () {
if (this.disabled) {
return;
}
// Do not update if all configs are unavailable.
if (!configs.length) {
let hotlistDiffs;
try {
hotlistDiffs = yield this.queryConfig(exports.METAMASK_HOTLIST_DIFF_URL);
}
finally {
// Set `stalelistLastFetched` even for failed requests to prevent server from being overwhelmed with
// traffic after a network disruption.
this.update({
hotlistLastFetched: (0, utils_1.fetchTimeNow)(),
});
}
if (!hotlistDiffs) {
return;
}
this.detector = new detector_1.default(configs);
// Correctly shaping MetaMask config.
const newListState = (0, utils_1.applyDiffs)(this.state.listState, hotlistDiffs);
this.update({
phishing: configs,
listState: newListState,
});
this.updatePhishingDetector();
});

@@ -237,0 +309,0 @@ };

{
"name": "@metamask/phishing-controller",
"version": "1.1.2",
"version": "2.0.0",
"description": "Maintains a periodically updated list of approved and unapproved website origins",

@@ -5,0 +5,0 @@ "keywords": [

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc