@metamask-previews/phishing-controller 14.1.0-preview-096af0b9 → 14.1.1-preview-05b702c4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -1
- package/dist/PhishingController.cjs +2 -2
- package/dist/PhishingController.cjs.map +1 -1
- package/dist/PhishingController.d.cts.map +1 -1
- package/dist/PhishingController.d.mts.map +1 -1
- package/dist/PhishingController.mjs +2 -2
- package/dist/PhishingController.mjs.map +1 -1
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [14.1.1]
|
11
|
+
|
12
|
+
### Changed
|
13
|
+
|
14
|
+
- Bump `@metamask/base-controller` from `^8.4.0` to `^8.4.1` ([#6807](https://github.com/MetaMask/core/pull/6807))
|
15
|
+
- Bump `@metamask/controller-utils` from `^11.14.0` to `^11.14.1` ([#6807](https://github.com/MetaMask/core/pull/6807))
|
16
|
+
|
17
|
+
### Fixed
|
18
|
+
|
19
|
+
- Fetches the hotlist endpoint with a query param for blocklistPaths ([#6808](https://github.com/MetaMask/core/pull/6808))
|
20
|
+
|
10
21
|
## [14.1.0]
|
11
22
|
|
12
23
|
### Added
|
@@ -430,7 +441,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
430
441
|
|
431
442
|
All changes listed after this point were applied to this package following the monorepo conversion.
|
432
443
|
|
433
|
-
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@14.1.
|
444
|
+
[Unreleased]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@14.1.1...HEAD
|
445
|
+
[14.1.1]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@14.1.0...@metamask/phishing-controller@14.1.1
|
434
446
|
[14.1.0]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@14.0.0...@metamask/phishing-controller@14.1.0
|
435
447
|
[14.0.0]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@13.1.0...@metamask/phishing-controller@14.0.0
|
436
448
|
[13.1.0]: https://github.com/MetaMask/core/compare/@metamask/phishing-controller@13.0.0...@metamask/phishing-controller@13.1.0
|
@@ -809,7 +809,7 @@ async function _PhishingController_updateStalelist() {
|
|
809
809
|
// Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,
|
810
810
|
// so it doesn't make sense to call if there is not a timestamp to begin with.
|
811
811
|
if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {
|
812
|
-
hotlistDiffsResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${exports.METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);
|
812
|
+
hotlistDiffsResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${exports.METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}?blocklistPaths=true`);
|
813
813
|
}
|
814
814
|
}
|
815
815
|
finally {
|
@@ -857,7 +857,7 @@ async function _PhishingController_updateHotlist() {
|
|
857
857
|
return;
|
858
858
|
}
|
859
859
|
const lastDiffTimestamp = Math.max(...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated));
|
860
|
-
hotlistResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${exports.METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`);
|
860
|
+
hotlistResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${exports.METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}?blocklistPaths=true`);
|
861
861
|
}
|
862
862
|
finally {
|
863
863
|
// Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"PhishingController.cjs","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type {\n TransactionControllerStateChangeEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Patch } from 'immer';\nimport { toASCII } from 'punycode/punycode.js';\n\nimport { CacheManager, type CacheEntry } from './CacheManager';\nimport {\n type PathTrie,\n convertListToTrie,\n insertToTrie,\n matchedPathPrefix,\n} from './PathTrie';\nimport { PhishingDetector } from './PhishingDetector';\nimport {\n PhishingDetectorResultType,\n type PhishingDetectorResult,\n type PhishingDetectionScanResult,\n RecommendedAction,\n type TokenScanCacheData,\n type BulkTokenScanResponse,\n type BulkTokenScanRequest,\n type TokenScanApiResponse,\n} from './types';\nimport {\n applyDiffs,\n fetchTimeNow,\n getHostnameFromUrl,\n roundToNearestMinute,\n getHostnameFromWebUrl,\n buildCacheKey,\n splitCacheHits,\n resolveChainName,\n getPathnameFromUrl,\n} from './utils';\n\nexport const PHISHING_CONFIG_BASE_URL =\n 'https://phishing-detection.api.cx.metamask.io';\nexport const METAMASK_STALELIST_FILE = '/v1/stalelist';\nexport const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince';\n\nexport const CLIENT_SIDE_DETECION_BASE_URL =\n 'https://client-side-detection.api.cx.metamask.io';\nexport const C2_DOMAIN_BLOCKLIST_ENDPOINT = '/v1/request-blocklist';\n\nexport const PHISHING_DETECTION_BASE_URL =\n 'https://dapp-scanning.api.cx.metamask.io';\nexport const PHISHING_DETECTION_SCAN_ENDPOINT = 'v2/scan';\nexport const PHISHING_DETECTION_BULK_SCAN_ENDPOINT = 'bulk-scan';\n\nexport const SECURITY_ALERTS_BASE_URL =\n 'https://security-alerts.api.cx.metamask.io';\nexport const TOKEN_BULK_SCANNING_ENDPOINT = '/token/scan-bulk';\n\n// Cache configuration defaults\nexport const DEFAULT_URL_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_URL_SCAN_CACHE_MAX_SIZE = 250;\nexport const DEFAULT_TOKEN_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE = 1000;\n\nexport const C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const HOTLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const STALELIST_REFRESH_INTERVAL = 30 * 24 * 60 * 60; // 30 days in seconds\n\nexport const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`;\nexport const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`;\nexport const C2_DOMAIN_BLOCKLIST_URL = `${CLIENT_SIDE_DETECION_BASE_URL}${C2_DOMAIN_BLOCKLIST_ENDPOINT}`;\n\n/**\n * @type ListTypes\n *\n * Type outlining the types of lists provided by aggregating different source lists\n */\nexport type ListTypes =\n | 'fuzzylist'\n | 'blocklist'\n | 'blocklistPaths'\n | 'allowlist'\n | 'c2DomainBlocklist';\n\n/**\n * @type EthPhishingResponse\n *\n * Configuration response from the eth-phishing-detect package\n * consisting of approved and unapproved website origins\n * @property blacklist - List of unapproved origins\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property version - Version number of this configuration\n * @property whitelist - List of approved origins\n */\nexport type EthPhishingResponse = {\n blacklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n whitelist: string[];\n};\n\n/**\n * @type C2DomainBlocklistResponse\n *\n * Response for blocklist update requests\n * @property recentlyAdded - List of c2 domains recently added to the blocklist\n * @property recentlyRemoved - List of c2 domains recently removed from the blocklist\n * @property lastFetchedAt - Timestamp of the last fetch request\n */\nexport type C2DomainBlocklistResponse = {\n recentlyAdded: string[];\n recentlyRemoved: string[];\n lastFetchedAt: string;\n};\n\n/**\n * PhishingStalelist defines the expected type of the stalelist from the API.\n *\n * allowlist - List of approved origins.\n * blocklist - List of unapproved origins (hostname-only entries).\n * blocklistPaths - Trie of unapproved origins with paths (hostname + path entries).\n * fuzzylist - List of fuzzy-matched unapproved origins.\n * tolerance - Fuzzy match tolerance level\n * lastUpdated - Timestamp of last update.\n * version - Stalelist data structure iteration.\n */\nexport type PhishingStalelist = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n};\n\n/**\n * @type PhishingListState\n *\n * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`.\n * @property allowlist - List of approved origins (legacy naming \"whitelist\")\n * @property blocklist - List of unapproved origins (legacy naming \"blacklist\")\n * @property blocklistPaths - Trie of unapproved origins with paths (hostname + path, no query params).\n * @property c2DomainBlocklist - List of hashed hostnames that C2 requests are blocked against.\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Version of the phishing list state.\n * @property name - Name of the list. Used for attribution.\n */\nexport type PhishingListState = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: PathTrie;\n c2DomainBlocklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n name: ListNames;\n};\n\n/**\n * @type HotlistDiff\n *\n * type defining the expected type of the diffs in hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type HotlistDiff = {\n url: string;\n timestamp: number;\n targetList: `${ListKeys}.${ListTypes}`;\n isRemoval?: boolean;\n};\n\nexport type DataResultWrapper<T> = {\n data: T;\n};\n\n/**\n * @type Hotlist\n *\n * Type defining expected hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type Hotlist = HotlistDiff[];\n\n/**\n * Enum containing upstream data provider source list keys.\n * These are the keys denoting lists consumed by the upstream data provider.\n */\nexport enum ListKeys {\n EthPhishingDetectConfig = 'eth_phishing_detect_config',\n}\n\n/**\n * Enum containing downstream client attribution names.\n */\nexport enum ListNames {\n MetaMask = 'MetaMask',\n}\n\n/**\n * Maps from downstream client attribution name\n * to list key sourced from upstream data provider.\n */\nconst phishingListNameKeyMap = {\n [ListNames.MetaMask]: ListKeys.EthPhishingDetectConfig,\n};\n\n/**\n * Maps from list key sourced from upstream data\n * provider to downstream client attribution name.\n */\nexport const phishingListKeyNameMap = {\n [ListKeys.EthPhishingDetectConfig]: ListNames.MetaMask,\n};\n\nconst controllerName = 'PhishingController';\n\nconst metadata: StateMetadata<PhishingControllerState> = {\n phishingLists: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelist: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelistPaths: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n hotlistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n stalelistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n c2DomainBlocklistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n urlScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n tokenScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n};\n\n/**\n * Get a default empty state for the controller.\n *\n * @returns The default empty state.\n */\nconst getDefaultState = (): PhishingControllerState => {\n return {\n phishingLists: [],\n whitelist: [],\n whitelistPaths: {},\n hotlistLastFetched: 0,\n stalelistLastFetched: 0,\n c2DomainBlocklistLastFetched: 0,\n urlScanCache: {},\n tokenScanCache: {},\n };\n};\n\n/**\n * @type PhishingControllerState\n *\n * Phishing controller state\n * phishingLists - array of phishing lists\n * whitelist - origins that bypass the phishing detector\n * whitelistPaths - origins with paths that bypass the phishing detector\n * hotlistLastFetched - timestamp of the last hotlist fetch\n * stalelistLastFetched - timestamp of the last stalelist fetch\n * c2DomainBlocklistLastFetched - timestamp of the last c2 domain blocklist fetch\n * urlScanCache - cache of scan results\n */\nexport type PhishingControllerState = {\n phishingLists: PhishingListState[];\n whitelist: string[];\n whitelistPaths: PathTrie;\n hotlistLastFetched: number;\n stalelistLastFetched: number;\n c2DomainBlocklistLastFetched: number;\n urlScanCache: Record<string, CacheEntry<PhishingDetectionScanResult>>;\n tokenScanCache: Record<string, CacheEntry<TokenScanCacheData>>;\n};\n\n/**\n * PhishingControllerOptions\n *\n * Phishing controller options\n * stalelistRefreshInterval - Polling interval used to fetch stale list.\n * hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * urlScanCacheTTL - Time to live in seconds for cached scan results.\n * urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n */\nexport type PhishingControllerOptions = {\n stalelistRefreshInterval?: number;\n hotlistRefreshInterval?: number;\n c2DomainBlocklistRefreshInterval?: number;\n urlScanCacheTTL?: number;\n urlScanCacheMaxSize?: number;\n tokenScanCacheTTL?: number;\n tokenScanCacheMaxSize?: number;\n messenger: PhishingControllerMessenger;\n state?: Partial<PhishingControllerState>;\n};\n\nexport type MaybeUpdateState = {\n type: `${typeof controllerName}:maybeUpdateState`;\n handler: PhishingController['maybeUpdateState'];\n};\n\nexport type TestOrigin = {\n type: `${typeof controllerName}:testOrigin`;\n handler: PhishingController['test'];\n};\n\nexport type PhishingControllerBulkScanUrlsAction = {\n type: `${typeof controllerName}:bulkScanUrls`;\n handler: PhishingController['bulkScanUrls'];\n};\n\nexport type PhishingControllerBulkScanTokensAction = {\n type: `${typeof controllerName}:bulkScanTokens`;\n handler: PhishingController['bulkScanTokens'];\n};\n\nexport type PhishingControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerActions =\n | PhishingControllerGetStateAction\n | MaybeUpdateState\n | TestOrigin\n | PhishingControllerBulkScanUrlsAction\n | PhishingControllerBulkScanTokensAction;\n\nexport type PhishingControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerEvents = PhishingControllerStateChangeEvent;\n\n/**\n * The external actions available to the PhishingController.\n */\ntype AllowedActions = never;\n\n/**\n * The external events available to the PhishingController.\n */\nexport type AllowedEvents = TransactionControllerStateChangeEvent;\n\nexport type PhishingControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n PhishingControllerActions | AllowedActions,\n PhishingControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * BulkPhishingDetectionScanResponse\n *\n * Response for bulk phishing detection scan requests\n * results - Record of domain names and their corresponding phishing detection scan results\n *\n * errors - Record of domain names and their corresponding errors\n */\nexport type BulkPhishingDetectionScanResponse = {\n results: Record<string, PhishingDetectionScanResult>;\n errors: Record<string, string[]>;\n};\n\n/**\n * Controller that manages community-maintained lists of approved and unapproved website origins.\n */\nexport class PhishingController extends BaseController<\n typeof controllerName,\n PhishingControllerState,\n PhishingControllerMessenger\n> {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #detector: any;\n\n #stalelistRefreshInterval: number;\n\n #hotlistRefreshInterval: number;\n\n #c2DomainBlocklistRefreshInterval: number;\n\n readonly #urlScanCache: CacheManager<PhishingDetectionScanResult>;\n\n readonly #tokenScanCache: CacheManager<TokenScanCacheData>;\n\n #inProgressHotlistUpdate?: Promise<void>;\n\n #inProgressStalelistUpdate?: Promise<void>;\n\n #isProgressC2DomainBlocklistUpdate?: Promise<void>;\n\n readonly #transactionControllerStateChangeHandler: (\n state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) => void;\n\n /**\n * Construct a Phishing Controller.\n *\n * @param config - Initial options used to configure this controller.\n * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * @param config.c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * @param config.urlScanCacheTTL - Time to live in seconds for cached scan results.\n * @param config.urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * @param config.tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * @param config.tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n * @param config.messenger - The controller restricted messenger.\n * @param config.state - Initial state to set on this controller.\n */\n constructor({\n stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL,\n hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL,\n c2DomainBlocklistRefreshInterval = C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL,\n urlScanCacheTTL = DEFAULT_URL_SCAN_CACHE_TTL,\n urlScanCacheMaxSize = DEFAULT_URL_SCAN_CACHE_MAX_SIZE,\n tokenScanCacheTTL = DEFAULT_TOKEN_SCAN_CACHE_TTL,\n tokenScanCacheMaxSize = DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE,\n messenger,\n state = {},\n }: PhishingControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultState(),\n ...state,\n },\n });\n\n this.#stalelistRefreshInterval = stalelistRefreshInterval;\n this.#hotlistRefreshInterval = hotlistRefreshInterval;\n this.#c2DomainBlocklistRefreshInterval = c2DomainBlocklistRefreshInterval;\n this.#transactionControllerStateChangeHandler =\n this.#onTransactionControllerStateChange.bind(this);\n this.#urlScanCache = new CacheManager<PhishingDetectionScanResult>({\n cacheTTL: urlScanCacheTTL,\n maxCacheSize: urlScanCacheMaxSize,\n initialCache: this.state.urlScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.urlScanCache = cache;\n });\n },\n });\n this.#tokenScanCache = new CacheManager<TokenScanCacheData>({\n cacheTTL: tokenScanCacheTTL,\n maxCacheSize: tokenScanCacheMaxSize,\n initialCache: this.state.tokenScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.tokenScanCache = cache;\n });\n },\n });\n\n this.#registerMessageHandlers();\n\n this.updatePhishingDetector();\n this.#subscribeToTransactionControllerStateChange();\n }\n\n #subscribeToTransactionControllerStateChange() {\n this.messagingSystem.subscribe(\n 'TransactionController:stateChange',\n this.#transactionControllerStateChangeHandler,\n );\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:maybeUpdateState` as const,\n this.maybeUpdateState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:testOrigin` as const,\n this.test.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanUrls` as const,\n this.bulkScanUrls.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanTokens` as const,\n this.bulkScanTokens.bind(this),\n );\n }\n\n /**\n * Checks if a patch represents a transaction-level change or nested transaction property change\n *\n * @param patch - Immer patch to check\n * @returns True if patch affects a transaction or its nested properties\n */\n #isTransactionPatch(patch: Patch): boolean {\n const { path } = patch;\n return (\n path.length === 2 &&\n path[0] === 'transactions' &&\n typeof path[1] === 'number'\n );\n }\n\n /**\n * Handle transaction controller state changes using Immer patches\n * Extracts token addresses from simulation data and groups them by chain for bulk scanning\n *\n * @param _state - The current transaction controller state\n * @param _state.transactions - Array of transaction metadata\n * @param patches - Array of Immer patches only for transaction-level changes\n */\n #onTransactionControllerStateChange(\n _state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) {\n try {\n const tokensByChain = new Map<string, Set<string>>();\n\n for (const patch of patches) {\n if (patch.op === 'remove') {\n continue;\n }\n\n // Handle transaction-level patches (includes simulation data updates)\n if (this.#isTransactionPatch(patch)) {\n const transaction = patch.value as TransactionMeta;\n this.#getTokensFromTransaction(transaction, tokensByChain);\n }\n }\n\n this.#scanTokensByChain(tokensByChain);\n } catch (error) {\n console.error('Error processing transaction state change:', error);\n }\n }\n\n /**\n * Collect token addresses from a transaction and group them by chain\n *\n * @param transaction - Transaction metadata to extract tokens from\n * @param tokensByChain - Map to collect tokens grouped by chainId\n */\n #getTokensFromTransaction(\n transaction: TransactionMeta,\n tokensByChain: Map<string, Set<string>>,\n ) {\n // extract token addresses from simulation data\n const tokenAddresses = transaction.simulationData?.tokenBalanceChanges?.map(\n (tokenChange) => tokenChange.address.toLowerCase(),\n );\n\n // add token addresses to the map by chainId\n if (tokenAddresses && tokenAddresses.length > 0 && transaction.chainId) {\n const chainId = transaction.chainId.toLowerCase();\n\n if (!tokensByChain.has(chainId)) {\n tokensByChain.set(chainId, new Set());\n }\n\n const chainTokens = tokensByChain.get(chainId);\n if (chainTokens) {\n for (const address of tokenAddresses) {\n chainTokens.add(address);\n }\n }\n }\n }\n\n /**\n * Scan tokens grouped by chain ID\n *\n * @param tokensByChain - Map of chainId to token addresses\n */\n #scanTokensByChain(tokensByChain: Map<string, Set<string>>) {\n for (const [chainId, tokenSet] of tokensByChain) {\n if (tokenSet.size > 0) {\n const tokens = Array.from(tokenSet);\n this.bulkScanTokens({\n chainId,\n tokens,\n }).catch((error) =>\n console.error(`Error scanning tokens for chain ${chainId}:`, error),\n );\n }\n }\n }\n\n /**\n * Updates this.detector with an instance of PhishingDetector using the current state.\n */\n updatePhishingDetector() {\n this.#detector = new PhishingDetector(this.state.phishingLists);\n }\n\n /**\n * Set the interval at which the stale phishing list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateStalelist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setStalelistRefreshInterval(interval: number) {\n this.#stalelistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the hot list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setHotlistRefreshInterval(interval: number) {\n this.#hotlistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the C2 domain blocklist will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setC2DomainBlocklistRefreshInterval(interval: number) {\n this.#c2DomainBlocklistRefreshInterval = interval;\n }\n\n /**\n * Set the time-to-live for URL scan cache entries.\n *\n * @param ttl - The TTL in seconds.\n */\n setUrlScanCacheTTL(ttl: number) {\n this.#urlScanCache.setTTL(ttl);\n }\n\n /**\n * Set the maximum number of entries in the URL scan cache.\n *\n * @param maxSize - The maximum cache size.\n */\n setUrlScanCacheMaxSize(maxSize: number) {\n this.#urlScanCache.setMaxSize(maxSize);\n }\n\n /**\n * Clear the URL scan cache.\n */\n clearUrlScanCache() {\n this.#urlScanCache.clear();\n }\n\n /**\n * Determine if an update to the stalelist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isStalelistOutOfDate() {\n return (\n fetchTimeNow() - this.state.stalelistLastFetched >=\n this.#stalelistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the hotlist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isHotlistOutOfDate() {\n return (\n fetchTimeNow() - this.state.hotlistLastFetched >=\n this.#hotlistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the C2 domain blocklist is needed.\n *\n * @returns Whether an update is needed\n */\n isC2DomainBlocklistOutOfDate() {\n return (\n fetchTimeNow() - this.state.c2DomainBlocklistLastFetched >=\n this.#c2DomainBlocklistRefreshInterval\n );\n }\n\n /**\n * Conditionally update the phishing configuration.\n *\n * If the stalelist configuration is out of date, this function will call `updateStalelist`\n * to update the configuration. This will automatically grab the hotlist,\n * so it isn't necessary to continue on to download the hotlist and the c2 domain blocklist.\n *\n */\n async maybeUpdateState() {\n const staleListOutOfDate = this.isStalelistOutOfDate();\n if (staleListOutOfDate) {\n await this.updateStalelist();\n return;\n }\n const hotlistOutOfDate = this.isHotlistOutOfDate();\n if (hotlistOutOfDate) {\n await this.updateHotlist();\n }\n const c2DomainBlocklistOutOfDate = this.isC2DomainBlocklistOutOfDate();\n if (c2DomainBlocklistOutOfDate) {\n await this.updateC2DomainBlocklist();\n }\n }\n\n /**\n * Determines if a given origin is unapproved.\n *\n * It is strongly recommended that you call {@link maybeUpdateState} before calling this,\n * to check whether the phishing configuration is up-to-date. It will be updated if necessary\n * by calling {@link updateStalelist} or {@link updateHotlist}.\n *\n * @param origin - Domain origin of a website.\n * @returns Whether the origin is an unapproved origin.\n */\n test(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n\n if (matchedPathPrefix(hostnameWithPaths, this.state.whitelistPaths)) {\n return { result: false, type: PhishingDetectorResultType.All };\n }\n\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.check(punycodeOrigin);\n }\n\n /**\n * Checks if a request URL's domain is blocked against the request blocklist.\n *\n * This method is used to determine if a specific request URL is associated with a malicious\n * command and control (C2) domain. The URL's hostname is hashed and checked against a configured\n * blocklist of known malicious domains.\n *\n * @param origin - The full request URL to be checked.\n * @returns An object indicating whether the URL's domain is blocked and relevant metadata.\n */\n isBlockedRequest(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.isMaliciousC2Domain(punycodeOrigin);\n }\n\n /**\n * Temporarily marks a given origin as approved.\n *\n * @param origin - The origin to mark as approved.\n */\n bypass(origin: string) {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n const { whitelist, whitelistPaths } = this.state;\n const whitelistPath = matchedPathPrefix(hostnameWithPaths, whitelistPaths);\n\n if (whitelist.includes(hostname || punycodeOrigin) || whitelistPath) {\n return;\n }\n\n // If the origin was blocked by a path, then we only want to add it to the whitelistPaths since\n // other paths with the same hostname may not be blocked.\n const blockingPath = this.#detector.blockingPath(origin);\n if (blockingPath) {\n this.update((draftState) => {\n insertToTrie(blockingPath, draftState.whitelistPaths);\n });\n return;\n }\n\n this.update((draftState) => {\n draftState.whitelist.push(hostname || punycodeOrigin);\n });\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateC2DomainBlocklist() {\n if (this.#isProgressC2DomainBlocklistUpdate) {\n await this.#isProgressC2DomainBlocklistUpdate;\n return;\n }\n\n try {\n this.#isProgressC2DomainBlocklistUpdate = this.#updateC2DomainBlocklist();\n await this.#isProgressC2DomainBlocklistUpdate;\n } finally {\n this.#isProgressC2DomainBlocklistUpdate = undefined;\n }\n }\n\n /**\n * Update the hotlist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateHotlist() {\n if (this.#inProgressHotlistUpdate) {\n await this.#inProgressHotlistUpdate;\n return;\n }\n\n try {\n this.#inProgressHotlistUpdate = this.#updateHotlist();\n await this.#inProgressHotlistUpdate;\n } finally {\n this.#inProgressHotlistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateStalelist() {\n if (this.#inProgressStalelistUpdate) {\n await this.#inProgressStalelistUpdate;\n return;\n }\n\n try {\n this.#inProgressStalelistUpdate = this.#updateStalelist();\n await this.#inProgressStalelistUpdate;\n } finally {\n this.#inProgressStalelistUpdate = undefined;\n }\n }\n\n /**\n * Scan a URL for phishing. It will only scan the hostname of the URL. It also only supports\n * web URLs.\n *\n * @param url - The URL to scan.\n * @returns The phishing detection scan result.\n */\n scanUrl = async (url: string): Promise<PhishingDetectionScanResult> => {\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'url is not a valid web URL',\n };\n }\n\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n return cachedResult;\n }\n\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_SCAN_ENDPOINT}?url=${encodeURIComponent(hostname)}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n };\n }\n const data = await res.json();\n return data;\n },\n true,\n 8000,\n );\n\n // Need to do it this way because safelyExecuteWithTimeout returns undefined for both timeouts and errors.\n if (!apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'timeout of 8000ms exceeded',\n };\n } else if ('error' in apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: apiResponse.error,\n };\n }\n\n const result = {\n hostname,\n recommendedAction: apiResponse.recommendedAction,\n };\n\n this.#urlScanCache.set(hostname, result);\n\n return result;\n };\n\n /**\n * Scan multiple URLs for phishing in bulk. It will only scan the hostnames of the URLs.\n * It also only supports web URLs.\n *\n * @param urls - The URLs to scan.\n * @returns A mapping of URLs to their phishing detection scan results and errors.\n */\n bulkScanUrls = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n if (!urls || urls.length === 0) {\n return {\n results: {},\n errors: {},\n };\n }\n\n // we are arbitrarily limiting the number of URLs to 250\n const MAX_TOTAL_URLS = 250;\n if (urls.length > MAX_TOTAL_URLS) {\n return {\n results: {},\n errors: {\n too_many_urls: [\n `Maximum of ${MAX_TOTAL_URLS} URLs allowed per request`,\n ],\n },\n };\n }\n\n const MAX_URL_LENGTH = 2048;\n const combinedResponse: BulkPhishingDetectionScanResponse = {\n results: {},\n errors: {},\n };\n\n // Extract hostnames from URLs and check for validity and length constraints\n const urlsToHostnames: Record<string, string> = {};\n const urlsToFetch: string[] = [];\n\n for (const url of urls) {\n if (url.length > MAX_URL_LENGTH) {\n combinedResponse.errors[url] = [\n `URL length must not exceed ${MAX_URL_LENGTH} characters`,\n ];\n continue;\n }\n\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n combinedResponse.errors[url] = ['url is not a valid web URL'];\n continue;\n }\n\n // Check if result is already in cache\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n // Use cached result\n combinedResponse.results[url] = cachedResult;\n } else {\n // Add to list of URLs to fetch\n urlsToHostnames[url] = hostname;\n urlsToFetch.push(url);\n }\n }\n\n // If there are URLs to fetch, process them in batches\n if (urlsToFetch.length > 0) {\n // The API has a limit of 50 URLs per request, so we batch the requests\n const MAX_URLS_PER_BATCH = 50;\n const batches: string[][] = [];\n for (let i = 0; i < urlsToFetch.length; i += MAX_URLS_PER_BATCH) {\n batches.push(urlsToFetch.slice(i, i + MAX_URLS_PER_BATCH));\n }\n\n // Process each batch in parallel\n const batchResults = await Promise.all(\n batches.map((batchUrls) => this.#processBatch(batchUrls)),\n );\n\n // Merge results and errors from all batches\n batchResults.forEach((batchResponse) => {\n // Add results to cache and combine with response\n Object.entries(batchResponse.results).forEach(([url, result]) => {\n const hostname = urlsToHostnames[url];\n if (hostname) {\n this.#urlScanCache.set(hostname, result);\n }\n combinedResponse.results[url] = result;\n });\n\n // Combine errors\n Object.entries(batchResponse.errors).forEach(([key, messages]) => {\n combinedResponse.errors[key] = [\n ...(combinedResponse.errors[key] || []),\n ...messages,\n ];\n });\n });\n }\n\n return combinedResponse;\n };\n\n /**\n * Fetch bulk token scan results from the security alerts API.\n *\n * @param chain - The chain name.\n * @param tokens - Array of token addresses to scan.\n * @returns The API response or null if there was an error.\n */\n readonly #fetchTokenScanBulkResults = async (\n chain: string,\n tokens: string[],\n ): Promise<TokenScanApiResponse | null> => {\n const timeout = 8000; // 8 seconds\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const response = await fetch(\n `${SECURITY_ALERTS_BASE_URL}${TOKEN_BULK_SCANNING_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n chain,\n tokens,\n }),\n },\n );\n\n if (!response.ok) {\n return {\n error: `${response.status} ${response.statusText}`,\n status: response.status,\n statusText: response.statusText,\n };\n }\n\n const data = await response.json();\n return data;\n },\n true,\n timeout,\n );\n\n if (!apiResponse) {\n console.error(`Error scanning tokens: timeout of ${timeout}ms exceeded`);\n return null;\n }\n\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n console.warn(\n `Token bulk screening API error: ${apiResponse.status} ${apiResponse.statusText}`,\n );\n return null;\n }\n\n return apiResponse as TokenScanApiResponse;\n };\n\n /**\n * Scan multiple tokens for malicious activity in bulk.\n *\n * @param request - The bulk scan request containing chainId and tokens.\n * @param request.chainId - The chain ID in hex format (e.g., '0x1' for Ethereum).\n * @param request.tokens - Array of token addresses to scan.\n * @returns A mapping of lowercase token addresses to their scan results. Tokens that fail to scan are omitted.\n */\n bulkScanTokens = async (\n request: BulkTokenScanRequest,\n ): Promise<BulkTokenScanResponse> => {\n const { chainId, tokens } = request;\n\n if (!tokens || tokens.length === 0) {\n return {};\n }\n\n const MAX_TOKENS_PER_REQUEST = 100;\n if (tokens.length > MAX_TOKENS_PER_REQUEST) {\n console.warn(\n `Maximum of ${MAX_TOKENS_PER_REQUEST} tokens allowed per request`,\n );\n return {};\n }\n\n const normalizedChainId = chainId.toLowerCase();\n const chain = resolveChainName(normalizedChainId);\n\n if (!chain) {\n console.warn(`Unknown chain ID: ${chainId}`);\n return {};\n }\n\n // Split tokens into cached results and tokens that need to be fetched\n const { cachedResults, tokensToFetch } = splitCacheHits(\n this.#tokenScanCache,\n normalizedChainId,\n tokens,\n );\n\n const results: BulkTokenScanResponse = { ...cachedResults };\n\n // If there are tokens to fetch, call the bulk token scan API\n if (tokensToFetch.length > 0) {\n const apiResponse = await this.#fetchTokenScanBulkResults(\n chain,\n tokensToFetch,\n );\n\n if (apiResponse?.results) {\n // Process API results and update cache\n for (const tokenAddress of tokensToFetch) {\n const normalizedAddress = tokenAddress.toLowerCase();\n const tokenResult = apiResponse.results[normalizedAddress];\n\n if (tokenResult?.result_type) {\n const result = {\n result_type: tokenResult.result_type,\n chain: tokenResult.chain || normalizedChainId,\n address: tokenResult.address || normalizedAddress,\n };\n\n // Update cache\n const cacheKey = buildCacheKey(\n normalizedChainId,\n normalizedAddress,\n );\n this.#tokenScanCache.set(cacheKey, {\n result_type: tokenResult.result_type,\n });\n\n results[normalizedAddress] = result;\n }\n }\n }\n }\n\n return results;\n };\n\n /**\n * Process a batch of URLs (up to 50) for phishing detection.\n *\n * @param urls - A batch of URLs to scan.\n * @returns The scan results and errors for this batch.\n */\n readonly #processBatch = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_BULK_SCAN_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ urls }),\n },\n );\n\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n status: res.status,\n statusText: res.statusText,\n };\n }\n\n const data = await res.json();\n return data;\n },\n true,\n 15000,\n );\n\n // Handle timeout or network errors\n if (!apiResponse) {\n return {\n results: {},\n errors: {\n network_error: ['timeout of 15000ms exceeded'],\n },\n };\n }\n\n // Handle HTTP error responses\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n return {\n results: {},\n errors: {\n api_error: [`${apiResponse.status} ${apiResponse.statusText}`],\n },\n };\n }\n\n return apiResponse as BulkPhishingDetectionScanResponse;\n };\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateStalelist() {\n let stalelistResponse: DataResultWrapper<PhishingStalelist> | null = null;\n let hotlistDiffsResponse: DataResultWrapper<Hotlist> | null = null;\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n try {\n const stalelistPromise = this.#queryConfig<\n DataResultWrapper<PhishingStalelist>\n >(METAMASK_STALELIST_URL);\n\n const c2DomainBlocklistPromise =\n this.#queryConfig<C2DomainBlocklistResponse>(C2_DOMAIN_BLOCKLIST_URL);\n\n [stalelistResponse, c2DomainBlocklistResponse] = await Promise.all([\n stalelistPromise,\n c2DomainBlocklistPromise,\n ]);\n // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,\n // so it doesn't make sense to call if there is not a timestamp to begin with.\n if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {\n hotlistDiffsResponse = await this.#queryConfig<\n DataResultWrapper<Hotlist>\n >(`${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);\n }\n } finally {\n // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server\n // from being overwhelmed with traffic after a network disruption.\n const timeNow = fetchTimeNow();\n this.update((draftState) => {\n draftState.stalelistLastFetched = timeNow;\n draftState.hotlistLastFetched = timeNow;\n draftState.c2DomainBlocklistLastFetched = timeNow;\n });\n }\n\n if (!stalelistResponse || !hotlistDiffsResponse) {\n return;\n }\n\n const metamaskListState: PhishingListState = {\n allowlist: stalelistResponse.data.allowlist,\n fuzzylist: stalelistResponse.data.fuzzylist,\n tolerance: stalelistResponse.data.tolerance,\n version: stalelistResponse.data.version,\n lastUpdated: stalelistResponse.data.lastUpdated,\n blocklist: stalelistResponse.data.blocklist,\n blocklistPaths: convertListToTrie(stalelistResponse.data.blocklistPaths),\n c2DomainBlocklist: c2DomainBlocklistResponse\n ? c2DomainBlocklistResponse.recentlyAdded\n : [],\n name: phishingListKeyNameMap.eth_phishing_detect_config,\n };\n\n const newMetaMaskListState: PhishingListState = applyDiffs(\n metamaskListState,\n hotlistDiffsResponse.data,\n ListKeys.EthPhishingDetectConfig,\n );\n\n this.update((draftState) => {\n draftState.phishingLists = [newMetaMaskListState];\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateHotlist() {\n let hotlistResponse: DataResultWrapper<Hotlist> | null;\n\n try {\n if (this.state.phishingLists.length === 0) {\n return;\n }\n\n const lastDiffTimestamp = Math.max(\n ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated),\n );\n\n hotlistResponse = await this.#queryConfig<DataResultWrapper<Hotlist>>(\n `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`,\n );\n } finally {\n // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.hotlistLastFetched = fetchTimeNow();\n });\n }\n\n if (!hotlistResponse?.data) {\n return;\n }\n const hotlist = hotlistResponse.data;\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n hotlist,\n phishingListNameKeyMap[phishingList.name],\n [],\n [],\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * This should only be called from the `updateC2DomainBlocklist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateC2DomainBlocklist() {\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n\n try {\n c2DomainBlocklistResponse =\n await this.#queryConfig<C2DomainBlocklistResponse>(\n `${C2_DOMAIN_BLOCKLIST_URL}?timestamp=${roundToNearestMinute(\n this.state.c2DomainBlocklistLastFetched,\n )}`,\n );\n } finally {\n // Set `c2DomainBlocklistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.c2DomainBlocklistLastFetched = fetchTimeNow();\n });\n }\n\n if (!c2DomainBlocklistResponse) {\n return;\n }\n\n const recentlyAddedC2Domains = c2DomainBlocklistResponse.recentlyAdded;\n const recentlyRemovedC2Domains = c2DomainBlocklistResponse.recentlyRemoved;\n\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n [],\n phishingListNameKeyMap[phishingList.name],\n recentlyAddedC2Domains,\n recentlyRemovedC2Domains,\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n async #queryConfig<ResponseType>(\n input: RequestInfo,\n ): Promise<ResponseType | null> {\n const response = await safelyExecute(\n () => fetch(input, { cache: 'no-cache' }),\n true,\n );\n\n switch (response?.status) {\n case 200: {\n return await response.json();\n }\n\n default: {\n return null;\n }\n }\n }\n}\n\nexport default PhishingController;\n\nexport type { PhishingDetectorResult };\n"]}
|
1
|
+
{"version":3,"file":"PhishingController.cjs","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type {\n TransactionControllerStateChangeEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Patch } from 'immer';\nimport { toASCII } from 'punycode/punycode.js';\n\nimport { CacheManager, type CacheEntry } from './CacheManager';\nimport {\n type PathTrie,\n convertListToTrie,\n insertToTrie,\n matchedPathPrefix,\n} from './PathTrie';\nimport { PhishingDetector } from './PhishingDetector';\nimport {\n PhishingDetectorResultType,\n type PhishingDetectorResult,\n type PhishingDetectionScanResult,\n RecommendedAction,\n type TokenScanCacheData,\n type BulkTokenScanResponse,\n type BulkTokenScanRequest,\n type TokenScanApiResponse,\n} from './types';\nimport {\n applyDiffs,\n fetchTimeNow,\n getHostnameFromUrl,\n roundToNearestMinute,\n getHostnameFromWebUrl,\n buildCacheKey,\n splitCacheHits,\n resolveChainName,\n getPathnameFromUrl,\n} from './utils';\n\nexport const PHISHING_CONFIG_BASE_URL =\n 'https://phishing-detection.api.cx.metamask.io';\nexport const METAMASK_STALELIST_FILE = '/v1/stalelist';\nexport const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince';\n\nexport const CLIENT_SIDE_DETECION_BASE_URL =\n 'https://client-side-detection.api.cx.metamask.io';\nexport const C2_DOMAIN_BLOCKLIST_ENDPOINT = '/v1/request-blocklist';\n\nexport const PHISHING_DETECTION_BASE_URL =\n 'https://dapp-scanning.api.cx.metamask.io';\nexport const PHISHING_DETECTION_SCAN_ENDPOINT = 'v2/scan';\nexport const PHISHING_DETECTION_BULK_SCAN_ENDPOINT = 'bulk-scan';\n\nexport const SECURITY_ALERTS_BASE_URL =\n 'https://security-alerts.api.cx.metamask.io';\nexport const TOKEN_BULK_SCANNING_ENDPOINT = '/token/scan-bulk';\n\n// Cache configuration defaults\nexport const DEFAULT_URL_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_URL_SCAN_CACHE_MAX_SIZE = 250;\nexport const DEFAULT_TOKEN_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE = 1000;\n\nexport const C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const HOTLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const STALELIST_REFRESH_INTERVAL = 30 * 24 * 60 * 60; // 30 days in seconds\n\nexport const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`;\nexport const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`;\nexport const C2_DOMAIN_BLOCKLIST_URL = `${CLIENT_SIDE_DETECION_BASE_URL}${C2_DOMAIN_BLOCKLIST_ENDPOINT}`;\n\n/**\n * @type ListTypes\n *\n * Type outlining the types of lists provided by aggregating different source lists\n */\nexport type ListTypes =\n | 'fuzzylist'\n | 'blocklist'\n | 'blocklistPaths'\n | 'allowlist'\n | 'c2DomainBlocklist';\n\n/**\n * @type EthPhishingResponse\n *\n * Configuration response from the eth-phishing-detect package\n * consisting of approved and unapproved website origins\n * @property blacklist - List of unapproved origins\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property version - Version number of this configuration\n * @property whitelist - List of approved origins\n */\nexport type EthPhishingResponse = {\n blacklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n whitelist: string[];\n};\n\n/**\n * @type C2DomainBlocklistResponse\n *\n * Response for blocklist update requests\n * @property recentlyAdded - List of c2 domains recently added to the blocklist\n * @property recentlyRemoved - List of c2 domains recently removed from the blocklist\n * @property lastFetchedAt - Timestamp of the last fetch request\n */\nexport type C2DomainBlocklistResponse = {\n recentlyAdded: string[];\n recentlyRemoved: string[];\n lastFetchedAt: string;\n};\n\n/**\n * PhishingStalelist defines the expected type of the stalelist from the API.\n *\n * allowlist - List of approved origins.\n * blocklist - List of unapproved origins (hostname-only entries).\n * blocklistPaths - Trie of unapproved origins with paths (hostname + path entries).\n * fuzzylist - List of fuzzy-matched unapproved origins.\n * tolerance - Fuzzy match tolerance level\n * lastUpdated - Timestamp of last update.\n * version - Stalelist data structure iteration.\n */\nexport type PhishingStalelist = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n};\n\n/**\n * @type PhishingListState\n *\n * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`.\n * @property allowlist - List of approved origins (legacy naming \"whitelist\")\n * @property blocklist - List of unapproved origins (legacy naming \"blacklist\")\n * @property blocklistPaths - Trie of unapproved origins with paths (hostname + path, no query params).\n * @property c2DomainBlocklist - List of hashed hostnames that C2 requests are blocked against.\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Version of the phishing list state.\n * @property name - Name of the list. Used for attribution.\n */\nexport type PhishingListState = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: PathTrie;\n c2DomainBlocklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n name: ListNames;\n};\n\n/**\n * @type HotlistDiff\n *\n * type defining the expected type of the diffs in hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type HotlistDiff = {\n url: string;\n timestamp: number;\n targetList: `${ListKeys}.${ListTypes}`;\n isRemoval?: boolean;\n};\n\nexport type DataResultWrapper<T> = {\n data: T;\n};\n\n/**\n * @type Hotlist\n *\n * Type defining expected hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type Hotlist = HotlistDiff[];\n\n/**\n * Enum containing upstream data provider source list keys.\n * These are the keys denoting lists consumed by the upstream data provider.\n */\nexport enum ListKeys {\n EthPhishingDetectConfig = 'eth_phishing_detect_config',\n}\n\n/**\n * Enum containing downstream client attribution names.\n */\nexport enum ListNames {\n MetaMask = 'MetaMask',\n}\n\n/**\n * Maps from downstream client attribution name\n * to list key sourced from upstream data provider.\n */\nconst phishingListNameKeyMap = {\n [ListNames.MetaMask]: ListKeys.EthPhishingDetectConfig,\n};\n\n/**\n * Maps from list key sourced from upstream data\n * provider to downstream client attribution name.\n */\nexport const phishingListKeyNameMap = {\n [ListKeys.EthPhishingDetectConfig]: ListNames.MetaMask,\n};\n\nconst controllerName = 'PhishingController';\n\nconst metadata: StateMetadata<PhishingControllerState> = {\n phishingLists: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelist: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelistPaths: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n hotlistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n stalelistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n c2DomainBlocklistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n urlScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n tokenScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n};\n\n/**\n * Get a default empty state for the controller.\n *\n * @returns The default empty state.\n */\nconst getDefaultState = (): PhishingControllerState => {\n return {\n phishingLists: [],\n whitelist: [],\n whitelistPaths: {},\n hotlistLastFetched: 0,\n stalelistLastFetched: 0,\n c2DomainBlocklistLastFetched: 0,\n urlScanCache: {},\n tokenScanCache: {},\n };\n};\n\n/**\n * @type PhishingControllerState\n *\n * Phishing controller state\n * phishingLists - array of phishing lists\n * whitelist - origins that bypass the phishing detector\n * whitelistPaths - origins with paths that bypass the phishing detector\n * hotlistLastFetched - timestamp of the last hotlist fetch\n * stalelistLastFetched - timestamp of the last stalelist fetch\n * c2DomainBlocklistLastFetched - timestamp of the last c2 domain blocklist fetch\n * urlScanCache - cache of scan results\n */\nexport type PhishingControllerState = {\n phishingLists: PhishingListState[];\n whitelist: string[];\n whitelistPaths: PathTrie;\n hotlistLastFetched: number;\n stalelistLastFetched: number;\n c2DomainBlocklistLastFetched: number;\n urlScanCache: Record<string, CacheEntry<PhishingDetectionScanResult>>;\n tokenScanCache: Record<string, CacheEntry<TokenScanCacheData>>;\n};\n\n/**\n * PhishingControllerOptions\n *\n * Phishing controller options\n * stalelistRefreshInterval - Polling interval used to fetch stale list.\n * hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * urlScanCacheTTL - Time to live in seconds for cached scan results.\n * urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n */\nexport type PhishingControllerOptions = {\n stalelistRefreshInterval?: number;\n hotlistRefreshInterval?: number;\n c2DomainBlocklistRefreshInterval?: number;\n urlScanCacheTTL?: number;\n urlScanCacheMaxSize?: number;\n tokenScanCacheTTL?: number;\n tokenScanCacheMaxSize?: number;\n messenger: PhishingControllerMessenger;\n state?: Partial<PhishingControllerState>;\n};\n\nexport type MaybeUpdateState = {\n type: `${typeof controllerName}:maybeUpdateState`;\n handler: PhishingController['maybeUpdateState'];\n};\n\nexport type TestOrigin = {\n type: `${typeof controllerName}:testOrigin`;\n handler: PhishingController['test'];\n};\n\nexport type PhishingControllerBulkScanUrlsAction = {\n type: `${typeof controllerName}:bulkScanUrls`;\n handler: PhishingController['bulkScanUrls'];\n};\n\nexport type PhishingControllerBulkScanTokensAction = {\n type: `${typeof controllerName}:bulkScanTokens`;\n handler: PhishingController['bulkScanTokens'];\n};\n\nexport type PhishingControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerActions =\n | PhishingControllerGetStateAction\n | MaybeUpdateState\n | TestOrigin\n | PhishingControllerBulkScanUrlsAction\n | PhishingControllerBulkScanTokensAction;\n\nexport type PhishingControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerEvents = PhishingControllerStateChangeEvent;\n\n/**\n * The external actions available to the PhishingController.\n */\ntype AllowedActions = never;\n\n/**\n * The external events available to the PhishingController.\n */\nexport type AllowedEvents = TransactionControllerStateChangeEvent;\n\nexport type PhishingControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n PhishingControllerActions | AllowedActions,\n PhishingControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * BulkPhishingDetectionScanResponse\n *\n * Response for bulk phishing detection scan requests\n * results - Record of domain names and their corresponding phishing detection scan results\n *\n * errors - Record of domain names and their corresponding errors\n */\nexport type BulkPhishingDetectionScanResponse = {\n results: Record<string, PhishingDetectionScanResult>;\n errors: Record<string, string[]>;\n};\n\n/**\n * Controller that manages community-maintained lists of approved and unapproved website origins.\n */\nexport class PhishingController extends BaseController<\n typeof controllerName,\n PhishingControllerState,\n PhishingControllerMessenger\n> {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #detector: any;\n\n #stalelistRefreshInterval: number;\n\n #hotlistRefreshInterval: number;\n\n #c2DomainBlocklistRefreshInterval: number;\n\n readonly #urlScanCache: CacheManager<PhishingDetectionScanResult>;\n\n readonly #tokenScanCache: CacheManager<TokenScanCacheData>;\n\n #inProgressHotlistUpdate?: Promise<void>;\n\n #inProgressStalelistUpdate?: Promise<void>;\n\n #isProgressC2DomainBlocklistUpdate?: Promise<void>;\n\n readonly #transactionControllerStateChangeHandler: (\n state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) => void;\n\n /**\n * Construct a Phishing Controller.\n *\n * @param config - Initial options used to configure this controller.\n * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * @param config.c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * @param config.urlScanCacheTTL - Time to live in seconds for cached scan results.\n * @param config.urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * @param config.tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * @param config.tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n * @param config.messenger - The controller restricted messenger.\n * @param config.state - Initial state to set on this controller.\n */\n constructor({\n stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL,\n hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL,\n c2DomainBlocklistRefreshInterval = C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL,\n urlScanCacheTTL = DEFAULT_URL_SCAN_CACHE_TTL,\n urlScanCacheMaxSize = DEFAULT_URL_SCAN_CACHE_MAX_SIZE,\n tokenScanCacheTTL = DEFAULT_TOKEN_SCAN_CACHE_TTL,\n tokenScanCacheMaxSize = DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE,\n messenger,\n state = {},\n }: PhishingControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultState(),\n ...state,\n },\n });\n\n this.#stalelistRefreshInterval = stalelistRefreshInterval;\n this.#hotlistRefreshInterval = hotlistRefreshInterval;\n this.#c2DomainBlocklistRefreshInterval = c2DomainBlocklistRefreshInterval;\n this.#transactionControllerStateChangeHandler =\n this.#onTransactionControllerStateChange.bind(this);\n this.#urlScanCache = new CacheManager<PhishingDetectionScanResult>({\n cacheTTL: urlScanCacheTTL,\n maxCacheSize: urlScanCacheMaxSize,\n initialCache: this.state.urlScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.urlScanCache = cache;\n });\n },\n });\n this.#tokenScanCache = new CacheManager<TokenScanCacheData>({\n cacheTTL: tokenScanCacheTTL,\n maxCacheSize: tokenScanCacheMaxSize,\n initialCache: this.state.tokenScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.tokenScanCache = cache;\n });\n },\n });\n\n this.#registerMessageHandlers();\n\n this.updatePhishingDetector();\n this.#subscribeToTransactionControllerStateChange();\n }\n\n #subscribeToTransactionControllerStateChange() {\n this.messagingSystem.subscribe(\n 'TransactionController:stateChange',\n this.#transactionControllerStateChangeHandler,\n );\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:maybeUpdateState` as const,\n this.maybeUpdateState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:testOrigin` as const,\n this.test.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanUrls` as const,\n this.bulkScanUrls.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanTokens` as const,\n this.bulkScanTokens.bind(this),\n );\n }\n\n /**\n * Checks if a patch represents a transaction-level change or nested transaction property change\n *\n * @param patch - Immer patch to check\n * @returns True if patch affects a transaction or its nested properties\n */\n #isTransactionPatch(patch: Patch): boolean {\n const { path } = patch;\n return (\n path.length === 2 &&\n path[0] === 'transactions' &&\n typeof path[1] === 'number'\n );\n }\n\n /**\n * Handle transaction controller state changes using Immer patches\n * Extracts token addresses from simulation data and groups them by chain for bulk scanning\n *\n * @param _state - The current transaction controller state\n * @param _state.transactions - Array of transaction metadata\n * @param patches - Array of Immer patches only for transaction-level changes\n */\n #onTransactionControllerStateChange(\n _state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) {\n try {\n const tokensByChain = new Map<string, Set<string>>();\n\n for (const patch of patches) {\n if (patch.op === 'remove') {\n continue;\n }\n\n // Handle transaction-level patches (includes simulation data updates)\n if (this.#isTransactionPatch(patch)) {\n const transaction = patch.value as TransactionMeta;\n this.#getTokensFromTransaction(transaction, tokensByChain);\n }\n }\n\n this.#scanTokensByChain(tokensByChain);\n } catch (error) {\n console.error('Error processing transaction state change:', error);\n }\n }\n\n /**\n * Collect token addresses from a transaction and group them by chain\n *\n * @param transaction - Transaction metadata to extract tokens from\n * @param tokensByChain - Map to collect tokens grouped by chainId\n */\n #getTokensFromTransaction(\n transaction: TransactionMeta,\n tokensByChain: Map<string, Set<string>>,\n ) {\n // extract token addresses from simulation data\n const tokenAddresses = transaction.simulationData?.tokenBalanceChanges?.map(\n (tokenChange) => tokenChange.address.toLowerCase(),\n );\n\n // add token addresses to the map by chainId\n if (tokenAddresses && tokenAddresses.length > 0 && transaction.chainId) {\n const chainId = transaction.chainId.toLowerCase();\n\n if (!tokensByChain.has(chainId)) {\n tokensByChain.set(chainId, new Set());\n }\n\n const chainTokens = tokensByChain.get(chainId);\n if (chainTokens) {\n for (const address of tokenAddresses) {\n chainTokens.add(address);\n }\n }\n }\n }\n\n /**\n * Scan tokens grouped by chain ID\n *\n * @param tokensByChain - Map of chainId to token addresses\n */\n #scanTokensByChain(tokensByChain: Map<string, Set<string>>) {\n for (const [chainId, tokenSet] of tokensByChain) {\n if (tokenSet.size > 0) {\n const tokens = Array.from(tokenSet);\n this.bulkScanTokens({\n chainId,\n tokens,\n }).catch((error) =>\n console.error(`Error scanning tokens for chain ${chainId}:`, error),\n );\n }\n }\n }\n\n /**\n * Updates this.detector with an instance of PhishingDetector using the current state.\n */\n updatePhishingDetector() {\n this.#detector = new PhishingDetector(this.state.phishingLists);\n }\n\n /**\n * Set the interval at which the stale phishing list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateStalelist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setStalelistRefreshInterval(interval: number) {\n this.#stalelistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the hot list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setHotlistRefreshInterval(interval: number) {\n this.#hotlistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the C2 domain blocklist will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setC2DomainBlocklistRefreshInterval(interval: number) {\n this.#c2DomainBlocklistRefreshInterval = interval;\n }\n\n /**\n * Set the time-to-live for URL scan cache entries.\n *\n * @param ttl - The TTL in seconds.\n */\n setUrlScanCacheTTL(ttl: number) {\n this.#urlScanCache.setTTL(ttl);\n }\n\n /**\n * Set the maximum number of entries in the URL scan cache.\n *\n * @param maxSize - The maximum cache size.\n */\n setUrlScanCacheMaxSize(maxSize: number) {\n this.#urlScanCache.setMaxSize(maxSize);\n }\n\n /**\n * Clear the URL scan cache.\n */\n clearUrlScanCache() {\n this.#urlScanCache.clear();\n }\n\n /**\n * Determine if an update to the stalelist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isStalelistOutOfDate() {\n return (\n fetchTimeNow() - this.state.stalelistLastFetched >=\n this.#stalelistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the hotlist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isHotlistOutOfDate() {\n return (\n fetchTimeNow() - this.state.hotlistLastFetched >=\n this.#hotlistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the C2 domain blocklist is needed.\n *\n * @returns Whether an update is needed\n */\n isC2DomainBlocklistOutOfDate() {\n return (\n fetchTimeNow() - this.state.c2DomainBlocklistLastFetched >=\n this.#c2DomainBlocklistRefreshInterval\n );\n }\n\n /**\n * Conditionally update the phishing configuration.\n *\n * If the stalelist configuration is out of date, this function will call `updateStalelist`\n * to update the configuration. This will automatically grab the hotlist,\n * so it isn't necessary to continue on to download the hotlist and the c2 domain blocklist.\n *\n */\n async maybeUpdateState() {\n const staleListOutOfDate = this.isStalelistOutOfDate();\n if (staleListOutOfDate) {\n await this.updateStalelist();\n return;\n }\n const hotlistOutOfDate = this.isHotlistOutOfDate();\n if (hotlistOutOfDate) {\n await this.updateHotlist();\n }\n const c2DomainBlocklistOutOfDate = this.isC2DomainBlocklistOutOfDate();\n if (c2DomainBlocklistOutOfDate) {\n await this.updateC2DomainBlocklist();\n }\n }\n\n /**\n * Determines if a given origin is unapproved.\n *\n * It is strongly recommended that you call {@link maybeUpdateState} before calling this,\n * to check whether the phishing configuration is up-to-date. It will be updated if necessary\n * by calling {@link updateStalelist} or {@link updateHotlist}.\n *\n * @param origin - Domain origin of a website.\n * @returns Whether the origin is an unapproved origin.\n */\n test(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n\n if (matchedPathPrefix(hostnameWithPaths, this.state.whitelistPaths)) {\n return { result: false, type: PhishingDetectorResultType.All };\n }\n\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.check(punycodeOrigin);\n }\n\n /**\n * Checks if a request URL's domain is blocked against the request blocklist.\n *\n * This method is used to determine if a specific request URL is associated with a malicious\n * command and control (C2) domain. The URL's hostname is hashed and checked against a configured\n * blocklist of known malicious domains.\n *\n * @param origin - The full request URL to be checked.\n * @returns An object indicating whether the URL's domain is blocked and relevant metadata.\n */\n isBlockedRequest(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.isMaliciousC2Domain(punycodeOrigin);\n }\n\n /**\n * Temporarily marks a given origin as approved.\n *\n * @param origin - The origin to mark as approved.\n */\n bypass(origin: string) {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n const { whitelist, whitelistPaths } = this.state;\n const whitelistPath = matchedPathPrefix(hostnameWithPaths, whitelistPaths);\n\n if (whitelist.includes(hostname || punycodeOrigin) || whitelistPath) {\n return;\n }\n\n // If the origin was blocked by a path, then we only want to add it to the whitelistPaths since\n // other paths with the same hostname may not be blocked.\n const blockingPath = this.#detector.blockingPath(origin);\n if (blockingPath) {\n this.update((draftState) => {\n insertToTrie(blockingPath, draftState.whitelistPaths);\n });\n return;\n }\n\n this.update((draftState) => {\n draftState.whitelist.push(hostname || punycodeOrigin);\n });\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateC2DomainBlocklist() {\n if (this.#isProgressC2DomainBlocklistUpdate) {\n await this.#isProgressC2DomainBlocklistUpdate;\n return;\n }\n\n try {\n this.#isProgressC2DomainBlocklistUpdate = this.#updateC2DomainBlocklist();\n await this.#isProgressC2DomainBlocklistUpdate;\n } finally {\n this.#isProgressC2DomainBlocklistUpdate = undefined;\n }\n }\n\n /**\n * Update the hotlist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateHotlist() {\n if (this.#inProgressHotlistUpdate) {\n await this.#inProgressHotlistUpdate;\n return;\n }\n\n try {\n this.#inProgressHotlistUpdate = this.#updateHotlist();\n await this.#inProgressHotlistUpdate;\n } finally {\n this.#inProgressHotlistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateStalelist() {\n if (this.#inProgressStalelistUpdate) {\n await this.#inProgressStalelistUpdate;\n return;\n }\n\n try {\n this.#inProgressStalelistUpdate = this.#updateStalelist();\n await this.#inProgressStalelistUpdate;\n } finally {\n this.#inProgressStalelistUpdate = undefined;\n }\n }\n\n /**\n * Scan a URL for phishing. It will only scan the hostname of the URL. It also only supports\n * web URLs.\n *\n * @param url - The URL to scan.\n * @returns The phishing detection scan result.\n */\n scanUrl = async (url: string): Promise<PhishingDetectionScanResult> => {\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'url is not a valid web URL',\n };\n }\n\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n return cachedResult;\n }\n\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_SCAN_ENDPOINT}?url=${encodeURIComponent(hostname)}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n };\n }\n const data = await res.json();\n return data;\n },\n true,\n 8000,\n );\n\n // Need to do it this way because safelyExecuteWithTimeout returns undefined for both timeouts and errors.\n if (!apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'timeout of 8000ms exceeded',\n };\n } else if ('error' in apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: apiResponse.error,\n };\n }\n\n const result = {\n hostname,\n recommendedAction: apiResponse.recommendedAction,\n };\n\n this.#urlScanCache.set(hostname, result);\n\n return result;\n };\n\n /**\n * Scan multiple URLs for phishing in bulk. It will only scan the hostnames of the URLs.\n * It also only supports web URLs.\n *\n * @param urls - The URLs to scan.\n * @returns A mapping of URLs to their phishing detection scan results and errors.\n */\n bulkScanUrls = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n if (!urls || urls.length === 0) {\n return {\n results: {},\n errors: {},\n };\n }\n\n // we are arbitrarily limiting the number of URLs to 250\n const MAX_TOTAL_URLS = 250;\n if (urls.length > MAX_TOTAL_URLS) {\n return {\n results: {},\n errors: {\n too_many_urls: [\n `Maximum of ${MAX_TOTAL_URLS} URLs allowed per request`,\n ],\n },\n };\n }\n\n const MAX_URL_LENGTH = 2048;\n const combinedResponse: BulkPhishingDetectionScanResponse = {\n results: {},\n errors: {},\n };\n\n // Extract hostnames from URLs and check for validity and length constraints\n const urlsToHostnames: Record<string, string> = {};\n const urlsToFetch: string[] = [];\n\n for (const url of urls) {\n if (url.length > MAX_URL_LENGTH) {\n combinedResponse.errors[url] = [\n `URL length must not exceed ${MAX_URL_LENGTH} characters`,\n ];\n continue;\n }\n\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n combinedResponse.errors[url] = ['url is not a valid web URL'];\n continue;\n }\n\n // Check if result is already in cache\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n // Use cached result\n combinedResponse.results[url] = cachedResult;\n } else {\n // Add to list of URLs to fetch\n urlsToHostnames[url] = hostname;\n urlsToFetch.push(url);\n }\n }\n\n // If there are URLs to fetch, process them in batches\n if (urlsToFetch.length > 0) {\n // The API has a limit of 50 URLs per request, so we batch the requests\n const MAX_URLS_PER_BATCH = 50;\n const batches: string[][] = [];\n for (let i = 0; i < urlsToFetch.length; i += MAX_URLS_PER_BATCH) {\n batches.push(urlsToFetch.slice(i, i + MAX_URLS_PER_BATCH));\n }\n\n // Process each batch in parallel\n const batchResults = await Promise.all(\n batches.map((batchUrls) => this.#processBatch(batchUrls)),\n );\n\n // Merge results and errors from all batches\n batchResults.forEach((batchResponse) => {\n // Add results to cache and combine with response\n Object.entries(batchResponse.results).forEach(([url, result]) => {\n const hostname = urlsToHostnames[url];\n if (hostname) {\n this.#urlScanCache.set(hostname, result);\n }\n combinedResponse.results[url] = result;\n });\n\n // Combine errors\n Object.entries(batchResponse.errors).forEach(([key, messages]) => {\n combinedResponse.errors[key] = [\n ...(combinedResponse.errors[key] || []),\n ...messages,\n ];\n });\n });\n }\n\n return combinedResponse;\n };\n\n /**\n * Fetch bulk token scan results from the security alerts API.\n *\n * @param chain - The chain name.\n * @param tokens - Array of token addresses to scan.\n * @returns The API response or null if there was an error.\n */\n readonly #fetchTokenScanBulkResults = async (\n chain: string,\n tokens: string[],\n ): Promise<TokenScanApiResponse | null> => {\n const timeout = 8000; // 8 seconds\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const response = await fetch(\n `${SECURITY_ALERTS_BASE_URL}${TOKEN_BULK_SCANNING_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n chain,\n tokens,\n }),\n },\n );\n\n if (!response.ok) {\n return {\n error: `${response.status} ${response.statusText}`,\n status: response.status,\n statusText: response.statusText,\n };\n }\n\n const data = await response.json();\n return data;\n },\n true,\n timeout,\n );\n\n if (!apiResponse) {\n console.error(`Error scanning tokens: timeout of ${timeout}ms exceeded`);\n return null;\n }\n\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n console.warn(\n `Token bulk screening API error: ${apiResponse.status} ${apiResponse.statusText}`,\n );\n return null;\n }\n\n return apiResponse as TokenScanApiResponse;\n };\n\n /**\n * Scan multiple tokens for malicious activity in bulk.\n *\n * @param request - The bulk scan request containing chainId and tokens.\n * @param request.chainId - The chain ID in hex format (e.g., '0x1' for Ethereum).\n * @param request.tokens - Array of token addresses to scan.\n * @returns A mapping of lowercase token addresses to their scan results. Tokens that fail to scan are omitted.\n */\n bulkScanTokens = async (\n request: BulkTokenScanRequest,\n ): Promise<BulkTokenScanResponse> => {\n const { chainId, tokens } = request;\n\n if (!tokens || tokens.length === 0) {\n return {};\n }\n\n const MAX_TOKENS_PER_REQUEST = 100;\n if (tokens.length > MAX_TOKENS_PER_REQUEST) {\n console.warn(\n `Maximum of ${MAX_TOKENS_PER_REQUEST} tokens allowed per request`,\n );\n return {};\n }\n\n const normalizedChainId = chainId.toLowerCase();\n const chain = resolveChainName(normalizedChainId);\n\n if (!chain) {\n console.warn(`Unknown chain ID: ${chainId}`);\n return {};\n }\n\n // Split tokens into cached results and tokens that need to be fetched\n const { cachedResults, tokensToFetch } = splitCacheHits(\n this.#tokenScanCache,\n normalizedChainId,\n tokens,\n );\n\n const results: BulkTokenScanResponse = { ...cachedResults };\n\n // If there are tokens to fetch, call the bulk token scan API\n if (tokensToFetch.length > 0) {\n const apiResponse = await this.#fetchTokenScanBulkResults(\n chain,\n tokensToFetch,\n );\n\n if (apiResponse?.results) {\n // Process API results and update cache\n for (const tokenAddress of tokensToFetch) {\n const normalizedAddress = tokenAddress.toLowerCase();\n const tokenResult = apiResponse.results[normalizedAddress];\n\n if (tokenResult?.result_type) {\n const result = {\n result_type: tokenResult.result_type,\n chain: tokenResult.chain || normalizedChainId,\n address: tokenResult.address || normalizedAddress,\n };\n\n // Update cache\n const cacheKey = buildCacheKey(\n normalizedChainId,\n normalizedAddress,\n );\n this.#tokenScanCache.set(cacheKey, {\n result_type: tokenResult.result_type,\n });\n\n results[normalizedAddress] = result;\n }\n }\n }\n }\n\n return results;\n };\n\n /**\n * Process a batch of URLs (up to 50) for phishing detection.\n *\n * @param urls - A batch of URLs to scan.\n * @returns The scan results and errors for this batch.\n */\n readonly #processBatch = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_BULK_SCAN_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ urls }),\n },\n );\n\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n status: res.status,\n statusText: res.statusText,\n };\n }\n\n const data = await res.json();\n return data;\n },\n true,\n 15000,\n );\n\n // Handle timeout or network errors\n if (!apiResponse) {\n return {\n results: {},\n errors: {\n network_error: ['timeout of 15000ms exceeded'],\n },\n };\n }\n\n // Handle HTTP error responses\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n return {\n results: {},\n errors: {\n api_error: [`${apiResponse.status} ${apiResponse.statusText}`],\n },\n };\n }\n\n return apiResponse as BulkPhishingDetectionScanResponse;\n };\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateStalelist() {\n let stalelistResponse: DataResultWrapper<PhishingStalelist> | null = null;\n let hotlistDiffsResponse: DataResultWrapper<Hotlist> | null = null;\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n try {\n const stalelistPromise = this.#queryConfig<\n DataResultWrapper<PhishingStalelist>\n >(METAMASK_STALELIST_URL);\n\n const c2DomainBlocklistPromise =\n this.#queryConfig<C2DomainBlocklistResponse>(C2_DOMAIN_BLOCKLIST_URL);\n\n [stalelistResponse, c2DomainBlocklistResponse] = await Promise.all([\n stalelistPromise,\n c2DomainBlocklistPromise,\n ]);\n // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,\n // so it doesn't make sense to call if there is not a timestamp to begin with.\n if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {\n hotlistDiffsResponse = await this.#queryConfig<\n DataResultWrapper<Hotlist>\n >(\n `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}?blocklistPaths=true`,\n );\n }\n } finally {\n // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server\n // from being overwhelmed with traffic after a network disruption.\n const timeNow = fetchTimeNow();\n this.update((draftState) => {\n draftState.stalelistLastFetched = timeNow;\n draftState.hotlistLastFetched = timeNow;\n draftState.c2DomainBlocklistLastFetched = timeNow;\n });\n }\n\n if (!stalelistResponse || !hotlistDiffsResponse) {\n return;\n }\n\n const metamaskListState: PhishingListState = {\n allowlist: stalelistResponse.data.allowlist,\n fuzzylist: stalelistResponse.data.fuzzylist,\n tolerance: stalelistResponse.data.tolerance,\n version: stalelistResponse.data.version,\n lastUpdated: stalelistResponse.data.lastUpdated,\n blocklist: stalelistResponse.data.blocklist,\n blocklistPaths: convertListToTrie(stalelistResponse.data.blocklistPaths),\n c2DomainBlocklist: c2DomainBlocklistResponse\n ? c2DomainBlocklistResponse.recentlyAdded\n : [],\n name: phishingListKeyNameMap.eth_phishing_detect_config,\n };\n\n const newMetaMaskListState: PhishingListState = applyDiffs(\n metamaskListState,\n hotlistDiffsResponse.data,\n ListKeys.EthPhishingDetectConfig,\n );\n\n this.update((draftState) => {\n draftState.phishingLists = [newMetaMaskListState];\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateHotlist() {\n let hotlistResponse: DataResultWrapper<Hotlist> | null;\n\n try {\n if (this.state.phishingLists.length === 0) {\n return;\n }\n\n const lastDiffTimestamp = Math.max(\n ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated),\n );\n\n hotlistResponse = await this.#queryConfig<DataResultWrapper<Hotlist>>(\n `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}?blocklistPaths=true`,\n );\n } finally {\n // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.hotlistLastFetched = fetchTimeNow();\n });\n }\n\n if (!hotlistResponse?.data) {\n return;\n }\n const hotlist = hotlistResponse.data;\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n hotlist,\n phishingListNameKeyMap[phishingList.name],\n [],\n [],\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * This should only be called from the `updateC2DomainBlocklist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateC2DomainBlocklist() {\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n\n try {\n c2DomainBlocklistResponse =\n await this.#queryConfig<C2DomainBlocklistResponse>(\n `${C2_DOMAIN_BLOCKLIST_URL}?timestamp=${roundToNearestMinute(\n this.state.c2DomainBlocklistLastFetched,\n )}`,\n );\n } finally {\n // Set `c2DomainBlocklistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.c2DomainBlocklistLastFetched = fetchTimeNow();\n });\n }\n\n if (!c2DomainBlocklistResponse) {\n return;\n }\n\n const recentlyAddedC2Domains = c2DomainBlocklistResponse.recentlyAdded;\n const recentlyRemovedC2Domains = c2DomainBlocklistResponse.recentlyRemoved;\n\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n [],\n phishingListNameKeyMap[phishingList.name],\n recentlyAddedC2Domains,\n recentlyRemovedC2Domains,\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n async #queryConfig<ResponseType>(\n input: RequestInfo,\n ): Promise<ResponseType | null> {\n const response = await safelyExecute(\n () => fetch(input, { cache: 'no-cache' }),\n true,\n );\n\n switch (response?.status) {\n case 200: {\n return await response.json();\n }\n\n default: {\n return null;\n }\n }\n }\n}\n\nexport default PhishingController;\n\nexport type { PhishingDetectorResult };\n"]}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"PhishingController.d.cts","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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
|
1
|
+
{"version":3,"file":"PhishingController.d.cts","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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"}
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"PhishingController.d.mts","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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
|
1
|
+
{"version":3,"file":"PhishingController.d.mts","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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"}
|
@@ -806,7 +806,7 @@ async function _PhishingController_updateStalelist() {
|
|
806
806
|
// Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,
|
807
807
|
// so it doesn't make sense to call if there is not a timestamp to begin with.
|
808
808
|
if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {
|
809
|
-
hotlistDiffsResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);
|
809
|
+
hotlistDiffsResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}?blocklistPaths=true`);
|
810
810
|
}
|
811
811
|
}
|
812
812
|
finally {
|
@@ -854,7 +854,7 @@ async function _PhishingController_updateHotlist() {
|
|
854
854
|
return;
|
855
855
|
}
|
856
856
|
const lastDiffTimestamp = Math.max(...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated));
|
857
|
-
hotlistResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`);
|
857
|
+
hotlistResponse = await __classPrivateFieldGet(this, _PhishingController_instances, "m", _PhishingController_queryConfig).call(this, `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}?blocklistPaths=true`);
|
858
858
|
}
|
859
859
|
finally {
|
860
860
|
// Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with
|
@@ -1 +1 @@
|
|
1
|
-
{"version":3,"file":"PhishingController.mjs","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type {\n TransactionControllerStateChangeEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Patch } from 'immer';\nimport { toASCII } from 'punycode/punycode.js';\n\nimport { CacheManager, type CacheEntry } from './CacheManager';\nimport {\n type PathTrie,\n convertListToTrie,\n insertToTrie,\n matchedPathPrefix,\n} from './PathTrie';\nimport { PhishingDetector } from './PhishingDetector';\nimport {\n PhishingDetectorResultType,\n type PhishingDetectorResult,\n type PhishingDetectionScanResult,\n RecommendedAction,\n type TokenScanCacheData,\n type BulkTokenScanResponse,\n type BulkTokenScanRequest,\n type TokenScanApiResponse,\n} from './types';\nimport {\n applyDiffs,\n fetchTimeNow,\n getHostnameFromUrl,\n roundToNearestMinute,\n getHostnameFromWebUrl,\n buildCacheKey,\n splitCacheHits,\n resolveChainName,\n getPathnameFromUrl,\n} from './utils';\n\nexport const PHISHING_CONFIG_BASE_URL =\n 'https://phishing-detection.api.cx.metamask.io';\nexport const METAMASK_STALELIST_FILE = '/v1/stalelist';\nexport const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince';\n\nexport const CLIENT_SIDE_DETECION_BASE_URL =\n 'https://client-side-detection.api.cx.metamask.io';\nexport const C2_DOMAIN_BLOCKLIST_ENDPOINT = '/v1/request-blocklist';\n\nexport const PHISHING_DETECTION_BASE_URL =\n 'https://dapp-scanning.api.cx.metamask.io';\nexport const PHISHING_DETECTION_SCAN_ENDPOINT = 'v2/scan';\nexport const PHISHING_DETECTION_BULK_SCAN_ENDPOINT = 'bulk-scan';\n\nexport const SECURITY_ALERTS_BASE_URL =\n 'https://security-alerts.api.cx.metamask.io';\nexport const TOKEN_BULK_SCANNING_ENDPOINT = '/token/scan-bulk';\n\n// Cache configuration defaults\nexport const DEFAULT_URL_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_URL_SCAN_CACHE_MAX_SIZE = 250;\nexport const DEFAULT_TOKEN_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE = 1000;\n\nexport const C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const HOTLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const STALELIST_REFRESH_INTERVAL = 30 * 24 * 60 * 60; // 30 days in seconds\n\nexport const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`;\nexport const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`;\nexport const C2_DOMAIN_BLOCKLIST_URL = `${CLIENT_SIDE_DETECION_BASE_URL}${C2_DOMAIN_BLOCKLIST_ENDPOINT}`;\n\n/**\n * @type ListTypes\n *\n * Type outlining the types of lists provided by aggregating different source lists\n */\nexport type ListTypes =\n | 'fuzzylist'\n | 'blocklist'\n | 'blocklistPaths'\n | 'allowlist'\n | 'c2DomainBlocklist';\n\n/**\n * @type EthPhishingResponse\n *\n * Configuration response from the eth-phishing-detect package\n * consisting of approved and unapproved website origins\n * @property blacklist - List of unapproved origins\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property version - Version number of this configuration\n * @property whitelist - List of approved origins\n */\nexport type EthPhishingResponse = {\n blacklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n whitelist: string[];\n};\n\n/**\n * @type C2DomainBlocklistResponse\n *\n * Response for blocklist update requests\n * @property recentlyAdded - List of c2 domains recently added to the blocklist\n * @property recentlyRemoved - List of c2 domains recently removed from the blocklist\n * @property lastFetchedAt - Timestamp of the last fetch request\n */\nexport type C2DomainBlocklistResponse = {\n recentlyAdded: string[];\n recentlyRemoved: string[];\n lastFetchedAt: string;\n};\n\n/**\n * PhishingStalelist defines the expected type of the stalelist from the API.\n *\n * allowlist - List of approved origins.\n * blocklist - List of unapproved origins (hostname-only entries).\n * blocklistPaths - Trie of unapproved origins with paths (hostname + path entries).\n * fuzzylist - List of fuzzy-matched unapproved origins.\n * tolerance - Fuzzy match tolerance level\n * lastUpdated - Timestamp of last update.\n * version - Stalelist data structure iteration.\n */\nexport type PhishingStalelist = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n};\n\n/**\n * @type PhishingListState\n *\n * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`.\n * @property allowlist - List of approved origins (legacy naming \"whitelist\")\n * @property blocklist - List of unapproved origins (legacy naming \"blacklist\")\n * @property blocklistPaths - Trie of unapproved origins with paths (hostname + path, no query params).\n * @property c2DomainBlocklist - List of hashed hostnames that C2 requests are blocked against.\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Version of the phishing list state.\n * @property name - Name of the list. Used for attribution.\n */\nexport type PhishingListState = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: PathTrie;\n c2DomainBlocklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n name: ListNames;\n};\n\n/**\n * @type HotlistDiff\n *\n * type defining the expected type of the diffs in hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type HotlistDiff = {\n url: string;\n timestamp: number;\n targetList: `${ListKeys}.${ListTypes}`;\n isRemoval?: boolean;\n};\n\nexport type DataResultWrapper<T> = {\n data: T;\n};\n\n/**\n * @type Hotlist\n *\n * Type defining expected hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type Hotlist = HotlistDiff[];\n\n/**\n * Enum containing upstream data provider source list keys.\n * These are the keys denoting lists consumed by the upstream data provider.\n */\nexport enum ListKeys {\n EthPhishingDetectConfig = 'eth_phishing_detect_config',\n}\n\n/**\n * Enum containing downstream client attribution names.\n */\nexport enum ListNames {\n MetaMask = 'MetaMask',\n}\n\n/**\n * Maps from downstream client attribution name\n * to list key sourced from upstream data provider.\n */\nconst phishingListNameKeyMap = {\n [ListNames.MetaMask]: ListKeys.EthPhishingDetectConfig,\n};\n\n/**\n * Maps from list key sourced from upstream data\n * provider to downstream client attribution name.\n */\nexport const phishingListKeyNameMap = {\n [ListKeys.EthPhishingDetectConfig]: ListNames.MetaMask,\n};\n\nconst controllerName = 'PhishingController';\n\nconst metadata: StateMetadata<PhishingControllerState> = {\n phishingLists: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelist: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelistPaths: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n hotlistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n stalelistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n c2DomainBlocklistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n urlScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n tokenScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n};\n\n/**\n * Get a default empty state for the controller.\n *\n * @returns The default empty state.\n */\nconst getDefaultState = (): PhishingControllerState => {\n return {\n phishingLists: [],\n whitelist: [],\n whitelistPaths: {},\n hotlistLastFetched: 0,\n stalelistLastFetched: 0,\n c2DomainBlocklistLastFetched: 0,\n urlScanCache: {},\n tokenScanCache: {},\n };\n};\n\n/**\n * @type PhishingControllerState\n *\n * Phishing controller state\n * phishingLists - array of phishing lists\n * whitelist - origins that bypass the phishing detector\n * whitelistPaths - origins with paths that bypass the phishing detector\n * hotlistLastFetched - timestamp of the last hotlist fetch\n * stalelistLastFetched - timestamp of the last stalelist fetch\n * c2DomainBlocklistLastFetched - timestamp of the last c2 domain blocklist fetch\n * urlScanCache - cache of scan results\n */\nexport type PhishingControllerState = {\n phishingLists: PhishingListState[];\n whitelist: string[];\n whitelistPaths: PathTrie;\n hotlistLastFetched: number;\n stalelistLastFetched: number;\n c2DomainBlocklistLastFetched: number;\n urlScanCache: Record<string, CacheEntry<PhishingDetectionScanResult>>;\n tokenScanCache: Record<string, CacheEntry<TokenScanCacheData>>;\n};\n\n/**\n * PhishingControllerOptions\n *\n * Phishing controller options\n * stalelistRefreshInterval - Polling interval used to fetch stale list.\n * hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * urlScanCacheTTL - Time to live in seconds for cached scan results.\n * urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n */\nexport type PhishingControllerOptions = {\n stalelistRefreshInterval?: number;\n hotlistRefreshInterval?: number;\n c2DomainBlocklistRefreshInterval?: number;\n urlScanCacheTTL?: number;\n urlScanCacheMaxSize?: number;\n tokenScanCacheTTL?: number;\n tokenScanCacheMaxSize?: number;\n messenger: PhishingControllerMessenger;\n state?: Partial<PhishingControllerState>;\n};\n\nexport type MaybeUpdateState = {\n type: `${typeof controllerName}:maybeUpdateState`;\n handler: PhishingController['maybeUpdateState'];\n};\n\nexport type TestOrigin = {\n type: `${typeof controllerName}:testOrigin`;\n handler: PhishingController['test'];\n};\n\nexport type PhishingControllerBulkScanUrlsAction = {\n type: `${typeof controllerName}:bulkScanUrls`;\n handler: PhishingController['bulkScanUrls'];\n};\n\nexport type PhishingControllerBulkScanTokensAction = {\n type: `${typeof controllerName}:bulkScanTokens`;\n handler: PhishingController['bulkScanTokens'];\n};\n\nexport type PhishingControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerActions =\n | PhishingControllerGetStateAction\n | MaybeUpdateState\n | TestOrigin\n | PhishingControllerBulkScanUrlsAction\n | PhishingControllerBulkScanTokensAction;\n\nexport type PhishingControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerEvents = PhishingControllerStateChangeEvent;\n\n/**\n * The external actions available to the PhishingController.\n */\ntype AllowedActions = never;\n\n/**\n * The external events available to the PhishingController.\n */\nexport type AllowedEvents = TransactionControllerStateChangeEvent;\n\nexport type PhishingControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n PhishingControllerActions | AllowedActions,\n PhishingControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * BulkPhishingDetectionScanResponse\n *\n * Response for bulk phishing detection scan requests\n * results - Record of domain names and their corresponding phishing detection scan results\n *\n * errors - Record of domain names and their corresponding errors\n */\nexport type BulkPhishingDetectionScanResponse = {\n results: Record<string, PhishingDetectionScanResult>;\n errors: Record<string, string[]>;\n};\n\n/**\n * Controller that manages community-maintained lists of approved and unapproved website origins.\n */\nexport class PhishingController extends BaseController<\n typeof controllerName,\n PhishingControllerState,\n PhishingControllerMessenger\n> {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #detector: any;\n\n #stalelistRefreshInterval: number;\n\n #hotlistRefreshInterval: number;\n\n #c2DomainBlocklistRefreshInterval: number;\n\n readonly #urlScanCache: CacheManager<PhishingDetectionScanResult>;\n\n readonly #tokenScanCache: CacheManager<TokenScanCacheData>;\n\n #inProgressHotlistUpdate?: Promise<void>;\n\n #inProgressStalelistUpdate?: Promise<void>;\n\n #isProgressC2DomainBlocklistUpdate?: Promise<void>;\n\n readonly #transactionControllerStateChangeHandler: (\n state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) => void;\n\n /**\n * Construct a Phishing Controller.\n *\n * @param config - Initial options used to configure this controller.\n * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * @param config.c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * @param config.urlScanCacheTTL - Time to live in seconds for cached scan results.\n * @param config.urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * @param config.tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * @param config.tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n * @param config.messenger - The controller restricted messenger.\n * @param config.state - Initial state to set on this controller.\n */\n constructor({\n stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL,\n hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL,\n c2DomainBlocklistRefreshInterval = C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL,\n urlScanCacheTTL = DEFAULT_URL_SCAN_CACHE_TTL,\n urlScanCacheMaxSize = DEFAULT_URL_SCAN_CACHE_MAX_SIZE,\n tokenScanCacheTTL = DEFAULT_TOKEN_SCAN_CACHE_TTL,\n tokenScanCacheMaxSize = DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE,\n messenger,\n state = {},\n }: PhishingControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultState(),\n ...state,\n },\n });\n\n this.#stalelistRefreshInterval = stalelistRefreshInterval;\n this.#hotlistRefreshInterval = hotlistRefreshInterval;\n this.#c2DomainBlocklistRefreshInterval = c2DomainBlocklistRefreshInterval;\n this.#transactionControllerStateChangeHandler =\n this.#onTransactionControllerStateChange.bind(this);\n this.#urlScanCache = new CacheManager<PhishingDetectionScanResult>({\n cacheTTL: urlScanCacheTTL,\n maxCacheSize: urlScanCacheMaxSize,\n initialCache: this.state.urlScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.urlScanCache = cache;\n });\n },\n });\n this.#tokenScanCache = new CacheManager<TokenScanCacheData>({\n cacheTTL: tokenScanCacheTTL,\n maxCacheSize: tokenScanCacheMaxSize,\n initialCache: this.state.tokenScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.tokenScanCache = cache;\n });\n },\n });\n\n this.#registerMessageHandlers();\n\n this.updatePhishingDetector();\n this.#subscribeToTransactionControllerStateChange();\n }\n\n #subscribeToTransactionControllerStateChange() {\n this.messagingSystem.subscribe(\n 'TransactionController:stateChange',\n this.#transactionControllerStateChangeHandler,\n );\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:maybeUpdateState` as const,\n this.maybeUpdateState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:testOrigin` as const,\n this.test.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanUrls` as const,\n this.bulkScanUrls.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanTokens` as const,\n this.bulkScanTokens.bind(this),\n );\n }\n\n /**\n * Checks if a patch represents a transaction-level change or nested transaction property change\n *\n * @param patch - Immer patch to check\n * @returns True if patch affects a transaction or its nested properties\n */\n #isTransactionPatch(patch: Patch): boolean {\n const { path } = patch;\n return (\n path.length === 2 &&\n path[0] === 'transactions' &&\n typeof path[1] === 'number'\n );\n }\n\n /**\n * Handle transaction controller state changes using Immer patches\n * Extracts token addresses from simulation data and groups them by chain for bulk scanning\n *\n * @param _state - The current transaction controller state\n * @param _state.transactions - Array of transaction metadata\n * @param patches - Array of Immer patches only for transaction-level changes\n */\n #onTransactionControllerStateChange(\n _state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) {\n try {\n const tokensByChain = new Map<string, Set<string>>();\n\n for (const patch of patches) {\n if (patch.op === 'remove') {\n continue;\n }\n\n // Handle transaction-level patches (includes simulation data updates)\n if (this.#isTransactionPatch(patch)) {\n const transaction = patch.value as TransactionMeta;\n this.#getTokensFromTransaction(transaction, tokensByChain);\n }\n }\n\n this.#scanTokensByChain(tokensByChain);\n } catch (error) {\n console.error('Error processing transaction state change:', error);\n }\n }\n\n /**\n * Collect token addresses from a transaction and group them by chain\n *\n * @param transaction - Transaction metadata to extract tokens from\n * @param tokensByChain - Map to collect tokens grouped by chainId\n */\n #getTokensFromTransaction(\n transaction: TransactionMeta,\n tokensByChain: Map<string, Set<string>>,\n ) {\n // extract token addresses from simulation data\n const tokenAddresses = transaction.simulationData?.tokenBalanceChanges?.map(\n (tokenChange) => tokenChange.address.toLowerCase(),\n );\n\n // add token addresses to the map by chainId\n if (tokenAddresses && tokenAddresses.length > 0 && transaction.chainId) {\n const chainId = transaction.chainId.toLowerCase();\n\n if (!tokensByChain.has(chainId)) {\n tokensByChain.set(chainId, new Set());\n }\n\n const chainTokens = tokensByChain.get(chainId);\n if (chainTokens) {\n for (const address of tokenAddresses) {\n chainTokens.add(address);\n }\n }\n }\n }\n\n /**\n * Scan tokens grouped by chain ID\n *\n * @param tokensByChain - Map of chainId to token addresses\n */\n #scanTokensByChain(tokensByChain: Map<string, Set<string>>) {\n for (const [chainId, tokenSet] of tokensByChain) {\n if (tokenSet.size > 0) {\n const tokens = Array.from(tokenSet);\n this.bulkScanTokens({\n chainId,\n tokens,\n }).catch((error) =>\n console.error(`Error scanning tokens for chain ${chainId}:`, error),\n );\n }\n }\n }\n\n /**\n * Updates this.detector with an instance of PhishingDetector using the current state.\n */\n updatePhishingDetector() {\n this.#detector = new PhishingDetector(this.state.phishingLists);\n }\n\n /**\n * Set the interval at which the stale phishing list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateStalelist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setStalelistRefreshInterval(interval: number) {\n this.#stalelistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the hot list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setHotlistRefreshInterval(interval: number) {\n this.#hotlistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the C2 domain blocklist will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setC2DomainBlocklistRefreshInterval(interval: number) {\n this.#c2DomainBlocklistRefreshInterval = interval;\n }\n\n /**\n * Set the time-to-live for URL scan cache entries.\n *\n * @param ttl - The TTL in seconds.\n */\n setUrlScanCacheTTL(ttl: number) {\n this.#urlScanCache.setTTL(ttl);\n }\n\n /**\n * Set the maximum number of entries in the URL scan cache.\n *\n * @param maxSize - The maximum cache size.\n */\n setUrlScanCacheMaxSize(maxSize: number) {\n this.#urlScanCache.setMaxSize(maxSize);\n }\n\n /**\n * Clear the URL scan cache.\n */\n clearUrlScanCache() {\n this.#urlScanCache.clear();\n }\n\n /**\n * Determine if an update to the stalelist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isStalelistOutOfDate() {\n return (\n fetchTimeNow() - this.state.stalelistLastFetched >=\n this.#stalelistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the hotlist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isHotlistOutOfDate() {\n return (\n fetchTimeNow() - this.state.hotlistLastFetched >=\n this.#hotlistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the C2 domain blocklist is needed.\n *\n * @returns Whether an update is needed\n */\n isC2DomainBlocklistOutOfDate() {\n return (\n fetchTimeNow() - this.state.c2DomainBlocklistLastFetched >=\n this.#c2DomainBlocklistRefreshInterval\n );\n }\n\n /**\n * Conditionally update the phishing configuration.\n *\n * If the stalelist configuration is out of date, this function will call `updateStalelist`\n * to update the configuration. This will automatically grab the hotlist,\n * so it isn't necessary to continue on to download the hotlist and the c2 domain blocklist.\n *\n */\n async maybeUpdateState() {\n const staleListOutOfDate = this.isStalelistOutOfDate();\n if (staleListOutOfDate) {\n await this.updateStalelist();\n return;\n }\n const hotlistOutOfDate = this.isHotlistOutOfDate();\n if (hotlistOutOfDate) {\n await this.updateHotlist();\n }\n const c2DomainBlocklistOutOfDate = this.isC2DomainBlocklistOutOfDate();\n if (c2DomainBlocklistOutOfDate) {\n await this.updateC2DomainBlocklist();\n }\n }\n\n /**\n * Determines if a given origin is unapproved.\n *\n * It is strongly recommended that you call {@link maybeUpdateState} before calling this,\n * to check whether the phishing configuration is up-to-date. It will be updated if necessary\n * by calling {@link updateStalelist} or {@link updateHotlist}.\n *\n * @param origin - Domain origin of a website.\n * @returns Whether the origin is an unapproved origin.\n */\n test(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n\n if (matchedPathPrefix(hostnameWithPaths, this.state.whitelistPaths)) {\n return { result: false, type: PhishingDetectorResultType.All };\n }\n\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.check(punycodeOrigin);\n }\n\n /**\n * Checks if a request URL's domain is blocked against the request blocklist.\n *\n * This method is used to determine if a specific request URL is associated with a malicious\n * command and control (C2) domain. The URL's hostname is hashed and checked against a configured\n * blocklist of known malicious domains.\n *\n * @param origin - The full request URL to be checked.\n * @returns An object indicating whether the URL's domain is blocked and relevant metadata.\n */\n isBlockedRequest(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.isMaliciousC2Domain(punycodeOrigin);\n }\n\n /**\n * Temporarily marks a given origin as approved.\n *\n * @param origin - The origin to mark as approved.\n */\n bypass(origin: string) {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n const { whitelist, whitelistPaths } = this.state;\n const whitelistPath = matchedPathPrefix(hostnameWithPaths, whitelistPaths);\n\n if (whitelist.includes(hostname || punycodeOrigin) || whitelistPath) {\n return;\n }\n\n // If the origin was blocked by a path, then we only want to add it to the whitelistPaths since\n // other paths with the same hostname may not be blocked.\n const blockingPath = this.#detector.blockingPath(origin);\n if (blockingPath) {\n this.update((draftState) => {\n insertToTrie(blockingPath, draftState.whitelistPaths);\n });\n return;\n }\n\n this.update((draftState) => {\n draftState.whitelist.push(hostname || punycodeOrigin);\n });\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateC2DomainBlocklist() {\n if (this.#isProgressC2DomainBlocklistUpdate) {\n await this.#isProgressC2DomainBlocklistUpdate;\n return;\n }\n\n try {\n this.#isProgressC2DomainBlocklistUpdate = this.#updateC2DomainBlocklist();\n await this.#isProgressC2DomainBlocklistUpdate;\n } finally {\n this.#isProgressC2DomainBlocklistUpdate = undefined;\n }\n }\n\n /**\n * Update the hotlist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateHotlist() {\n if (this.#inProgressHotlistUpdate) {\n await this.#inProgressHotlistUpdate;\n return;\n }\n\n try {\n this.#inProgressHotlistUpdate = this.#updateHotlist();\n await this.#inProgressHotlistUpdate;\n } finally {\n this.#inProgressHotlistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateStalelist() {\n if (this.#inProgressStalelistUpdate) {\n await this.#inProgressStalelistUpdate;\n return;\n }\n\n try {\n this.#inProgressStalelistUpdate = this.#updateStalelist();\n await this.#inProgressStalelistUpdate;\n } finally {\n this.#inProgressStalelistUpdate = undefined;\n }\n }\n\n /**\n * Scan a URL for phishing. It will only scan the hostname of the URL. It also only supports\n * web URLs.\n *\n * @param url - The URL to scan.\n * @returns The phishing detection scan result.\n */\n scanUrl = async (url: string): Promise<PhishingDetectionScanResult> => {\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'url is not a valid web URL',\n };\n }\n\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n return cachedResult;\n }\n\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_SCAN_ENDPOINT}?url=${encodeURIComponent(hostname)}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n };\n }\n const data = await res.json();\n return data;\n },\n true,\n 8000,\n );\n\n // Need to do it this way because safelyExecuteWithTimeout returns undefined for both timeouts and errors.\n if (!apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'timeout of 8000ms exceeded',\n };\n } else if ('error' in apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: apiResponse.error,\n };\n }\n\n const result = {\n hostname,\n recommendedAction: apiResponse.recommendedAction,\n };\n\n this.#urlScanCache.set(hostname, result);\n\n return result;\n };\n\n /**\n * Scan multiple URLs for phishing in bulk. It will only scan the hostnames of the URLs.\n * It also only supports web URLs.\n *\n * @param urls - The URLs to scan.\n * @returns A mapping of URLs to their phishing detection scan results and errors.\n */\n bulkScanUrls = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n if (!urls || urls.length === 0) {\n return {\n results: {},\n errors: {},\n };\n }\n\n // we are arbitrarily limiting the number of URLs to 250\n const MAX_TOTAL_URLS = 250;\n if (urls.length > MAX_TOTAL_URLS) {\n return {\n results: {},\n errors: {\n too_many_urls: [\n `Maximum of ${MAX_TOTAL_URLS} URLs allowed per request`,\n ],\n },\n };\n }\n\n const MAX_URL_LENGTH = 2048;\n const combinedResponse: BulkPhishingDetectionScanResponse = {\n results: {},\n errors: {},\n };\n\n // Extract hostnames from URLs and check for validity and length constraints\n const urlsToHostnames: Record<string, string> = {};\n const urlsToFetch: string[] = [];\n\n for (const url of urls) {\n if (url.length > MAX_URL_LENGTH) {\n combinedResponse.errors[url] = [\n `URL length must not exceed ${MAX_URL_LENGTH} characters`,\n ];\n continue;\n }\n\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n combinedResponse.errors[url] = ['url is not a valid web URL'];\n continue;\n }\n\n // Check if result is already in cache\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n // Use cached result\n combinedResponse.results[url] = cachedResult;\n } else {\n // Add to list of URLs to fetch\n urlsToHostnames[url] = hostname;\n urlsToFetch.push(url);\n }\n }\n\n // If there are URLs to fetch, process them in batches\n if (urlsToFetch.length > 0) {\n // The API has a limit of 50 URLs per request, so we batch the requests\n const MAX_URLS_PER_BATCH = 50;\n const batches: string[][] = [];\n for (let i = 0; i < urlsToFetch.length; i += MAX_URLS_PER_BATCH) {\n batches.push(urlsToFetch.slice(i, i + MAX_URLS_PER_BATCH));\n }\n\n // Process each batch in parallel\n const batchResults = await Promise.all(\n batches.map((batchUrls) => this.#processBatch(batchUrls)),\n );\n\n // Merge results and errors from all batches\n batchResults.forEach((batchResponse) => {\n // Add results to cache and combine with response\n Object.entries(batchResponse.results).forEach(([url, result]) => {\n const hostname = urlsToHostnames[url];\n if (hostname) {\n this.#urlScanCache.set(hostname, result);\n }\n combinedResponse.results[url] = result;\n });\n\n // Combine errors\n Object.entries(batchResponse.errors).forEach(([key, messages]) => {\n combinedResponse.errors[key] = [\n ...(combinedResponse.errors[key] || []),\n ...messages,\n ];\n });\n });\n }\n\n return combinedResponse;\n };\n\n /**\n * Fetch bulk token scan results from the security alerts API.\n *\n * @param chain - The chain name.\n * @param tokens - Array of token addresses to scan.\n * @returns The API response or null if there was an error.\n */\n readonly #fetchTokenScanBulkResults = async (\n chain: string,\n tokens: string[],\n ): Promise<TokenScanApiResponse | null> => {\n const timeout = 8000; // 8 seconds\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const response = await fetch(\n `${SECURITY_ALERTS_BASE_URL}${TOKEN_BULK_SCANNING_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n chain,\n tokens,\n }),\n },\n );\n\n if (!response.ok) {\n return {\n error: `${response.status} ${response.statusText}`,\n status: response.status,\n statusText: response.statusText,\n };\n }\n\n const data = await response.json();\n return data;\n },\n true,\n timeout,\n );\n\n if (!apiResponse) {\n console.error(`Error scanning tokens: timeout of ${timeout}ms exceeded`);\n return null;\n }\n\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n console.warn(\n `Token bulk screening API error: ${apiResponse.status} ${apiResponse.statusText}`,\n );\n return null;\n }\n\n return apiResponse as TokenScanApiResponse;\n };\n\n /**\n * Scan multiple tokens for malicious activity in bulk.\n *\n * @param request - The bulk scan request containing chainId and tokens.\n * @param request.chainId - The chain ID in hex format (e.g., '0x1' for Ethereum).\n * @param request.tokens - Array of token addresses to scan.\n * @returns A mapping of lowercase token addresses to their scan results. Tokens that fail to scan are omitted.\n */\n bulkScanTokens = async (\n request: BulkTokenScanRequest,\n ): Promise<BulkTokenScanResponse> => {\n const { chainId, tokens } = request;\n\n if (!tokens || tokens.length === 0) {\n return {};\n }\n\n const MAX_TOKENS_PER_REQUEST = 100;\n if (tokens.length > MAX_TOKENS_PER_REQUEST) {\n console.warn(\n `Maximum of ${MAX_TOKENS_PER_REQUEST} tokens allowed per request`,\n );\n return {};\n }\n\n const normalizedChainId = chainId.toLowerCase();\n const chain = resolveChainName(normalizedChainId);\n\n if (!chain) {\n console.warn(`Unknown chain ID: ${chainId}`);\n return {};\n }\n\n // Split tokens into cached results and tokens that need to be fetched\n const { cachedResults, tokensToFetch } = splitCacheHits(\n this.#tokenScanCache,\n normalizedChainId,\n tokens,\n );\n\n const results: BulkTokenScanResponse = { ...cachedResults };\n\n // If there are tokens to fetch, call the bulk token scan API\n if (tokensToFetch.length > 0) {\n const apiResponse = await this.#fetchTokenScanBulkResults(\n chain,\n tokensToFetch,\n );\n\n if (apiResponse?.results) {\n // Process API results and update cache\n for (const tokenAddress of tokensToFetch) {\n const normalizedAddress = tokenAddress.toLowerCase();\n const tokenResult = apiResponse.results[normalizedAddress];\n\n if (tokenResult?.result_type) {\n const result = {\n result_type: tokenResult.result_type,\n chain: tokenResult.chain || normalizedChainId,\n address: tokenResult.address || normalizedAddress,\n };\n\n // Update cache\n const cacheKey = buildCacheKey(\n normalizedChainId,\n normalizedAddress,\n );\n this.#tokenScanCache.set(cacheKey, {\n result_type: tokenResult.result_type,\n });\n\n results[normalizedAddress] = result;\n }\n }\n }\n }\n\n return results;\n };\n\n /**\n * Process a batch of URLs (up to 50) for phishing detection.\n *\n * @param urls - A batch of URLs to scan.\n * @returns The scan results and errors for this batch.\n */\n readonly #processBatch = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_BULK_SCAN_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ urls }),\n },\n );\n\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n status: res.status,\n statusText: res.statusText,\n };\n }\n\n const data = await res.json();\n return data;\n },\n true,\n 15000,\n );\n\n // Handle timeout or network errors\n if (!apiResponse) {\n return {\n results: {},\n errors: {\n network_error: ['timeout of 15000ms exceeded'],\n },\n };\n }\n\n // Handle HTTP error responses\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n return {\n results: {},\n errors: {\n api_error: [`${apiResponse.status} ${apiResponse.statusText}`],\n },\n };\n }\n\n return apiResponse as BulkPhishingDetectionScanResponse;\n };\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateStalelist() {\n let stalelistResponse: DataResultWrapper<PhishingStalelist> | null = null;\n let hotlistDiffsResponse: DataResultWrapper<Hotlist> | null = null;\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n try {\n const stalelistPromise = this.#queryConfig<\n DataResultWrapper<PhishingStalelist>\n >(METAMASK_STALELIST_URL);\n\n const c2DomainBlocklistPromise =\n this.#queryConfig<C2DomainBlocklistResponse>(C2_DOMAIN_BLOCKLIST_URL);\n\n [stalelistResponse, c2DomainBlocklistResponse] = await Promise.all([\n stalelistPromise,\n c2DomainBlocklistPromise,\n ]);\n // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,\n // so it doesn't make sense to call if there is not a timestamp to begin with.\n if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {\n hotlistDiffsResponse = await this.#queryConfig<\n DataResultWrapper<Hotlist>\n >(`${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}`);\n }\n } finally {\n // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server\n // from being overwhelmed with traffic after a network disruption.\n const timeNow = fetchTimeNow();\n this.update((draftState) => {\n draftState.stalelistLastFetched = timeNow;\n draftState.hotlistLastFetched = timeNow;\n draftState.c2DomainBlocklistLastFetched = timeNow;\n });\n }\n\n if (!stalelistResponse || !hotlistDiffsResponse) {\n return;\n }\n\n const metamaskListState: PhishingListState = {\n allowlist: stalelistResponse.data.allowlist,\n fuzzylist: stalelistResponse.data.fuzzylist,\n tolerance: stalelistResponse.data.tolerance,\n version: stalelistResponse.data.version,\n lastUpdated: stalelistResponse.data.lastUpdated,\n blocklist: stalelistResponse.data.blocklist,\n blocklistPaths: convertListToTrie(stalelistResponse.data.blocklistPaths),\n c2DomainBlocklist: c2DomainBlocklistResponse\n ? c2DomainBlocklistResponse.recentlyAdded\n : [],\n name: phishingListKeyNameMap.eth_phishing_detect_config,\n };\n\n const newMetaMaskListState: PhishingListState = applyDiffs(\n metamaskListState,\n hotlistDiffsResponse.data,\n ListKeys.EthPhishingDetectConfig,\n );\n\n this.update((draftState) => {\n draftState.phishingLists = [newMetaMaskListState];\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateHotlist() {\n let hotlistResponse: DataResultWrapper<Hotlist> | null;\n\n try {\n if (this.state.phishingLists.length === 0) {\n return;\n }\n\n const lastDiffTimestamp = Math.max(\n ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated),\n );\n\n hotlistResponse = await this.#queryConfig<DataResultWrapper<Hotlist>>(\n `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}`,\n );\n } finally {\n // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.hotlistLastFetched = fetchTimeNow();\n });\n }\n\n if (!hotlistResponse?.data) {\n return;\n }\n const hotlist = hotlistResponse.data;\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n hotlist,\n phishingListNameKeyMap[phishingList.name],\n [],\n [],\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * This should only be called from the `updateC2DomainBlocklist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateC2DomainBlocklist() {\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n\n try {\n c2DomainBlocklistResponse =\n await this.#queryConfig<C2DomainBlocklistResponse>(\n `${C2_DOMAIN_BLOCKLIST_URL}?timestamp=${roundToNearestMinute(\n this.state.c2DomainBlocklistLastFetched,\n )}`,\n );\n } finally {\n // Set `c2DomainBlocklistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.c2DomainBlocklistLastFetched = fetchTimeNow();\n });\n }\n\n if (!c2DomainBlocklistResponse) {\n return;\n }\n\n const recentlyAddedC2Domains = c2DomainBlocklistResponse.recentlyAdded;\n const recentlyRemovedC2Domains = c2DomainBlocklistResponse.recentlyRemoved;\n\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n [],\n phishingListNameKeyMap[phishingList.name],\n recentlyAddedC2Domains,\n recentlyRemovedC2Domains,\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n async #queryConfig<ResponseType>(\n input: RequestInfo,\n ): Promise<ResponseType | null> {\n const response = await safelyExecute(\n () => fetch(input, { cache: 'no-cache' }),\n true,\n );\n\n switch (response?.status) {\n case 200: {\n return await response.json();\n }\n\n default: {\n return null;\n }\n }\n }\n}\n\nexport default PhishingController;\n\nexport type { PhishingDetectorResult };\n"]}
|
1
|
+
{"version":3,"file":"PhishingController.mjs","sourceRoot":"","sources":["../src/PhishingController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedMessenger,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport {\n safelyExecute,\n safelyExecuteWithTimeout,\n} from '@metamask/controller-utils';\nimport type {\n TransactionControllerStateChangeEvent,\n TransactionMeta,\n} from '@metamask/transaction-controller';\nimport type { Patch } from 'immer';\nimport { toASCII } from 'punycode/punycode.js';\n\nimport { CacheManager, type CacheEntry } from './CacheManager';\nimport {\n type PathTrie,\n convertListToTrie,\n insertToTrie,\n matchedPathPrefix,\n} from './PathTrie';\nimport { PhishingDetector } from './PhishingDetector';\nimport {\n PhishingDetectorResultType,\n type PhishingDetectorResult,\n type PhishingDetectionScanResult,\n RecommendedAction,\n type TokenScanCacheData,\n type BulkTokenScanResponse,\n type BulkTokenScanRequest,\n type TokenScanApiResponse,\n} from './types';\nimport {\n applyDiffs,\n fetchTimeNow,\n getHostnameFromUrl,\n roundToNearestMinute,\n getHostnameFromWebUrl,\n buildCacheKey,\n splitCacheHits,\n resolveChainName,\n getPathnameFromUrl,\n} from './utils';\n\nexport const PHISHING_CONFIG_BASE_URL =\n 'https://phishing-detection.api.cx.metamask.io';\nexport const METAMASK_STALELIST_FILE = '/v1/stalelist';\nexport const METAMASK_HOTLIST_DIFF_FILE = '/v1/diffsSince';\n\nexport const CLIENT_SIDE_DETECION_BASE_URL =\n 'https://client-side-detection.api.cx.metamask.io';\nexport const C2_DOMAIN_BLOCKLIST_ENDPOINT = '/v1/request-blocklist';\n\nexport const PHISHING_DETECTION_BASE_URL =\n 'https://dapp-scanning.api.cx.metamask.io';\nexport const PHISHING_DETECTION_SCAN_ENDPOINT = 'v2/scan';\nexport const PHISHING_DETECTION_BULK_SCAN_ENDPOINT = 'bulk-scan';\n\nexport const SECURITY_ALERTS_BASE_URL =\n 'https://security-alerts.api.cx.metamask.io';\nexport const TOKEN_BULK_SCANNING_ENDPOINT = '/token/scan-bulk';\n\n// Cache configuration defaults\nexport const DEFAULT_URL_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_URL_SCAN_CACHE_MAX_SIZE = 250;\nexport const DEFAULT_TOKEN_SCAN_CACHE_TTL = 15 * 60; // 15 minutes in seconds\nexport const DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE = 1000;\n\nexport const C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const HOTLIST_REFRESH_INTERVAL = 5 * 60; // 5 mins in seconds\nexport const STALELIST_REFRESH_INTERVAL = 30 * 24 * 60 * 60; // 30 days in seconds\n\nexport const METAMASK_STALELIST_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_STALELIST_FILE}`;\nexport const METAMASK_HOTLIST_DIFF_URL = `${PHISHING_CONFIG_BASE_URL}${METAMASK_HOTLIST_DIFF_FILE}`;\nexport const C2_DOMAIN_BLOCKLIST_URL = `${CLIENT_SIDE_DETECION_BASE_URL}${C2_DOMAIN_BLOCKLIST_ENDPOINT}`;\n\n/**\n * @type ListTypes\n *\n * Type outlining the types of lists provided by aggregating different source lists\n */\nexport type ListTypes =\n | 'fuzzylist'\n | 'blocklist'\n | 'blocklistPaths'\n | 'allowlist'\n | 'c2DomainBlocklist';\n\n/**\n * @type EthPhishingResponse\n *\n * Configuration response from the eth-phishing-detect package\n * consisting of approved and unapproved website origins\n * @property blacklist - List of unapproved origins\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property version - Version number of this configuration\n * @property whitelist - List of approved origins\n */\nexport type EthPhishingResponse = {\n blacklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n whitelist: string[];\n};\n\n/**\n * @type C2DomainBlocklistResponse\n *\n * Response for blocklist update requests\n * @property recentlyAdded - List of c2 domains recently added to the blocklist\n * @property recentlyRemoved - List of c2 domains recently removed from the blocklist\n * @property lastFetchedAt - Timestamp of the last fetch request\n */\nexport type C2DomainBlocklistResponse = {\n recentlyAdded: string[];\n recentlyRemoved: string[];\n lastFetchedAt: string;\n};\n\n/**\n * PhishingStalelist defines the expected type of the stalelist from the API.\n *\n * allowlist - List of approved origins.\n * blocklist - List of unapproved origins (hostname-only entries).\n * blocklistPaths - Trie of unapproved origins with paths (hostname + path entries).\n * fuzzylist - List of fuzzy-matched unapproved origins.\n * tolerance - Fuzzy match tolerance level\n * lastUpdated - Timestamp of last update.\n * version - Stalelist data structure iteration.\n */\nexport type PhishingStalelist = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n};\n\n/**\n * @type PhishingListState\n *\n * type defining the persisted list state. This is the persisted state that is updated frequently with `this.maybeUpdateState()`.\n * @property allowlist - List of approved origins (legacy naming \"whitelist\")\n * @property blocklist - List of unapproved origins (legacy naming \"blacklist\")\n * @property blocklistPaths - Trie of unapproved origins with paths (hostname + path, no query params).\n * @property c2DomainBlocklist - List of hashed hostnames that C2 requests are blocked against.\n * @property fuzzylist - List of fuzzy-matched unapproved origins\n * @property tolerance - Fuzzy match tolerance level\n * @property lastUpdated - Timestamp of last update.\n * @property version - Version of the phishing list state.\n * @property name - Name of the list. Used for attribution.\n */\nexport type PhishingListState = {\n allowlist: string[];\n blocklist: string[];\n blocklistPaths: PathTrie;\n c2DomainBlocklist: string[];\n fuzzylist: string[];\n tolerance: number;\n version: number;\n lastUpdated: number;\n name: ListNames;\n};\n\n/**\n * @type HotlistDiff\n *\n * type defining the expected type of the diffs in hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type HotlistDiff = {\n url: string;\n timestamp: number;\n targetList: `${ListKeys}.${ListTypes}`;\n isRemoval?: boolean;\n};\n\nexport type DataResultWrapper<T> = {\n data: T;\n};\n\n/**\n * @type Hotlist\n *\n * Type defining expected hotlist.json file.\n * @property url - Url of the diff entry.\n * @property timestamp - Timestamp at which the diff was identified.\n * @property targetList - The list name where the diff was identified.\n * @property isRemoval - Was the diff identified a removal type.\n */\nexport type Hotlist = HotlistDiff[];\n\n/**\n * Enum containing upstream data provider source list keys.\n * These are the keys denoting lists consumed by the upstream data provider.\n */\nexport enum ListKeys {\n EthPhishingDetectConfig = 'eth_phishing_detect_config',\n}\n\n/**\n * Enum containing downstream client attribution names.\n */\nexport enum ListNames {\n MetaMask = 'MetaMask',\n}\n\n/**\n * Maps from downstream client attribution name\n * to list key sourced from upstream data provider.\n */\nconst phishingListNameKeyMap = {\n [ListNames.MetaMask]: ListKeys.EthPhishingDetectConfig,\n};\n\n/**\n * Maps from list key sourced from upstream data\n * provider to downstream client attribution name.\n */\nexport const phishingListKeyNameMap = {\n [ListKeys.EthPhishingDetectConfig]: ListNames.MetaMask,\n};\n\nconst controllerName = 'PhishingController';\n\nconst metadata: StateMetadata<PhishingControllerState> = {\n phishingLists: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelist: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n whitelistPaths: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n hotlistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n stalelistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n c2DomainBlocklistLastFetched: {\n includeInStateLogs: true,\n persist: true,\n anonymous: false,\n usedInUi: false,\n },\n urlScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n tokenScanCache: {\n includeInStateLogs: false,\n persist: true,\n anonymous: false,\n usedInUi: true,\n },\n};\n\n/**\n * Get a default empty state for the controller.\n *\n * @returns The default empty state.\n */\nconst getDefaultState = (): PhishingControllerState => {\n return {\n phishingLists: [],\n whitelist: [],\n whitelistPaths: {},\n hotlistLastFetched: 0,\n stalelistLastFetched: 0,\n c2DomainBlocklistLastFetched: 0,\n urlScanCache: {},\n tokenScanCache: {},\n };\n};\n\n/**\n * @type PhishingControllerState\n *\n * Phishing controller state\n * phishingLists - array of phishing lists\n * whitelist - origins that bypass the phishing detector\n * whitelistPaths - origins with paths that bypass the phishing detector\n * hotlistLastFetched - timestamp of the last hotlist fetch\n * stalelistLastFetched - timestamp of the last stalelist fetch\n * c2DomainBlocklistLastFetched - timestamp of the last c2 domain blocklist fetch\n * urlScanCache - cache of scan results\n */\nexport type PhishingControllerState = {\n phishingLists: PhishingListState[];\n whitelist: string[];\n whitelistPaths: PathTrie;\n hotlistLastFetched: number;\n stalelistLastFetched: number;\n c2DomainBlocklistLastFetched: number;\n urlScanCache: Record<string, CacheEntry<PhishingDetectionScanResult>>;\n tokenScanCache: Record<string, CacheEntry<TokenScanCacheData>>;\n};\n\n/**\n * PhishingControllerOptions\n *\n * Phishing controller options\n * stalelistRefreshInterval - Polling interval used to fetch stale list.\n * hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * urlScanCacheTTL - Time to live in seconds for cached scan results.\n * urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n */\nexport type PhishingControllerOptions = {\n stalelistRefreshInterval?: number;\n hotlistRefreshInterval?: number;\n c2DomainBlocklistRefreshInterval?: number;\n urlScanCacheTTL?: number;\n urlScanCacheMaxSize?: number;\n tokenScanCacheTTL?: number;\n tokenScanCacheMaxSize?: number;\n messenger: PhishingControllerMessenger;\n state?: Partial<PhishingControllerState>;\n};\n\nexport type MaybeUpdateState = {\n type: `${typeof controllerName}:maybeUpdateState`;\n handler: PhishingController['maybeUpdateState'];\n};\n\nexport type TestOrigin = {\n type: `${typeof controllerName}:testOrigin`;\n handler: PhishingController['test'];\n};\n\nexport type PhishingControllerBulkScanUrlsAction = {\n type: `${typeof controllerName}:bulkScanUrls`;\n handler: PhishingController['bulkScanUrls'];\n};\n\nexport type PhishingControllerBulkScanTokensAction = {\n type: `${typeof controllerName}:bulkScanTokens`;\n handler: PhishingController['bulkScanTokens'];\n};\n\nexport type PhishingControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerActions =\n | PhishingControllerGetStateAction\n | MaybeUpdateState\n | TestOrigin\n | PhishingControllerBulkScanUrlsAction\n | PhishingControllerBulkScanTokensAction;\n\nexport type PhishingControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n PhishingControllerState\n>;\n\nexport type PhishingControllerEvents = PhishingControllerStateChangeEvent;\n\n/**\n * The external actions available to the PhishingController.\n */\ntype AllowedActions = never;\n\n/**\n * The external events available to the PhishingController.\n */\nexport type AllowedEvents = TransactionControllerStateChangeEvent;\n\nexport type PhishingControllerMessenger = RestrictedMessenger<\n typeof controllerName,\n PhishingControllerActions | AllowedActions,\n PhishingControllerEvents | AllowedEvents,\n AllowedActions['type'],\n AllowedEvents['type']\n>;\n\n/**\n * BulkPhishingDetectionScanResponse\n *\n * Response for bulk phishing detection scan requests\n * results - Record of domain names and their corresponding phishing detection scan results\n *\n * errors - Record of domain names and their corresponding errors\n */\nexport type BulkPhishingDetectionScanResponse = {\n results: Record<string, PhishingDetectionScanResult>;\n errors: Record<string, string[]>;\n};\n\n/**\n * Controller that manages community-maintained lists of approved and unapproved website origins.\n */\nexport class PhishingController extends BaseController<\n typeof controllerName,\n PhishingControllerState,\n PhishingControllerMessenger\n> {\n // TODO: Replace `any` with type\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n #detector: any;\n\n #stalelistRefreshInterval: number;\n\n #hotlistRefreshInterval: number;\n\n #c2DomainBlocklistRefreshInterval: number;\n\n readonly #urlScanCache: CacheManager<PhishingDetectionScanResult>;\n\n readonly #tokenScanCache: CacheManager<TokenScanCacheData>;\n\n #inProgressHotlistUpdate?: Promise<void>;\n\n #inProgressStalelistUpdate?: Promise<void>;\n\n #isProgressC2DomainBlocklistUpdate?: Promise<void>;\n\n readonly #transactionControllerStateChangeHandler: (\n state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) => void;\n\n /**\n * Construct a Phishing Controller.\n *\n * @param config - Initial options used to configure this controller.\n * @param config.stalelistRefreshInterval - Polling interval used to fetch stale list.\n * @param config.hotlistRefreshInterval - Polling interval used to fetch hotlist diff list.\n * @param config.c2DomainBlocklistRefreshInterval - Polling interval used to fetch c2 domain blocklist.\n * @param config.urlScanCacheTTL - Time to live in seconds for cached scan results.\n * @param config.urlScanCacheMaxSize - Maximum number of entries in the scan cache.\n * @param config.tokenScanCacheTTL - Time to live in seconds for cached token scan results.\n * @param config.tokenScanCacheMaxSize - Maximum number of entries in the token scan cache.\n * @param config.messenger - The controller restricted messenger.\n * @param config.state - Initial state to set on this controller.\n */\n constructor({\n stalelistRefreshInterval = STALELIST_REFRESH_INTERVAL,\n hotlistRefreshInterval = HOTLIST_REFRESH_INTERVAL,\n c2DomainBlocklistRefreshInterval = C2_DOMAIN_BLOCKLIST_REFRESH_INTERVAL,\n urlScanCacheTTL = DEFAULT_URL_SCAN_CACHE_TTL,\n urlScanCacheMaxSize = DEFAULT_URL_SCAN_CACHE_MAX_SIZE,\n tokenScanCacheTTL = DEFAULT_TOKEN_SCAN_CACHE_TTL,\n tokenScanCacheMaxSize = DEFAULT_TOKEN_SCAN_CACHE_MAX_SIZE,\n messenger,\n state = {},\n }: PhishingControllerOptions) {\n super({\n name: controllerName,\n metadata,\n messenger,\n state: {\n ...getDefaultState(),\n ...state,\n },\n });\n\n this.#stalelistRefreshInterval = stalelistRefreshInterval;\n this.#hotlistRefreshInterval = hotlistRefreshInterval;\n this.#c2DomainBlocklistRefreshInterval = c2DomainBlocklistRefreshInterval;\n this.#transactionControllerStateChangeHandler =\n this.#onTransactionControllerStateChange.bind(this);\n this.#urlScanCache = new CacheManager<PhishingDetectionScanResult>({\n cacheTTL: urlScanCacheTTL,\n maxCacheSize: urlScanCacheMaxSize,\n initialCache: this.state.urlScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.urlScanCache = cache;\n });\n },\n });\n this.#tokenScanCache = new CacheManager<TokenScanCacheData>({\n cacheTTL: tokenScanCacheTTL,\n maxCacheSize: tokenScanCacheMaxSize,\n initialCache: this.state.tokenScanCache,\n updateState: (cache) => {\n this.update((draftState) => {\n draftState.tokenScanCache = cache;\n });\n },\n });\n\n this.#registerMessageHandlers();\n\n this.updatePhishingDetector();\n this.#subscribeToTransactionControllerStateChange();\n }\n\n #subscribeToTransactionControllerStateChange() {\n this.messagingSystem.subscribe(\n 'TransactionController:stateChange',\n this.#transactionControllerStateChangeHandler,\n );\n }\n\n /**\n * Constructor helper for registering this controller's messaging system\n * actions.\n */\n #registerMessageHandlers(): void {\n this.messagingSystem.registerActionHandler(\n `${controllerName}:maybeUpdateState` as const,\n this.maybeUpdateState.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:testOrigin` as const,\n this.test.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanUrls` as const,\n this.bulkScanUrls.bind(this),\n );\n\n this.messagingSystem.registerActionHandler(\n `${controllerName}:bulkScanTokens` as const,\n this.bulkScanTokens.bind(this),\n );\n }\n\n /**\n * Checks if a patch represents a transaction-level change or nested transaction property change\n *\n * @param patch - Immer patch to check\n * @returns True if patch affects a transaction or its nested properties\n */\n #isTransactionPatch(patch: Patch): boolean {\n const { path } = patch;\n return (\n path.length === 2 &&\n path[0] === 'transactions' &&\n typeof path[1] === 'number'\n );\n }\n\n /**\n * Handle transaction controller state changes using Immer patches\n * Extracts token addresses from simulation data and groups them by chain for bulk scanning\n *\n * @param _state - The current transaction controller state\n * @param _state.transactions - Array of transaction metadata\n * @param patches - Array of Immer patches only for transaction-level changes\n */\n #onTransactionControllerStateChange(\n _state: { transactions: TransactionMeta[] },\n patches: Patch[],\n ) {\n try {\n const tokensByChain = new Map<string, Set<string>>();\n\n for (const patch of patches) {\n if (patch.op === 'remove') {\n continue;\n }\n\n // Handle transaction-level patches (includes simulation data updates)\n if (this.#isTransactionPatch(patch)) {\n const transaction = patch.value as TransactionMeta;\n this.#getTokensFromTransaction(transaction, tokensByChain);\n }\n }\n\n this.#scanTokensByChain(tokensByChain);\n } catch (error) {\n console.error('Error processing transaction state change:', error);\n }\n }\n\n /**\n * Collect token addresses from a transaction and group them by chain\n *\n * @param transaction - Transaction metadata to extract tokens from\n * @param tokensByChain - Map to collect tokens grouped by chainId\n */\n #getTokensFromTransaction(\n transaction: TransactionMeta,\n tokensByChain: Map<string, Set<string>>,\n ) {\n // extract token addresses from simulation data\n const tokenAddresses = transaction.simulationData?.tokenBalanceChanges?.map(\n (tokenChange) => tokenChange.address.toLowerCase(),\n );\n\n // add token addresses to the map by chainId\n if (tokenAddresses && tokenAddresses.length > 0 && transaction.chainId) {\n const chainId = transaction.chainId.toLowerCase();\n\n if (!tokensByChain.has(chainId)) {\n tokensByChain.set(chainId, new Set());\n }\n\n const chainTokens = tokensByChain.get(chainId);\n if (chainTokens) {\n for (const address of tokenAddresses) {\n chainTokens.add(address);\n }\n }\n }\n }\n\n /**\n * Scan tokens grouped by chain ID\n *\n * @param tokensByChain - Map of chainId to token addresses\n */\n #scanTokensByChain(tokensByChain: Map<string, Set<string>>) {\n for (const [chainId, tokenSet] of tokensByChain) {\n if (tokenSet.size > 0) {\n const tokens = Array.from(tokenSet);\n this.bulkScanTokens({\n chainId,\n tokens,\n }).catch((error) =>\n console.error(`Error scanning tokens for chain ${chainId}:`, error),\n );\n }\n }\n }\n\n /**\n * Updates this.detector with an instance of PhishingDetector using the current state.\n */\n updatePhishingDetector() {\n this.#detector = new PhishingDetector(this.state.phishingLists);\n }\n\n /**\n * Set the interval at which the stale phishing list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateStalelist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setStalelistRefreshInterval(interval: number) {\n this.#stalelistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the hot list will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setHotlistRefreshInterval(interval: number) {\n this.#hotlistRefreshInterval = interval;\n }\n\n /**\n * Set the interval at which the C2 domain blocklist will be refetched.\n * Fetching will only occur on the next call to test/bypass.\n * For immediate update to the phishing list, call {@link updateHotlist} directly.\n *\n * @param interval - the new interval, in ms.\n */\n setC2DomainBlocklistRefreshInterval(interval: number) {\n this.#c2DomainBlocklistRefreshInterval = interval;\n }\n\n /**\n * Set the time-to-live for URL scan cache entries.\n *\n * @param ttl - The TTL in seconds.\n */\n setUrlScanCacheTTL(ttl: number) {\n this.#urlScanCache.setTTL(ttl);\n }\n\n /**\n * Set the maximum number of entries in the URL scan cache.\n *\n * @param maxSize - The maximum cache size.\n */\n setUrlScanCacheMaxSize(maxSize: number) {\n this.#urlScanCache.setMaxSize(maxSize);\n }\n\n /**\n * Clear the URL scan cache.\n */\n clearUrlScanCache() {\n this.#urlScanCache.clear();\n }\n\n /**\n * Determine if an update to the stalelist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isStalelistOutOfDate() {\n return (\n fetchTimeNow() - this.state.stalelistLastFetched >=\n this.#stalelistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the hotlist configuration is needed.\n *\n * @returns Whether an update is needed\n */\n isHotlistOutOfDate() {\n return (\n fetchTimeNow() - this.state.hotlistLastFetched >=\n this.#hotlistRefreshInterval\n );\n }\n\n /**\n * Determine if an update to the C2 domain blocklist is needed.\n *\n * @returns Whether an update is needed\n */\n isC2DomainBlocklistOutOfDate() {\n return (\n fetchTimeNow() - this.state.c2DomainBlocklistLastFetched >=\n this.#c2DomainBlocklistRefreshInterval\n );\n }\n\n /**\n * Conditionally update the phishing configuration.\n *\n * If the stalelist configuration is out of date, this function will call `updateStalelist`\n * to update the configuration. This will automatically grab the hotlist,\n * so it isn't necessary to continue on to download the hotlist and the c2 domain blocklist.\n *\n */\n async maybeUpdateState() {\n const staleListOutOfDate = this.isStalelistOutOfDate();\n if (staleListOutOfDate) {\n await this.updateStalelist();\n return;\n }\n const hotlistOutOfDate = this.isHotlistOutOfDate();\n if (hotlistOutOfDate) {\n await this.updateHotlist();\n }\n const c2DomainBlocklistOutOfDate = this.isC2DomainBlocklistOutOfDate();\n if (c2DomainBlocklistOutOfDate) {\n await this.updateC2DomainBlocklist();\n }\n }\n\n /**\n * Determines if a given origin is unapproved.\n *\n * It is strongly recommended that you call {@link maybeUpdateState} before calling this,\n * to check whether the phishing configuration is up-to-date. It will be updated if necessary\n * by calling {@link updateStalelist} or {@link updateHotlist}.\n *\n * @param origin - Domain origin of a website.\n * @returns Whether the origin is an unapproved origin.\n */\n test(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n\n if (matchedPathPrefix(hostnameWithPaths, this.state.whitelistPaths)) {\n return { result: false, type: PhishingDetectorResultType.All };\n }\n\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.check(punycodeOrigin);\n }\n\n /**\n * Checks if a request URL's domain is blocked against the request blocklist.\n *\n * This method is used to determine if a specific request URL is associated with a malicious\n * command and control (C2) domain. The URL's hostname is hashed and checked against a configured\n * blocklist of known malicious domains.\n *\n * @param origin - The full request URL to be checked.\n * @returns An object indicating whether the URL's domain is blocked and relevant metadata.\n */\n isBlockedRequest(origin: string): PhishingDetectorResult {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n if (this.state.whitelist.includes(hostname || punycodeOrigin)) {\n return { result: false, type: PhishingDetectorResultType.All }; // Same as whitelisted match returned by detector.check(...).\n }\n return this.#detector.isMaliciousC2Domain(punycodeOrigin);\n }\n\n /**\n * Temporarily marks a given origin as approved.\n *\n * @param origin - The origin to mark as approved.\n */\n bypass(origin: string) {\n const punycodeOrigin = toASCII(origin);\n const hostname = getHostnameFromUrl(punycodeOrigin);\n const hostnameWithPaths = hostname + getPathnameFromUrl(origin);\n const { whitelist, whitelistPaths } = this.state;\n const whitelistPath = matchedPathPrefix(hostnameWithPaths, whitelistPaths);\n\n if (whitelist.includes(hostname || punycodeOrigin) || whitelistPath) {\n return;\n }\n\n // If the origin was blocked by a path, then we only want to add it to the whitelistPaths since\n // other paths with the same hostname may not be blocked.\n const blockingPath = this.#detector.blockingPath(origin);\n if (blockingPath) {\n this.update((draftState) => {\n insertToTrie(blockingPath, draftState.whitelistPaths);\n });\n return;\n }\n\n this.update((draftState) => {\n draftState.whitelist.push(hostname || punycodeOrigin);\n });\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateC2DomainBlocklist() {\n if (this.#isProgressC2DomainBlocklistUpdate) {\n await this.#isProgressC2DomainBlocklistUpdate;\n return;\n }\n\n try {\n this.#isProgressC2DomainBlocklistUpdate = this.#updateC2DomainBlocklist();\n await this.#isProgressC2DomainBlocklistUpdate;\n } finally {\n this.#isProgressC2DomainBlocklistUpdate = undefined;\n }\n }\n\n /**\n * Update the hotlist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateHotlist() {\n if (this.#inProgressHotlistUpdate) {\n await this.#inProgressHotlistUpdate;\n return;\n }\n\n try {\n this.#inProgressHotlistUpdate = this.#updateHotlist();\n await this.#inProgressHotlistUpdate;\n } finally {\n this.#inProgressHotlistUpdate = undefined;\n }\n }\n\n /**\n * Update the stalelist.\n *\n * If an update is in progress, no additional update will be made. Instead this will wait until\n * the in-progress update has finished.\n */\n async updateStalelist() {\n if (this.#inProgressStalelistUpdate) {\n await this.#inProgressStalelistUpdate;\n return;\n }\n\n try {\n this.#inProgressStalelistUpdate = this.#updateStalelist();\n await this.#inProgressStalelistUpdate;\n } finally {\n this.#inProgressStalelistUpdate = undefined;\n }\n }\n\n /**\n * Scan a URL for phishing. It will only scan the hostname of the URL. It also only supports\n * web URLs.\n *\n * @param url - The URL to scan.\n * @returns The phishing detection scan result.\n */\n scanUrl = async (url: string): Promise<PhishingDetectionScanResult> => {\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'url is not a valid web URL',\n };\n }\n\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n return cachedResult;\n }\n\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_SCAN_ENDPOINT}?url=${encodeURIComponent(hostname)}`,\n {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n },\n },\n );\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n };\n }\n const data = await res.json();\n return data;\n },\n true,\n 8000,\n );\n\n // Need to do it this way because safelyExecuteWithTimeout returns undefined for both timeouts and errors.\n if (!apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: 'timeout of 8000ms exceeded',\n };\n } else if ('error' in apiResponse) {\n return {\n hostname: '',\n recommendedAction: RecommendedAction.None,\n fetchError: apiResponse.error,\n };\n }\n\n const result = {\n hostname,\n recommendedAction: apiResponse.recommendedAction,\n };\n\n this.#urlScanCache.set(hostname, result);\n\n return result;\n };\n\n /**\n * Scan multiple URLs for phishing in bulk. It will only scan the hostnames of the URLs.\n * It also only supports web URLs.\n *\n * @param urls - The URLs to scan.\n * @returns A mapping of URLs to their phishing detection scan results and errors.\n */\n bulkScanUrls = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n if (!urls || urls.length === 0) {\n return {\n results: {},\n errors: {},\n };\n }\n\n // we are arbitrarily limiting the number of URLs to 250\n const MAX_TOTAL_URLS = 250;\n if (urls.length > MAX_TOTAL_URLS) {\n return {\n results: {},\n errors: {\n too_many_urls: [\n `Maximum of ${MAX_TOTAL_URLS} URLs allowed per request`,\n ],\n },\n };\n }\n\n const MAX_URL_LENGTH = 2048;\n const combinedResponse: BulkPhishingDetectionScanResponse = {\n results: {},\n errors: {},\n };\n\n // Extract hostnames from URLs and check for validity and length constraints\n const urlsToHostnames: Record<string, string> = {};\n const urlsToFetch: string[] = [];\n\n for (const url of urls) {\n if (url.length > MAX_URL_LENGTH) {\n combinedResponse.errors[url] = [\n `URL length must not exceed ${MAX_URL_LENGTH} characters`,\n ];\n continue;\n }\n\n const [hostname, ok] = getHostnameFromWebUrl(url);\n if (!ok) {\n combinedResponse.errors[url] = ['url is not a valid web URL'];\n continue;\n }\n\n // Check if result is already in cache\n const cachedResult = this.#urlScanCache.get(hostname);\n if (cachedResult) {\n // Use cached result\n combinedResponse.results[url] = cachedResult;\n } else {\n // Add to list of URLs to fetch\n urlsToHostnames[url] = hostname;\n urlsToFetch.push(url);\n }\n }\n\n // If there are URLs to fetch, process them in batches\n if (urlsToFetch.length > 0) {\n // The API has a limit of 50 URLs per request, so we batch the requests\n const MAX_URLS_PER_BATCH = 50;\n const batches: string[][] = [];\n for (let i = 0; i < urlsToFetch.length; i += MAX_URLS_PER_BATCH) {\n batches.push(urlsToFetch.slice(i, i + MAX_URLS_PER_BATCH));\n }\n\n // Process each batch in parallel\n const batchResults = await Promise.all(\n batches.map((batchUrls) => this.#processBatch(batchUrls)),\n );\n\n // Merge results and errors from all batches\n batchResults.forEach((batchResponse) => {\n // Add results to cache and combine with response\n Object.entries(batchResponse.results).forEach(([url, result]) => {\n const hostname = urlsToHostnames[url];\n if (hostname) {\n this.#urlScanCache.set(hostname, result);\n }\n combinedResponse.results[url] = result;\n });\n\n // Combine errors\n Object.entries(batchResponse.errors).forEach(([key, messages]) => {\n combinedResponse.errors[key] = [\n ...(combinedResponse.errors[key] || []),\n ...messages,\n ];\n });\n });\n }\n\n return combinedResponse;\n };\n\n /**\n * Fetch bulk token scan results from the security alerts API.\n *\n * @param chain - The chain name.\n * @param tokens - Array of token addresses to scan.\n * @returns The API response or null if there was an error.\n */\n readonly #fetchTokenScanBulkResults = async (\n chain: string,\n tokens: string[],\n ): Promise<TokenScanApiResponse | null> => {\n const timeout = 8000; // 8 seconds\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const response = await fetch(\n `${SECURITY_ALERTS_BASE_URL}${TOKEN_BULK_SCANNING_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n chain,\n tokens,\n }),\n },\n );\n\n if (!response.ok) {\n return {\n error: `${response.status} ${response.statusText}`,\n status: response.status,\n statusText: response.statusText,\n };\n }\n\n const data = await response.json();\n return data;\n },\n true,\n timeout,\n );\n\n if (!apiResponse) {\n console.error(`Error scanning tokens: timeout of ${timeout}ms exceeded`);\n return null;\n }\n\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n console.warn(\n `Token bulk screening API error: ${apiResponse.status} ${apiResponse.statusText}`,\n );\n return null;\n }\n\n return apiResponse as TokenScanApiResponse;\n };\n\n /**\n * Scan multiple tokens for malicious activity in bulk.\n *\n * @param request - The bulk scan request containing chainId and tokens.\n * @param request.chainId - The chain ID in hex format (e.g., '0x1' for Ethereum).\n * @param request.tokens - Array of token addresses to scan.\n * @returns A mapping of lowercase token addresses to their scan results. Tokens that fail to scan are omitted.\n */\n bulkScanTokens = async (\n request: BulkTokenScanRequest,\n ): Promise<BulkTokenScanResponse> => {\n const { chainId, tokens } = request;\n\n if (!tokens || tokens.length === 0) {\n return {};\n }\n\n const MAX_TOKENS_PER_REQUEST = 100;\n if (tokens.length > MAX_TOKENS_PER_REQUEST) {\n console.warn(\n `Maximum of ${MAX_TOKENS_PER_REQUEST} tokens allowed per request`,\n );\n return {};\n }\n\n const normalizedChainId = chainId.toLowerCase();\n const chain = resolveChainName(normalizedChainId);\n\n if (!chain) {\n console.warn(`Unknown chain ID: ${chainId}`);\n return {};\n }\n\n // Split tokens into cached results and tokens that need to be fetched\n const { cachedResults, tokensToFetch } = splitCacheHits(\n this.#tokenScanCache,\n normalizedChainId,\n tokens,\n );\n\n const results: BulkTokenScanResponse = { ...cachedResults };\n\n // If there are tokens to fetch, call the bulk token scan API\n if (tokensToFetch.length > 0) {\n const apiResponse = await this.#fetchTokenScanBulkResults(\n chain,\n tokensToFetch,\n );\n\n if (apiResponse?.results) {\n // Process API results and update cache\n for (const tokenAddress of tokensToFetch) {\n const normalizedAddress = tokenAddress.toLowerCase();\n const tokenResult = apiResponse.results[normalizedAddress];\n\n if (tokenResult?.result_type) {\n const result = {\n result_type: tokenResult.result_type,\n chain: tokenResult.chain || normalizedChainId,\n address: tokenResult.address || normalizedAddress,\n };\n\n // Update cache\n const cacheKey = buildCacheKey(\n normalizedChainId,\n normalizedAddress,\n );\n this.#tokenScanCache.set(cacheKey, {\n result_type: tokenResult.result_type,\n });\n\n results[normalizedAddress] = result;\n }\n }\n }\n }\n\n return results;\n };\n\n /**\n * Process a batch of URLs (up to 50) for phishing detection.\n *\n * @param urls - A batch of URLs to scan.\n * @returns The scan results and errors for this batch.\n */\n readonly #processBatch = async (\n urls: string[],\n ): Promise<BulkPhishingDetectionScanResponse> => {\n const apiResponse = await safelyExecuteWithTimeout(\n async () => {\n const res = await fetch(\n `${PHISHING_DETECTION_BASE_URL}/${PHISHING_DETECTION_BULK_SCAN_ENDPOINT}`,\n {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({ urls }),\n },\n );\n\n if (!res.ok) {\n return {\n error: `${res.status} ${res.statusText}`,\n status: res.status,\n statusText: res.statusText,\n };\n }\n\n const data = await res.json();\n return data;\n },\n true,\n 15000,\n );\n\n // Handle timeout or network errors\n if (!apiResponse) {\n return {\n results: {},\n errors: {\n network_error: ['timeout of 15000ms exceeded'],\n },\n };\n }\n\n // Handle HTTP error responses\n if (\n 'error' in apiResponse &&\n 'status' in apiResponse &&\n 'statusText' in apiResponse\n ) {\n return {\n results: {},\n errors: {\n api_error: [`${apiResponse.status} ${apiResponse.statusText}`],\n },\n };\n }\n\n return apiResponse as BulkPhishingDetectionScanResponse;\n };\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateStalelist() {\n let stalelistResponse: DataResultWrapper<PhishingStalelist> | null = null;\n let hotlistDiffsResponse: DataResultWrapper<Hotlist> | null = null;\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n try {\n const stalelistPromise = this.#queryConfig<\n DataResultWrapper<PhishingStalelist>\n >(METAMASK_STALELIST_URL);\n\n const c2DomainBlocklistPromise =\n this.#queryConfig<C2DomainBlocklistResponse>(C2_DOMAIN_BLOCKLIST_URL);\n\n [stalelistResponse, c2DomainBlocklistResponse] = await Promise.all([\n stalelistPromise,\n c2DomainBlocklistPromise,\n ]);\n // Fetching hotlist diffs relies on having a lastUpdated timestamp to do `GET /v1/diffsSince/:timestamp`,\n // so it doesn't make sense to call if there is not a timestamp to begin with.\n if (stalelistResponse?.data && stalelistResponse.data.lastUpdated > 0) {\n hotlistDiffsResponse = await this.#queryConfig<\n DataResultWrapper<Hotlist>\n >(\n `${METAMASK_HOTLIST_DIFF_URL}/${stalelistResponse.data.lastUpdated}?blocklistPaths=true`,\n );\n }\n } finally {\n // Set `stalelistLastFetched` and `hotlistLastFetched` even for failed requests to prevent server\n // from being overwhelmed with traffic after a network disruption.\n const timeNow = fetchTimeNow();\n this.update((draftState) => {\n draftState.stalelistLastFetched = timeNow;\n draftState.hotlistLastFetched = timeNow;\n draftState.c2DomainBlocklistLastFetched = timeNow;\n });\n }\n\n if (!stalelistResponse || !hotlistDiffsResponse) {\n return;\n }\n\n const metamaskListState: PhishingListState = {\n allowlist: stalelistResponse.data.allowlist,\n fuzzylist: stalelistResponse.data.fuzzylist,\n tolerance: stalelistResponse.data.tolerance,\n version: stalelistResponse.data.version,\n lastUpdated: stalelistResponse.data.lastUpdated,\n blocklist: stalelistResponse.data.blocklist,\n blocklistPaths: convertListToTrie(stalelistResponse.data.blocklistPaths),\n c2DomainBlocklist: c2DomainBlocklistResponse\n ? c2DomainBlocklistResponse.recentlyAdded\n : [],\n name: phishingListKeyNameMap.eth_phishing_detect_config,\n };\n\n const newMetaMaskListState: PhishingListState = applyDiffs(\n metamaskListState,\n hotlistDiffsResponse.data,\n ListKeys.EthPhishingDetectConfig,\n );\n\n this.update((draftState) => {\n draftState.phishingLists = [newMetaMaskListState];\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the stalelist configuration.\n *\n * This should only be called from the `updateStalelist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateHotlist() {\n let hotlistResponse: DataResultWrapper<Hotlist> | null;\n\n try {\n if (this.state.phishingLists.length === 0) {\n return;\n }\n\n const lastDiffTimestamp = Math.max(\n ...this.state.phishingLists.map(({ lastUpdated }) => lastUpdated),\n );\n\n hotlistResponse = await this.#queryConfig<DataResultWrapper<Hotlist>>(\n `${METAMASK_HOTLIST_DIFF_URL}/${lastDiffTimestamp}?blocklistPaths=true`,\n );\n } finally {\n // Set `hotlistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.hotlistLastFetched = fetchTimeNow();\n });\n }\n\n if (!hotlistResponse?.data) {\n return;\n }\n const hotlist = hotlistResponse.data;\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n hotlist,\n phishingListNameKeyMap[phishingList.name],\n [],\n [],\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n /**\n * Update the C2 domain blocklist.\n *\n * This should only be called from the `updateC2DomainBlocklist` function, which is a wrapper around\n * this function that prevents redundant configuration updates.\n */\n async #updateC2DomainBlocklist() {\n let c2DomainBlocklistResponse: C2DomainBlocklistResponse | null = null;\n\n try {\n c2DomainBlocklistResponse =\n await this.#queryConfig<C2DomainBlocklistResponse>(\n `${C2_DOMAIN_BLOCKLIST_URL}?timestamp=${roundToNearestMinute(\n this.state.c2DomainBlocklistLastFetched,\n )}`,\n );\n } finally {\n // Set `c2DomainBlocklistLastFetched` even for failed requests to prevent server from being overwhelmed with\n // traffic after a network disruption.\n this.update((draftState) => {\n draftState.c2DomainBlocklistLastFetched = fetchTimeNow();\n });\n }\n\n if (!c2DomainBlocklistResponse) {\n return;\n }\n\n const recentlyAddedC2Domains = c2DomainBlocklistResponse.recentlyAdded;\n const recentlyRemovedC2Domains = c2DomainBlocklistResponse.recentlyRemoved;\n\n const newPhishingLists = this.state.phishingLists.map((phishingList) => {\n const updatedList = applyDiffs(\n phishingList,\n [],\n phishingListNameKeyMap[phishingList.name],\n recentlyAddedC2Domains,\n recentlyRemovedC2Domains,\n );\n\n return updatedList;\n });\n\n this.update((draftState) => {\n draftState.phishingLists = newPhishingLists;\n });\n this.updatePhishingDetector();\n }\n\n async #queryConfig<ResponseType>(\n input: RequestInfo,\n ): Promise<ResponseType | null> {\n const response = await safelyExecute(\n () => fetch(input, { cache: 'no-cache' }),\n true,\n );\n\n switch (response?.status) {\n case 200: {\n return await response.json();\n }\n\n default: {\n return null;\n }\n }\n }\n}\n\nexport default PhishingController;\n\nexport type { PhishingDetectorResult };\n"]}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@metamask-previews/phishing-controller",
|
3
|
-
"version": "14.1.
|
3
|
+
"version": "14.1.1-preview-05b702c4",
|
4
4
|
"description": "Maintains a periodically updated list of approved and unapproved website origins",
|
5
5
|
"keywords": [
|
6
6
|
"MetaMask",
|
@@ -47,8 +47,8 @@
|
|
47
47
|
"test:watch": "NODE_OPTIONS=--experimental-vm-modules jest --watch"
|
48
48
|
},
|
49
49
|
"dependencies": {
|
50
|
-
"@metamask/base-controller": "^8.4.
|
51
|
-
"@metamask/controller-utils": "^11.14.
|
50
|
+
"@metamask/base-controller": "^8.4.1",
|
51
|
+
"@metamask/controller-utils": "^11.14.1",
|
52
52
|
"@noble/hashes": "^1.8.0",
|
53
53
|
"@types/punycode": "^2.1.0",
|
54
54
|
"ethereum-cryptography": "^2.1.2",
|
@@ -57,7 +57,7 @@
|
|
57
57
|
},
|
58
58
|
"devDependencies": {
|
59
59
|
"@metamask/auto-changelog": "^3.4.4",
|
60
|
-
"@metamask/transaction-controller": "^60.6.
|
60
|
+
"@metamask/transaction-controller": "^60.6.1",
|
61
61
|
"@types/jest": "^27.4.1",
|
62
62
|
"deepmerge": "^4.2.2",
|
63
63
|
"jest": "^27.5.1",
|