@metamask-previews/phishing-controller 16.2.0-preview-6a225bc30 → 16.2.0-preview-e7b1aa6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsCA;;GAEG;AACH,MAAM,CAAN,IAAY,0BA+BX;AA/BD,WAAY,0BAA0B;IACpC;;OAEG;IACH,yCAAW,CAAA;IACX;;OAEG;IACH,6CAAe,CAAA;IACf;;OAEG;IACH,qDAAuB,CAAA;IACvB;;OAEG;IACH,qDAAuB,CAAA;IACvB;;;OAGG;IACH,qDAAuB,CAAA;IACvB;;;OAGG;IACH,qDAAuB,CAAA;IACvB;;OAEG;IACH,qEAAuC,CAAA;AACzC,CAAC,EA/BW,0BAA0B,KAA1B,0BAA0B,QA+BrC;AA8BD;;GAEG;AACH,MAAM,CAAN,IAAY,iBAkBX;AAlBD,WAAY,iBAAiB;IAC3B;;OAEG;IACH,kCAAa,CAAA;IACb;;OAEG;IACH,kCAAa,CAAA;IACb;;OAEG;IACH,oCAAe,CAAA;IACf;;;OAGG;IACH,0CAAqB,CAAA;AACvB,CAAC,EAlBW,iBAAiB,KAAjB,iBAAiB,QAkB5B;AAUD;;GAEG;AACH,MAAM,CAAN,IAAY,mBAKX;AALD,WAAY,mBAAmB;IAC7B,wCAAiB,CAAA;IACjB,0CAAmB,CAAA;IACnB,8CAAuB,CAAA;IACvB,oCAAa,CAAA;AACf,CAAC,EALW,mBAAmB,KAAnB,mBAAmB,QAK9B;AAoCD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,KAAK;IACb,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,MAAM;IAClB,QAAQ,EAAE,OAAO;IACjB,YAAY,EAAE,OAAO;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,QAAQ;IACnB,SAAS,EAAE,OAAO;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,gBAAgB;IACzB,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,kBAAkB;IAC9B,QAAQ,EAAE,gBAAgB;IAC1B,QAAQ,EAAE,iBAAiB;IAC3B,QAAQ,EAAE,yBAAyB;IACnC,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,kBAAkB;IAC7B,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,aAAa;IACxB,QAAQ,EAAE,kBAAkB;IAC5B,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,QAAQ;CACR,CAAC;AAIX;;GAEG;AACH,MAAM,CAAN,IAAY,qBAiBX;AAjBD,WAAY,qBAAqB;IAC/B;;OAEG;IACH,0CAAiB,CAAA;IACjB;;OAEG;IACH,4CAAmB,CAAA;IACnB;;OAEG;IACH,gDAAuB,CAAA;IACvB;;OAEG;IACH,oDAA2B,CAAA;AAC7B,CAAC,EAjBW,qBAAqB,KAArB,qBAAqB,QAiBhC","sourcesContent":["/**\n * Represents the result of checking a domain.\n */\nexport type PhishingDetectorResult = {\n /**\n * The name of the configuration object in which the domain was found within\n * an allowlist, blocklist, or fuzzylist.\n */\n name?: string;\n /**\n * The version associated with the configuration object in which the domain\n * was found within an allowlist, blocklist, or fuzzylist.\n */\n version?: string;\n /**\n * Whether the domain is regarded as allowed (true) or not (false).\n */\n result: boolean;\n /**\n * A normalized version of the domain, which is only constructed if the domain\n * is found within a list.\n */\n match?: string;\n /**\n * Which type of list in which the domain was found.\n *\n * - \"allowlist\" means that the domain was found in the allowlist.\n * - \"blocklist\" means that the domain was found in the blocklist.\n * - \"fuzzy\" means that the domain was found in the fuzzylist.\n * - \"blacklist\" means that the domain was found in a blacklist of a legacy\n * configuration object.\n * - \"whitelist\" means that the domain was found in a whitelist of a legacy\n * configuration object.\n * - \"all\" means that the domain was not found in any list.\n */\n type: PhishingDetectorResultType;\n};\n\n/**\n * The type of list in which the domain was found.\n */\nexport enum PhishingDetectorResultType {\n /*\n * \"all\" means that the domain was not found in any list.\n */\n All = 'all',\n /*\n * \"fuzzy\" means that the domain was found in the fuzzylist.\n */\n Fuzzy = 'fuzzy',\n /*\n * \"blocklist\" means that the domain was found in the blocklist.\n */\n Blocklist = 'blocklist',\n /*\n * \"allowlist\" means that the domain was found in the allowlist.\n */\n Allowlist = 'allowlist',\n /*\n * \"blacklist\" means that the domain was found in a blacklist of a legacy\n * configuration object.\n */\n Blacklist = 'blacklist',\n /*\n * \"whitelist\" means that the domain was found in a whitelist of a legacy\n * configuration object.\n */\n Whitelist = 'whitelist',\n /*\n * \"c2DomainBlocklist\" means that the domain was found in the C2 domain blocklist.\n */\n C2DomainBlocklist = 'c2DomainBlocklist',\n}\n\n/**\n * PhishingDetectionScanResult represents the result of a phishing detection scan.\n */\nexport type PhishingDetectionScanResult = {\n /**\n * The hostname that was scanned.\n */\n hostname: string;\n /**\n * Indicates the warning level based on risk factors.\n *\n * - \"NONE\" means it is most likely safe.\n * - \"WARN\" means there is some risk.\n * - \"BLOCK\" means it is highly likely to be malicious.\n * - \"VERIFIED\" means it has been associated as an official domain of a\n * company or organization and/or a top Web3 domain.\n */\n recommendedAction: RecommendedAction;\n /**\n * An optional error message that exists if:\n * - The link requested is not a valid web URL.\n * - Failed to fetch the result from the phishing detector.\n *\n * Consumers can use the existence of this field to retry.\n */\n fetchError?: string;\n};\n\n/**\n * Indicates the warning level based on risk factors\n */\nexport enum RecommendedAction {\n /**\n * None means it is most likely safe\n */\n None = 'NONE',\n /**\n * Warn means there is some risk\n */\n Warn = 'WARN',\n /**\n * Block means it is highly likely to be malicious\n */\n Block = 'BLOCK',\n /**\n * Verified means it has been associated as an official domain of a\n * company or organization and/or a top Web3 domain.\n */\n Verified = 'VERIFIED',\n}\n\n/**\n * Request for bulk token scan\n */\nexport type BulkTokenScanRequest = {\n chainId: string;\n tokens: string[];\n};\n\n/**\n * Result type of a token scan\n */\nexport enum TokenScanResultType {\n Benign = 'Benign',\n Warning = 'Warning',\n Malicious = 'Malicious',\n Spam = 'Spam',\n}\n\n/**\n * Result of a token scan\n */\nexport type TokenScanResult = {\n result_type: TokenScanResultType;\n chain: string;\n address: string;\n};\n\n/**\n * Response for bulk token scan requests\n */\nexport type BulkTokenScanResponse = Record<string, TokenScanResult>;\n\n/**\n * Token data stored in cache (excludes chain and address which are in the key)\n * For now, we only cache the result type, but we could add more data if needed in the future\n */\nexport type TokenScanCacheData = Omit<TokenScanResult, 'chain' | 'address'>;\n\n/**\n * API response from the bulk token scanning endpoint\n */\nexport type TokenScanApiResponse = {\n results: Record<\n string,\n {\n result_type: TokenScanResultType;\n chain?: string;\n address?: string;\n }\n >;\n};\n\nexport const DEFAULT_CHAIN_ID_TO_NAME = {\n '0x1': 'ethereum',\n '0x89': 'polygon',\n '0x38': 'bsc',\n '0xa4b1': 'arbitrum',\n '0xa86a': 'avalanche',\n '0x2105': 'base',\n '0xa': 'optimism',\n '0x76adf1': 'zora',\n '0xe708': 'linea',\n '0x27bc86aa': 'degen',\n '0x144': 'zksync',\n '0x82750': 'scroll',\n '0x13e31': 'blast',\n '0x74c': 'soneium',\n '0x79a': 'soneium-minato',\n '0x14a34': 'base-sepolia',\n '0xab5': 'abstract',\n '0x849ea': 'zero-network',\n '0x138de': 'berachain',\n '0x82': 'unichain',\n '0x7e4': 'ronin',\n '0x127': 'hedera',\n '0x12c': 'zksync-sepolia',\n '0xaa36a7': 'ethereum-sepolia',\n '0xa869': 'avalanche-fuji',\n '0x343b': 'immutable-zkevm',\n '0x34a1': 'immutable-zkevm-testnet',\n '0x64': 'gnosis',\n '0x1e0': 'worldchain',\n '0x8173': 'apechain',\n '0x138c5': 'berachain-bartio',\n '0xdef1': 'ink',\n '0xba5ed': 'ink-sepolia',\n '0x2b74': 'abstract-testnet',\n '0x531': 'sei',\n '0x2eb': 'flow-evm',\n '0x8f': 'monad',\n '0x3e7': 'hyperevm',\n solana: 'solana',\n} as const;\n\nexport type ChainIdToNameMap = typeof DEFAULT_CHAIN_ID_TO_NAME;\n\n/**\n * Result type of an address scan\n */\nexport enum AddressScanResultType {\n /**\n * Address is benign/safe\n */\n Benign = 'Benign',\n /**\n * Address has warning indicators\n */\n Warning = 'Warning',\n /**\n * Address is malicious\n */\n Malicious = 'Malicious',\n /**\n * Error occurred during scan\n */\n ErrorResult = 'ErrorResult',\n}\n\n/**\n * Result of an address security scan\n */\nexport type AddressScanResult = {\n /**\n * The result type indicating the security assessment\n */\n result_type: AddressScanResultType;\n /**\n * Additional label or description for the result\n */\n label: string;\n};\n\n/**\n * Address data stored in cache (minimal data needed)\n */\nexport type AddressScanCacheData = {\n result_type: AddressScanResultType;\n label: string;\n};\n"]}
1
+ {"version":3,"file":"types.mjs","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAsCA;;GAEG;AACH,MAAM,CAAN,IAAY,0BA+BX;AA/BD,WAAY,0BAA0B;IACpC;;OAEG;IACH,yCAAW,CAAA;IACX;;OAEG;IACH,6CAAe,CAAA;IACf;;OAEG;IACH,qDAAuB,CAAA;IACvB;;OAEG;IACH,qDAAuB,CAAA;IACvB;;;OAGG;IACH,qDAAuB,CAAA;IACvB;;;OAGG;IACH,qDAAuB,CAAA;IACvB;;OAEG;IACH,qEAAuC,CAAA;AACzC,CAAC,EA/BW,0BAA0B,KAA1B,0BAA0B,QA+BrC;AA8BD;;GAEG;AACH,MAAM,CAAN,IAAY,iBAkBX;AAlBD,WAAY,iBAAiB;IAC3B;;OAEG;IACH,kCAAa,CAAA;IACb;;OAEG;IACH,kCAAa,CAAA;IACb;;OAEG;IACH,oCAAe,CAAA;IACf;;;OAGG;IACH,0CAAqB,CAAA;AACvB,CAAC,EAlBW,iBAAiB,KAAjB,iBAAiB,QAkB5B;AAUD;;GAEG;AACH,MAAM,CAAN,IAAY,mBAKX;AALD,WAAY,mBAAmB;IAC7B,wCAAiB,CAAA;IACjB,0CAAmB,CAAA;IACnB,8CAAuB,CAAA;IACvB,oCAAa,CAAA;AACf,CAAC,EALW,mBAAmB,KAAnB,mBAAmB,QAK9B;AAoCD,MAAM,CAAC,MAAM,wBAAwB,GAAG;IACtC,KAAK,EAAE,UAAU;IACjB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,KAAK;IACb,QAAQ,EAAE,UAAU;IACpB,QAAQ,EAAE,WAAW;IACrB,QAAQ,EAAE,MAAM;IAChB,KAAK,EAAE,UAAU;IACjB,UAAU,EAAE,MAAM;IAClB,QAAQ,EAAE,OAAO;IACjB,YAAY,EAAE,OAAO;IACrB,OAAO,EAAE,QAAQ;IACjB,SAAS,EAAE,QAAQ;IACnB,SAAS,EAAE,OAAO;IAClB,OAAO,EAAE,SAAS;IAClB,OAAO,EAAE,gBAAgB;IACzB,SAAS,EAAE,cAAc;IACzB,OAAO,EAAE,UAAU;IACnB,SAAS,EAAE,cAAc;IACzB,SAAS,EAAE,WAAW;IACtB,MAAM,EAAE,UAAU;IAClB,OAAO,EAAE,OAAO;IAChB,OAAO,EAAE,QAAQ;IACjB,OAAO,EAAE,gBAAgB;IACzB,UAAU,EAAE,kBAAkB;IAC9B,QAAQ,EAAE,gBAAgB;IAC1B,QAAQ,EAAE,iBAAiB;IAC3B,QAAQ,EAAE,yBAAyB;IACnC,MAAM,EAAE,QAAQ;IAChB,OAAO,EAAE,YAAY;IACrB,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,kBAAkB;IAC7B,QAAQ,EAAE,KAAK;IACf,SAAS,EAAE,aAAa;IACxB,QAAQ,EAAE,kBAAkB;IAC5B,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,UAAU;IACnB,MAAM,EAAE,OAAO;IACf,OAAO,EAAE,UAAU;CACX,CAAC;AAIX;;GAEG;AACH,MAAM,CAAN,IAAY,qBAiBX;AAjBD,WAAY,qBAAqB;IAC/B;;OAEG;IACH,0CAAiB,CAAA;IACjB;;OAEG;IACH,4CAAmB,CAAA;IACnB;;OAEG;IACH,gDAAuB,CAAA;IACvB;;OAEG;IACH,oDAA2B,CAAA;AAC7B,CAAC,EAjBW,qBAAqB,KAArB,qBAAqB,QAiBhC","sourcesContent":["/**\n * Represents the result of checking a domain.\n */\nexport type PhishingDetectorResult = {\n /**\n * The name of the configuration object in which the domain was found within\n * an allowlist, blocklist, or fuzzylist.\n */\n name?: string;\n /**\n * The version associated with the configuration object in which the domain\n * was found within an allowlist, blocklist, or fuzzylist.\n */\n version?: string;\n /**\n * Whether the domain is regarded as allowed (true) or not (false).\n */\n result: boolean;\n /**\n * A normalized version of the domain, which is only constructed if the domain\n * is found within a list.\n */\n match?: string;\n /**\n * Which type of list in which the domain was found.\n *\n * - \"allowlist\" means that the domain was found in the allowlist.\n * - \"blocklist\" means that the domain was found in the blocklist.\n * - \"fuzzy\" means that the domain was found in the fuzzylist.\n * - \"blacklist\" means that the domain was found in a blacklist of a legacy\n * configuration object.\n * - \"whitelist\" means that the domain was found in a whitelist of a legacy\n * configuration object.\n * - \"all\" means that the domain was not found in any list.\n */\n type: PhishingDetectorResultType;\n};\n\n/**\n * The type of list in which the domain was found.\n */\nexport enum PhishingDetectorResultType {\n /*\n * \"all\" means that the domain was not found in any list.\n */\n All = 'all',\n /*\n * \"fuzzy\" means that the domain was found in the fuzzylist.\n */\n Fuzzy = 'fuzzy',\n /*\n * \"blocklist\" means that the domain was found in the blocklist.\n */\n Blocklist = 'blocklist',\n /*\n * \"allowlist\" means that the domain was found in the allowlist.\n */\n Allowlist = 'allowlist',\n /*\n * \"blacklist\" means that the domain was found in a blacklist of a legacy\n * configuration object.\n */\n Blacklist = 'blacklist',\n /*\n * \"whitelist\" means that the domain was found in a whitelist of a legacy\n * configuration object.\n */\n Whitelist = 'whitelist',\n /*\n * \"c2DomainBlocklist\" means that the domain was found in the C2 domain blocklist.\n */\n C2DomainBlocklist = 'c2DomainBlocklist',\n}\n\n/**\n * PhishingDetectionScanResult represents the result of a phishing detection scan.\n */\nexport type PhishingDetectionScanResult = {\n /**\n * The hostname that was scanned.\n */\n hostname: string;\n /**\n * Indicates the warning level based on risk factors.\n *\n * - \"NONE\" means it is most likely safe.\n * - \"WARN\" means there is some risk.\n * - \"BLOCK\" means it is highly likely to be malicious.\n * - \"VERIFIED\" means it has been associated as an official domain of a\n * company or organization and/or a top Web3 domain.\n */\n recommendedAction: RecommendedAction;\n /**\n * An optional error message that exists if:\n * - The link requested is not a valid web URL.\n * - Failed to fetch the result from the phishing detector.\n *\n * Consumers can use the existence of this field to retry.\n */\n fetchError?: string;\n};\n\n/**\n * Indicates the warning level based on risk factors\n */\nexport enum RecommendedAction {\n /**\n * None means it is most likely safe\n */\n None = 'NONE',\n /**\n * Warn means there is some risk\n */\n Warn = 'WARN',\n /**\n * Block means it is highly likely to be malicious\n */\n Block = 'BLOCK',\n /**\n * Verified means it has been associated as an official domain of a\n * company or organization and/or a top Web3 domain.\n */\n Verified = 'VERIFIED',\n}\n\n/**\n * Request for bulk token scan\n */\nexport type BulkTokenScanRequest = {\n chainId: string;\n tokens: string[];\n};\n\n/**\n * Result type of a token scan\n */\nexport enum TokenScanResultType {\n Benign = 'Benign',\n Warning = 'Warning',\n Malicious = 'Malicious',\n Spam = 'Spam',\n}\n\n/**\n * Result of a token scan\n */\nexport type TokenScanResult = {\n result_type: TokenScanResultType;\n chain: string;\n address: string;\n};\n\n/**\n * Response for bulk token scan requests\n */\nexport type BulkTokenScanResponse = Record<string, TokenScanResult>;\n\n/**\n * Token data stored in cache (excludes chain and address which are in the key)\n * For now, we only cache the result type, but we could add more data if needed in the future\n */\nexport type TokenScanCacheData = Omit<TokenScanResult, 'chain' | 'address'>;\n\n/**\n * API response from the bulk token scanning endpoint\n */\nexport type TokenScanApiResponse = {\n results: Record<\n string,\n {\n result_type: TokenScanResultType;\n chain?: string;\n address?: string;\n }\n >;\n};\n\nexport const DEFAULT_CHAIN_ID_TO_NAME = {\n '0x1': 'ethereum',\n '0x89': 'polygon',\n '0x38': 'bsc',\n '0xa4b1': 'arbitrum',\n '0xa86a': 'avalanche',\n '0x2105': 'base',\n '0xa': 'optimism',\n '0x76adf1': 'zora',\n '0xe708': 'linea',\n '0x27bc86aa': 'degen',\n '0x144': 'zksync',\n '0x82750': 'scroll',\n '0x13e31': 'blast',\n '0x74c': 'soneium',\n '0x79a': 'soneium-minato',\n '0x14a34': 'base-sepolia',\n '0xab5': 'abstract',\n '0x849ea': 'zero-network',\n '0x138de': 'berachain',\n '0x82': 'unichain',\n '0x7e4': 'ronin',\n '0x127': 'hedera',\n '0x12c': 'zksync-sepolia',\n '0xaa36a7': 'ethereum-sepolia',\n '0xa869': 'avalanche-fuji',\n '0x343b': 'immutable-zkevm',\n '0x34a1': 'immutable-zkevm-testnet',\n '0x64': 'gnosis',\n '0x1e0': 'worldchain',\n '0x8173': 'apechain',\n '0x138c5': 'berachain-bartio',\n '0xdef1': 'ink',\n '0xba5ed': 'ink-sepolia',\n '0x2b74': 'abstract-testnet',\n '0x531': 'sei',\n '0x2eb': 'flow-evm',\n '0x8f': 'monad',\n '0x3e7': 'hyperevm',\n} as const;\n\nexport type ChainIdToNameMap = typeof DEFAULT_CHAIN_ID_TO_NAME;\n\n/**\n * Result type of an address scan\n */\nexport enum AddressScanResultType {\n /**\n * Address is benign/safe\n */\n Benign = 'Benign',\n /**\n * Address has warning indicators\n */\n Warning = 'Warning',\n /**\n * Address is malicious\n */\n Malicious = 'Malicious',\n /**\n * Error occurred during scan\n */\n ErrorResult = 'ErrorResult',\n}\n\n/**\n * Result of an address security scan\n */\nexport type AddressScanResult = {\n /**\n * The result type indicating the security assessment\n */\n result_type: AddressScanResultType;\n /**\n * Additional label or description for the result\n */\n label: string;\n};\n\n/**\n * Address data stored in cache (minimal data needed)\n */\nexport type AddressScanCacheData = {\n result_type: AddressScanResultType;\n label: string;\n};\n"]}
package/dist/utils.cjs CHANGED
@@ -367,14 +367,10 @@ exports.generateParentDomains = generateParentDomains;
367
367
  *
368
368
  * @param chainId - The chain ID.
369
369
  * @param address - The token address.
370
- * @param caseSensitive - When `true`, the address is kept as-is (for chains
371
- * like Solana where addresses are case-sensitive). When `false` (default),
372
- * the address is lowercased (appropriate for EVM).
373
370
  * @returns The cache key.
374
371
  */
375
- const buildCacheKey = (chainId, address, caseSensitive = false) => {
376
- const normalizedAddress = caseSensitive ? address : address.toLowerCase();
377
- return `${chainId.toLowerCase()}:${normalizedAddress}`;
372
+ const buildCacheKey = (chainId, address) => {
373
+ return `${chainId.toLowerCase()}:${address.toLowerCase()}`;
378
374
  };
379
375
  exports.buildCacheKey = buildCacheKey;
380
376
  /**
@@ -395,27 +391,24 @@ exports.resolveChainName = resolveChainName;
395
391
  * @param cache.get - Method to retrieve cached data by key.
396
392
  * @param chainId - The chain ID.
397
393
  * @param tokens - Array of token addresses.
398
- * @param caseSensitive - When `true`, token addresses are kept as-is (for
399
- * chains like Solana where addresses are case-sensitive). When `false`
400
- * (default), addresses are lowercased (appropriate for EVM).
401
394
  * @returns Object containing cached results and tokens to fetch.
402
395
  */
403
- const splitCacheHits = (cache, chainId, tokens, caseSensitive = false) => {
396
+ const splitCacheHits = (cache, chainId, tokens) => {
404
397
  const cachedResults = {};
405
398
  const tokensToFetch = [];
406
- for (const address of tokens) {
407
- const normalizedAddress = caseSensitive ? address : address.toLowerCase();
408
- const key = (0, exports.buildCacheKey)(chainId, normalizedAddress, caseSensitive);
399
+ for (const addr of tokens) {
400
+ const normalizedAddr = addr.toLowerCase();
401
+ const key = (0, exports.buildCacheKey)(chainId, normalizedAddr);
409
402
  const hit = cache.get(key);
410
403
  if (hit) {
411
- cachedResults[normalizedAddress] = {
404
+ cachedResults[normalizedAddr] = {
412
405
  result_type: hit.result_type,
413
406
  chain: chainId,
414
- address: normalizedAddress,
407
+ address: normalizedAddr,
415
408
  };
416
409
  }
417
410
  else {
418
- tokensToFetch.push(normalizedAddress);
411
+ tokensToFetch.push(normalizedAddr);
419
412
  }
420
413
  }
421
414
  return { cachedResults, tokensToFetch };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToHex } from '@noble/hashes/utils';\nimport { sha256 } from 'ethereum-cryptography/sha256';\n\nimport { deleteFromTrie, insertToTrie, deepCopyPathTrie } from './PathTrie';\nimport type { Hotlist, PhishingListState } from './PhishingController';\nimport { ListKeys, phishingListKeyNameMap } from './PhishingController';\nimport type {\n PhishingDetectorList,\n PhishingDetectorConfiguration,\n} from './PhishingDetector';\nimport { DEFAULT_CHAIN_ID_TO_NAME } from './types';\nimport type { TokenScanCacheData, TokenScanResult } from './types';\n\nconst DEFAULT_TOLERANCE = 3;\n\n/**\n * Fetches current epoch time in seconds.\n *\n * @returns the Date.now() time in seconds instead of miliseconds. backend files rely on timestamps in seconds since epoch.\n */\nexport const fetchTimeNow = (): number => Math.round(Date.now() / 1000);\n\n/**\n * Rounds a Unix timestamp down to the nearest minute.\n *\n * @param unixTimestamp - The Unix timestamp to be rounded.\n * @returns The rounded Unix timestamp.\n */\nexport function roundToNearestMinute(unixTimestamp: number): number {\n return Math.floor(unixTimestamp / 60) * 60;\n}\n\n/**\n * Split a string into two pieces, using the first period as the delimiter.\n *\n * @param stringToSplit - The string to split.\n * @returns An array of length two containing the beginning and end of the string.\n */\nconst splitStringByPeriod = <Start extends string, End extends string>(\n stringToSplit: `${Start}.${End}`,\n): [Start, End] => {\n const periodIndex = stringToSplit.indexOf('.');\n return [\n stringToSplit.slice(0, periodIndex) as Start,\n stringToSplit.slice(periodIndex + 1) as End,\n ];\n};\n\nexport const getHostnameAndPathComponents = (\n url: string,\n): { hostname: string; pathComponents: string[] } => {\n const urlWithProtocol = url.startsWith('http') ? url : `https://${url}`;\n try {\n const { hostname, pathname } = new URL(urlWithProtocol);\n return {\n hostname: hostname.toLowerCase(),\n pathComponents: pathname\n .split('/')\n .filter(Boolean)\n .map((component) => decodeURIComponent(component)),\n };\n } catch {\n return {\n hostname: '',\n pathComponents: [],\n };\n }\n};\n\n/**\n * Determines which diffs are applicable to the listState, then applies those diffs.\n *\n * @param listState - the stalelist or the existing liststate that diffs will be applied to.\n * @param hotlistDiffs - the diffs to apply to the listState if valid.\n * @param listKey - the key associated with the input/output phishing list state.\n * @param recentlyAddedC2Domains - list of hashed C2 domains to add to the local c2 domain blocklist\n * @param recentlyRemovedC2Domains - list of hashed C2 domains to remove from the local c2 domain blocklist\n * @returns the new list state\n */\nexport const applyDiffs = (\n listState: PhishingListState,\n hotlistDiffs: Hotlist,\n listKey: ListKeys,\n recentlyAddedC2Domains: string[] = [],\n recentlyRemovedC2Domains: string[] = [],\n): PhishingListState => {\n // filter to remove diffs that were added before the lastUpdate time.\n // filter to remove diffs that aren't applicable to the specified list (by listKey).\n const diffsToApply = hotlistDiffs.filter(\n ({ timestamp, targetList }) =>\n timestamp > listState.lastUpdated &&\n splitStringByPeriod(targetList)[0] === listKey,\n );\n\n // the reason behind using latestDiffTimestamp as the lastUpdated time\n // is so that we can benefit server-side from memoization due to end client's\n // `GET /v1/diffSince/:timestamp` requests lining up with\n // our periodic updates (which create diffs at specific timestamps).\n let latestDiffTimestamp = listState.lastUpdated;\n\n const listSets = {\n allowlist: new Set(listState.allowlist),\n blocklist: new Set(listState.blocklist),\n fuzzylist: new Set(listState.fuzzylist),\n c2DomainBlocklist: new Set(listState.c2DomainBlocklist),\n };\n\n // deep copy of blocklistPaths to avoid mutating the original\n const newBlocklistPaths = deepCopyPathTrie(listState.blocklistPaths);\n\n for (const { isRemoval, targetList, url, timestamp } of diffsToApply) {\n const targetListType = splitStringByPeriod(targetList)[1];\n if (timestamp > latestDiffTimestamp) {\n latestDiffTimestamp = timestamp;\n }\n\n if (isRemoval) {\n if (targetListType === 'blocklistPaths') {\n deleteFromTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].delete(url);\n }\n continue;\n }\n\n if (targetListType === 'blocklistPaths') {\n insertToTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].add(url);\n }\n }\n\n if (listKey === ListKeys.EthPhishingDetectConfig) {\n for (const hash of recentlyAddedC2Domains) {\n listSets.c2DomainBlocklist.add(hash);\n }\n for (const hash of recentlyRemovedC2Domains) {\n listSets.c2DomainBlocklist.delete(hash);\n }\n }\n\n return {\n c2DomainBlocklist: Array.from(listSets.c2DomainBlocklist),\n allowlist: Array.from(listSets.allowlist),\n blocklist: Array.from(listSets.blocklist),\n fuzzylist: Array.from(listSets.fuzzylist),\n blocklistPaths: newBlocklistPaths,\n version: listState.version,\n name: phishingListKeyNameMap[listKey],\n tolerance: listState.tolerance,\n lastUpdated: latestDiffTimestamp,\n };\n};\n\n/**\n * Validates the configuration object for the phishing detector.\n *\n * @param config - the configuration object to validate.\n * @throws an error if the configuration is invalid.\n */\nexport function validateConfig(\n config: unknown,\n): asserts config is PhishingListState {\n if (config === null || typeof config !== 'object') {\n throw new Error('Invalid config');\n }\n\n if ('tolerance' in config && !('fuzzylist' in config)) {\n throw new Error('Fuzzylist tolerance provided without fuzzylist');\n }\n\n if (\n 'name' in config &&\n (typeof config.name !== 'string' || config.name === '')\n ) {\n throw new Error(\"Invalid config parameter: 'name'\");\n }\n\n if (\n 'version' in config &&\n (!['number', 'string'].includes(typeof config.version) ||\n config.version === '')\n ) {\n throw new Error(\"Invalid config parameter: 'version'\");\n }\n}\n\n/**\n * Converts a domain string to a list of domain parts.\n *\n * @param domain - the domain string to convert.\n * @returns the list of domain parts.\n */\nexport const domainToParts = (domain: string) => {\n return domain.split('.').reverse();\n};\n\n/**\n * Converts a list of domain strings to a list of domain parts.\n *\n * @param list - the list of domain strings to convert.\n * @returns the list of domain parts.\n */\nexport const processDomainList = (list: string[]): string[][] => {\n return list.reduce<string[][]>((acc, domain) => {\n if (typeof domain !== 'string') {\n console.warn(`Invalid domain value in list: ${JSON.stringify(domain)}`);\n return acc;\n }\n acc.push(domainToParts(domain));\n return acc;\n }, []);\n};\n\n/**\n * Gets the default phishing detector configuration.\n *\n * @param override - the optional override for the configuration.\n * @param override.allowlist - the optional allowlist to override.\n * @param override.blocklist - the optional blocklist to override.\n * @param override.fuzzylist - the optional fuzzylist to override.\n * @param override.tolerance - the optional tolerance to override.\n * @returns the default phishing detector configuration.\n */\nexport const getDefaultPhishingDetectorConfig = ({\n allowlist = [],\n blocklist = [],\n fuzzylist = [],\n tolerance = DEFAULT_TOLERANCE,\n}: {\n allowlist?: string[];\n blocklist?: string[];\n fuzzylist?: string[];\n tolerance?: number;\n}): PhishingDetectorConfiguration => {\n return {\n allowlist: processDomainList(allowlist),\n // We can assume that blocklist is already separated into hostname-only entries\n // and hostname+path entries so we do not need to separate it again.\n blocklist: processDomainList(blocklist),\n fuzzylist: processDomainList(fuzzylist),\n tolerance,\n };\n};\n\n/**\n * Processes the configurations for the phishing detector, filtering out any invalid configs.\n *\n * @param configs - The configurations to process.\n * @returns An array of processed and valid configurations.\n */\nexport const processConfigs = (\n configs: PhishingDetectorList[] = [],\n): PhishingDetectorConfiguration[] => {\n return configs\n .filter((config) => {\n try {\n validateConfig(config);\n return true;\n } catch (error) {\n console.error(error);\n return false;\n }\n })\n .map((config) => ({\n ...config,\n ...getDefaultPhishingDetectorConfig(config),\n }));\n};\n\n/**\n * Converts a list of domain parts to a domain string.\n *\n * @param domainParts - the list of domain parts.\n * @returns the domain string.\n */\nexport const domainPartsToDomain = (domainParts: string[]) => {\n return domainParts.slice().reverse().join('.');\n};\n\n/**\n * Converts a list of domain parts to a fuzzy form.\n *\n * @param domainParts - the list of domain parts.\n * @returns the fuzzy form of the domain.\n */\nexport const domainPartsToFuzzyForm = (domainParts: string[]) => {\n return domainParts.slice(1).reverse().join('.');\n};\n\n/**\n * Matches the target parts, ignoring extra subdomains on source.\n *\n * @param source - the source domain parts.\n * @param list - the list of domain parts to match against.\n * @returns the parts for the first found matching entry.\n */\nexport const matchPartsAgainstList = (source: string[], list: string[][]) => {\n return list.find((target) => {\n // target domain has more parts than source, fail\n if (target.length > source.length) {\n return false;\n }\n // source matches target or (is deeper subdomain)\n return target.every((part, index) => source[index] === part);\n });\n};\n\n/**\n * Generate the SHA-256 hash of a hostname.\n *\n * @param hostname - The hostname to hash.\n * @returns The SHA-256 hash of the hostname.\n */\nexport const sha256Hash = (hostname: string): string => {\n const hashBuffer = sha256(new TextEncoder().encode(hostname.toLowerCase()));\n return bytesToHex(hashBuffer);\n};\n\n/**\n * Extracts the hostname from a URL.\n *\n * @param url - The URL to extract the hostname from.\n * @returns The hostname extracted from the URL, or null if the URL is invalid.\n */\nexport const getHostnameFromUrl = (url: string): string | null => {\n let hostname;\n try {\n hostname = new URL(url).hostname;\n // above will not throw if 'http://.' is passed. in fact, any string with a dot will pass.\n if (!hostname || hostname.split('.').join('') === '') {\n return null;\n }\n } catch {\n return null;\n }\n return hostname;\n};\n\n/**\n * getHostnameFromWebUrl returns the hostname from a web URL.\n * It returns the hostname and a boolean indicating if the hostname is valid.\n *\n * @param url - The web URL to extract the hostname from.\n * @returns A tuple containing the extracted hostname and a boolean indicating if the hostname is valid.\n * @example\n * getHostnameFromWebUrl('https://example.com') // Returns: ['example.com', true]\n * getHostnameFromWebUrl('example.com') // Returns: ['', false]\n * getHostnameFromWebUrl('https://') // Returns: ['', false]\n * getHostnameFromWebUrl('') // Returns: ['', false]\n */\nexport const getHostnameFromWebUrl = (url: string): [string, boolean] => {\n if (\n !url.toLowerCase().startsWith('http://') &&\n !url.toLowerCase().startsWith('https://')\n ) {\n return ['', false];\n }\n\n const hostname = getHostnameFromUrl(url);\n return [hostname || '', Boolean(hostname)];\n};\n\nexport const getPathnameFromUrl = (url: string): string => {\n try {\n const { pathname } = new URL(url);\n return pathname;\n } catch {\n return '';\n }\n};\n\n/**\n * Generates all possible parent domains up to a specified limit.\n *\n * @param sourceParts - The list of domain parts in normal order (e.g., ['evil', 'domain', 'co', 'uk']).\n * @param limit - The maximum number of parent domains to generate (default is 5).\n * @returns An array of parent domains starting from the base TLD to the most specific subdomain.\n * @example\n * generateParentDomains(['evil', 'domain', 'co', 'uk'], 5)\n * // Returns: ['co.uk', 'domain.co.uk', 'evil.domain.co.uk']\n *\n * generateParentDomains(['uk'], 5)\n * // Returns: ['uk']\n *\n * generateParentDomains(['sub', 'example', 'com'], 5)\n * // Returns: ['example.com', 'sub.example.com']\n */\nexport const generateParentDomains = (\n sourceParts: string[],\n limit = 5,\n): string[] => {\n const domains: string[] = [];\n\n if (sourceParts.length === 0) {\n return domains;\n }\n\n if (sourceParts.length === 1) {\n // Single-segment hostname (e.g., 'uk')\n domains.push(sourceParts[0].toLowerCase());\n } else {\n // Start with the base domain or TLD (last two labels, e.g., 'co.uk' or 'example.com')\n const baseDomain = sourceParts.slice(-2).join('.');\n domains.push(baseDomain.toLowerCase());\n\n // Iteratively add one subdomain level at a time, up to the specified limit\n for (\n let i = sourceParts.length - 3;\n i >= 0 && domains.length < limit;\n i--\n ) {\n const domain = sourceParts.slice(i).join('.');\n domains.push(domain.toLowerCase());\n }\n }\n\n return domains;\n};\n\n/**\n * Builds a cache key for a token scan result.\n *\n * @param chainId - The chain ID.\n * @param address - The token address.\n * @param caseSensitive - When `true`, the address is kept as-is (for chains\n * like Solana where addresses are case-sensitive). When `false` (default),\n * the address is lowercased (appropriate for EVM).\n * @returns The cache key.\n */\nexport const buildCacheKey = (\n chainId: string,\n address: string,\n caseSensitive = false,\n) => {\n const normalizedAddress = caseSensitive ? address : address.toLowerCase();\n return `${chainId.toLowerCase()}:${normalizedAddress}`;\n};\n\n/**\n * Resolves the chain name from a chain ID.\n *\n * @param chainId - The chain ID.\n * @param mapping - The mapping of chain IDs to chain names.\n * @returns The chain name.\n */\nexport const resolveChainName = (\n chainId: string,\n mapping = DEFAULT_CHAIN_ID_TO_NAME,\n): string | null => {\n return mapping[chainId.toLowerCase() as keyof typeof mapping] ?? null;\n};\n\n/**\n * Split tokens into cached results and tokens that need to be fetched.\n *\n * @param cache - Cache-like object with get method.\n * @param cache.get - Method to retrieve cached data by key.\n * @param chainId - The chain ID.\n * @param tokens - Array of token addresses.\n * @param caseSensitive - When `true`, token addresses are kept as-is (for\n * chains like Solana where addresses are case-sensitive). When `false`\n * (default), addresses are lowercased (appropriate for EVM).\n * @returns Object containing cached results and tokens to fetch.\n */\nexport const splitCacheHits = (\n cache: { get: (key: string) => TokenScanCacheData | undefined },\n chainId: string,\n tokens: string[],\n caseSensitive = false,\n): {\n cachedResults: Record<string, TokenScanResult>;\n tokensToFetch: string[];\n} => {\n const cachedResults: Record<string, TokenScanResult> = {};\n const tokensToFetch: string[] = [];\n\n for (const address of tokens) {\n const normalizedAddress = caseSensitive ? address : address.toLowerCase();\n const key = buildCacheKey(chainId, normalizedAddress, caseSensitive);\n const hit = cache.get(key);\n if (hit) {\n cachedResults[normalizedAddress] = {\n result_type: hit.result_type,\n chain: chainId,\n address: normalizedAddress,\n };\n } else {\n tokensToFetch.push(normalizedAddress);\n }\n }\n\n return { cachedResults, tokensToFetch };\n};\n"]}
1
+ {"version":3,"file":"utils.cjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToHex } from '@noble/hashes/utils';\nimport { sha256 } from 'ethereum-cryptography/sha256';\n\nimport { deleteFromTrie, insertToTrie, deepCopyPathTrie } from './PathTrie';\nimport type { Hotlist, PhishingListState } from './PhishingController';\nimport { ListKeys, phishingListKeyNameMap } from './PhishingController';\nimport type {\n PhishingDetectorList,\n PhishingDetectorConfiguration,\n} from './PhishingDetector';\nimport { DEFAULT_CHAIN_ID_TO_NAME } from './types';\nimport type { TokenScanCacheData, TokenScanResult } from './types';\n\nconst DEFAULT_TOLERANCE = 3;\n\n/**\n * Fetches current epoch time in seconds.\n *\n * @returns the Date.now() time in seconds instead of miliseconds. backend files rely on timestamps in seconds since epoch.\n */\nexport const fetchTimeNow = (): number => Math.round(Date.now() / 1000);\n\n/**\n * Rounds a Unix timestamp down to the nearest minute.\n *\n * @param unixTimestamp - The Unix timestamp to be rounded.\n * @returns The rounded Unix timestamp.\n */\nexport function roundToNearestMinute(unixTimestamp: number): number {\n return Math.floor(unixTimestamp / 60) * 60;\n}\n\n/**\n * Split a string into two pieces, using the first period as the delimiter.\n *\n * @param stringToSplit - The string to split.\n * @returns An array of length two containing the beginning and end of the string.\n */\nconst splitStringByPeriod = <Start extends string, End extends string>(\n stringToSplit: `${Start}.${End}`,\n): [Start, End] => {\n const periodIndex = stringToSplit.indexOf('.');\n return [\n stringToSplit.slice(0, periodIndex) as Start,\n stringToSplit.slice(periodIndex + 1) as End,\n ];\n};\n\nexport const getHostnameAndPathComponents = (\n url: string,\n): { hostname: string; pathComponents: string[] } => {\n const urlWithProtocol = url.startsWith('http') ? url : `https://${url}`;\n try {\n const { hostname, pathname } = new URL(urlWithProtocol);\n return {\n hostname: hostname.toLowerCase(),\n pathComponents: pathname\n .split('/')\n .filter(Boolean)\n .map((component) => decodeURIComponent(component)),\n };\n } catch {\n return {\n hostname: '',\n pathComponents: [],\n };\n }\n};\n\n/**\n * Determines which diffs are applicable to the listState, then applies those diffs.\n *\n * @param listState - the stalelist or the existing liststate that diffs will be applied to.\n * @param hotlistDiffs - the diffs to apply to the listState if valid.\n * @param listKey - the key associated with the input/output phishing list state.\n * @param recentlyAddedC2Domains - list of hashed C2 domains to add to the local c2 domain blocklist\n * @param recentlyRemovedC2Domains - list of hashed C2 domains to remove from the local c2 domain blocklist\n * @returns the new list state\n */\nexport const applyDiffs = (\n listState: PhishingListState,\n hotlistDiffs: Hotlist,\n listKey: ListKeys,\n recentlyAddedC2Domains: string[] = [],\n recentlyRemovedC2Domains: string[] = [],\n): PhishingListState => {\n // filter to remove diffs that were added before the lastUpdate time.\n // filter to remove diffs that aren't applicable to the specified list (by listKey).\n const diffsToApply = hotlistDiffs.filter(\n ({ timestamp, targetList }) =>\n timestamp > listState.lastUpdated &&\n splitStringByPeriod(targetList)[0] === listKey,\n );\n\n // the reason behind using latestDiffTimestamp as the lastUpdated time\n // is so that we can benefit server-side from memoization due to end client's\n // `GET /v1/diffSince/:timestamp` requests lining up with\n // our periodic updates (which create diffs at specific timestamps).\n let latestDiffTimestamp = listState.lastUpdated;\n\n const listSets = {\n allowlist: new Set(listState.allowlist),\n blocklist: new Set(listState.blocklist),\n fuzzylist: new Set(listState.fuzzylist),\n c2DomainBlocklist: new Set(listState.c2DomainBlocklist),\n };\n\n // deep copy of blocklistPaths to avoid mutating the original\n const newBlocklistPaths = deepCopyPathTrie(listState.blocklistPaths);\n\n for (const { isRemoval, targetList, url, timestamp } of diffsToApply) {\n const targetListType = splitStringByPeriod(targetList)[1];\n if (timestamp > latestDiffTimestamp) {\n latestDiffTimestamp = timestamp;\n }\n\n if (isRemoval) {\n if (targetListType === 'blocklistPaths') {\n deleteFromTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].delete(url);\n }\n continue;\n }\n\n if (targetListType === 'blocklistPaths') {\n insertToTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].add(url);\n }\n }\n\n if (listKey === ListKeys.EthPhishingDetectConfig) {\n for (const hash of recentlyAddedC2Domains) {\n listSets.c2DomainBlocklist.add(hash);\n }\n for (const hash of recentlyRemovedC2Domains) {\n listSets.c2DomainBlocklist.delete(hash);\n }\n }\n\n return {\n c2DomainBlocklist: Array.from(listSets.c2DomainBlocklist),\n allowlist: Array.from(listSets.allowlist),\n blocklist: Array.from(listSets.blocklist),\n fuzzylist: Array.from(listSets.fuzzylist),\n blocklistPaths: newBlocklistPaths,\n version: listState.version,\n name: phishingListKeyNameMap[listKey],\n tolerance: listState.tolerance,\n lastUpdated: latestDiffTimestamp,\n };\n};\n\n/**\n * Validates the configuration object for the phishing detector.\n *\n * @param config - the configuration object to validate.\n * @throws an error if the configuration is invalid.\n */\nexport function validateConfig(\n config: unknown,\n): asserts config is PhishingListState {\n if (config === null || typeof config !== 'object') {\n throw new Error('Invalid config');\n }\n\n if ('tolerance' in config && !('fuzzylist' in config)) {\n throw new Error('Fuzzylist tolerance provided without fuzzylist');\n }\n\n if (\n 'name' in config &&\n (typeof config.name !== 'string' || config.name === '')\n ) {\n throw new Error(\"Invalid config parameter: 'name'\");\n }\n\n if (\n 'version' in config &&\n (!['number', 'string'].includes(typeof config.version) ||\n config.version === '')\n ) {\n throw new Error(\"Invalid config parameter: 'version'\");\n }\n}\n\n/**\n * Converts a domain string to a list of domain parts.\n *\n * @param domain - the domain string to convert.\n * @returns the list of domain parts.\n */\nexport const domainToParts = (domain: string) => {\n return domain.split('.').reverse();\n};\n\n/**\n * Converts a list of domain strings to a list of domain parts.\n *\n * @param list - the list of domain strings to convert.\n * @returns the list of domain parts.\n */\nexport const processDomainList = (list: string[]): string[][] => {\n return list.reduce<string[][]>((acc, domain) => {\n if (typeof domain !== 'string') {\n console.warn(`Invalid domain value in list: ${JSON.stringify(domain)}`);\n return acc;\n }\n acc.push(domainToParts(domain));\n return acc;\n }, []);\n};\n\n/**\n * Gets the default phishing detector configuration.\n *\n * @param override - the optional override for the configuration.\n * @param override.allowlist - the optional allowlist to override.\n * @param override.blocklist - the optional blocklist to override.\n * @param override.fuzzylist - the optional fuzzylist to override.\n * @param override.tolerance - the optional tolerance to override.\n * @returns the default phishing detector configuration.\n */\nexport const getDefaultPhishingDetectorConfig = ({\n allowlist = [],\n blocklist = [],\n fuzzylist = [],\n tolerance = DEFAULT_TOLERANCE,\n}: {\n allowlist?: string[];\n blocklist?: string[];\n fuzzylist?: string[];\n tolerance?: number;\n}): PhishingDetectorConfiguration => {\n return {\n allowlist: processDomainList(allowlist),\n // We can assume that blocklist is already separated into hostname-only entries\n // and hostname+path entries so we do not need to separate it again.\n blocklist: processDomainList(blocklist),\n fuzzylist: processDomainList(fuzzylist),\n tolerance,\n };\n};\n\n/**\n * Processes the configurations for the phishing detector, filtering out any invalid configs.\n *\n * @param configs - The configurations to process.\n * @returns An array of processed and valid configurations.\n */\nexport const processConfigs = (\n configs: PhishingDetectorList[] = [],\n): PhishingDetectorConfiguration[] => {\n return configs\n .filter((config) => {\n try {\n validateConfig(config);\n return true;\n } catch (error) {\n console.error(error);\n return false;\n }\n })\n .map((config) => ({\n ...config,\n ...getDefaultPhishingDetectorConfig(config),\n }));\n};\n\n/**\n * Converts a list of domain parts to a domain string.\n *\n * @param domainParts - the list of domain parts.\n * @returns the domain string.\n */\nexport const domainPartsToDomain = (domainParts: string[]) => {\n return domainParts.slice().reverse().join('.');\n};\n\n/**\n * Converts a list of domain parts to a fuzzy form.\n *\n * @param domainParts - the list of domain parts.\n * @returns the fuzzy form of the domain.\n */\nexport const domainPartsToFuzzyForm = (domainParts: string[]) => {\n return domainParts.slice(1).reverse().join('.');\n};\n\n/**\n * Matches the target parts, ignoring extra subdomains on source.\n *\n * @param source - the source domain parts.\n * @param list - the list of domain parts to match against.\n * @returns the parts for the first found matching entry.\n */\nexport const matchPartsAgainstList = (source: string[], list: string[][]) => {\n return list.find((target) => {\n // target domain has more parts than source, fail\n if (target.length > source.length) {\n return false;\n }\n // source matches target or (is deeper subdomain)\n return target.every((part, index) => source[index] === part);\n });\n};\n\n/**\n * Generate the SHA-256 hash of a hostname.\n *\n * @param hostname - The hostname to hash.\n * @returns The SHA-256 hash of the hostname.\n */\nexport const sha256Hash = (hostname: string): string => {\n const hashBuffer = sha256(new TextEncoder().encode(hostname.toLowerCase()));\n return bytesToHex(hashBuffer);\n};\n\n/**\n * Extracts the hostname from a URL.\n *\n * @param url - The URL to extract the hostname from.\n * @returns The hostname extracted from the URL, or null if the URL is invalid.\n */\nexport const getHostnameFromUrl = (url: string): string | null => {\n let hostname;\n try {\n hostname = new URL(url).hostname;\n // above will not throw if 'http://.' is passed. in fact, any string with a dot will pass.\n if (!hostname || hostname.split('.').join('') === '') {\n return null;\n }\n } catch {\n return null;\n }\n return hostname;\n};\n\n/**\n * getHostnameFromWebUrl returns the hostname from a web URL.\n * It returns the hostname and a boolean indicating if the hostname is valid.\n *\n * @param url - The web URL to extract the hostname from.\n * @returns A tuple containing the extracted hostname and a boolean indicating if the hostname is valid.\n * @example\n * getHostnameFromWebUrl('https://example.com') // Returns: ['example.com', true]\n * getHostnameFromWebUrl('example.com') // Returns: ['', false]\n * getHostnameFromWebUrl('https://') // Returns: ['', false]\n * getHostnameFromWebUrl('') // Returns: ['', false]\n */\nexport const getHostnameFromWebUrl = (url: string): [string, boolean] => {\n if (\n !url.toLowerCase().startsWith('http://') &&\n !url.toLowerCase().startsWith('https://')\n ) {\n return ['', false];\n }\n\n const hostname = getHostnameFromUrl(url);\n return [hostname || '', Boolean(hostname)];\n};\n\nexport const getPathnameFromUrl = (url: string): string => {\n try {\n const { pathname } = new URL(url);\n return pathname;\n } catch {\n return '';\n }\n};\n\n/**\n * Generates all possible parent domains up to a specified limit.\n *\n * @param sourceParts - The list of domain parts in normal order (e.g., ['evil', 'domain', 'co', 'uk']).\n * @param limit - The maximum number of parent domains to generate (default is 5).\n * @returns An array of parent domains starting from the base TLD to the most specific subdomain.\n * @example\n * generateParentDomains(['evil', 'domain', 'co', 'uk'], 5)\n * // Returns: ['co.uk', 'domain.co.uk', 'evil.domain.co.uk']\n *\n * generateParentDomains(['uk'], 5)\n * // Returns: ['uk']\n *\n * generateParentDomains(['sub', 'example', 'com'], 5)\n * // Returns: ['example.com', 'sub.example.com']\n */\nexport const generateParentDomains = (\n sourceParts: string[],\n limit = 5,\n): string[] => {\n const domains: string[] = [];\n\n if (sourceParts.length === 0) {\n return domains;\n }\n\n if (sourceParts.length === 1) {\n // Single-segment hostname (e.g., 'uk')\n domains.push(sourceParts[0].toLowerCase());\n } else {\n // Start with the base domain or TLD (last two labels, e.g., 'co.uk' or 'example.com')\n const baseDomain = sourceParts.slice(-2).join('.');\n domains.push(baseDomain.toLowerCase());\n\n // Iteratively add one subdomain level at a time, up to the specified limit\n for (\n let i = sourceParts.length - 3;\n i >= 0 && domains.length < limit;\n i--\n ) {\n const domain = sourceParts.slice(i).join('.');\n domains.push(domain.toLowerCase());\n }\n }\n\n return domains;\n};\n\n/**\n * Builds a cache key for a token scan result.\n *\n * @param chainId - The chain ID.\n * @param address - The token address.\n * @returns The cache key.\n */\nexport const buildCacheKey = (chainId: string, address: string) => {\n return `${chainId.toLowerCase()}:${address.toLowerCase()}`;\n};\n\n/**\n * Resolves the chain name from a chain ID.\n *\n * @param chainId - The chain ID.\n * @param mapping - The mapping of chain IDs to chain names.\n * @returns The chain name.\n */\nexport const resolveChainName = (\n chainId: string,\n mapping = DEFAULT_CHAIN_ID_TO_NAME,\n): string | null => {\n return mapping[chainId.toLowerCase() as keyof typeof mapping] ?? null;\n};\n\n/**\n * Split tokens into cached results and tokens that need to be fetched.\n *\n * @param cache - Cache-like object with get method.\n * @param cache.get - Method to retrieve cached data by key.\n * @param chainId - The chain ID.\n * @param tokens - Array of token addresses.\n * @returns Object containing cached results and tokens to fetch.\n */\nexport const splitCacheHits = (\n cache: { get: (key: string) => TokenScanCacheData | undefined },\n chainId: string,\n tokens: string[],\n): {\n cachedResults: Record<string, TokenScanResult>;\n tokensToFetch: string[];\n} => {\n const cachedResults: Record<string, TokenScanResult> = {};\n const tokensToFetch: string[] = [];\n\n for (const addr of tokens) {\n const normalizedAddr = addr.toLowerCase();\n const key = buildCacheKey(chainId, normalizedAddr);\n const hit = cache.get(key);\n if (hit) {\n cachedResults[normalizedAddr] = {\n result_type: hit.result_type,\n chain: chainId,\n address: normalizedAddr,\n };\n } else {\n tokensToFetch.push(normalizedAddr);\n }\n }\n\n return { cachedResults, tokensToFetch };\n};\n"]}
package/dist/utils.d.cts CHANGED
@@ -146,12 +146,9 @@ export declare const generateParentDomains: (sourceParts: string[], limit?: numb
146
146
  *
147
147
  * @param chainId - The chain ID.
148
148
  * @param address - The token address.
149
- * @param caseSensitive - When `true`, the address is kept as-is (for chains
150
- * like Solana where addresses are case-sensitive). When `false` (default),
151
- * the address is lowercased (appropriate for EVM).
152
149
  * @returns The cache key.
153
150
  */
154
- export declare const buildCacheKey: (chainId: string, address: string, caseSensitive?: boolean) => string;
151
+ export declare const buildCacheKey: (chainId: string, address: string) => string;
155
152
  /**
156
153
  * Resolves the chain name from a chain ID.
157
154
  *
@@ -198,7 +195,6 @@ export declare const resolveChainName: (chainId: string, mapping?: {
198
195
  readonly '0x2eb': "flow-evm";
199
196
  readonly '0x8f': "monad";
200
197
  readonly '0x3e7': "hyperevm";
201
- readonly solana: "solana";
202
198
  }) => string | null;
203
199
  /**
204
200
  * Split tokens into cached results and tokens that need to be fetched.
@@ -207,14 +203,11 @@ export declare const resolveChainName: (chainId: string, mapping?: {
207
203
  * @param cache.get - Method to retrieve cached data by key.
208
204
  * @param chainId - The chain ID.
209
205
  * @param tokens - Array of token addresses.
210
- * @param caseSensitive - When `true`, token addresses are kept as-is (for
211
- * chains like Solana where addresses are case-sensitive). When `false`
212
- * (default), addresses are lowercased (appropriate for EVM).
213
206
  * @returns Object containing cached results and tokens to fetch.
214
207
  */
215
208
  export declare const splitCacheHits: (cache: {
216
209
  get: (key: string) => TokenScanCacheData | undefined;
217
- }, chainId: string, tokens: string[], caseSensitive?: boolean) => {
210
+ }, chainId: string, tokens: string[]) => {
218
211
  cachedResults: Record<string, TokenScanResult>;
219
212
  tokensToFetch: string[];
220
213
  };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,iCAA6B;AACvE,OAAO,EAAE,QAAQ,EAA0B,iCAA6B;AACxE,OAAO,KAAK,EACV,oBAAoB,EACpB,6BAA6B,EAC9B,+BAA2B;AAE5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAgB;AAInE;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,MAAuC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAkBD,eAAO,MAAM,4BAA4B,QAClC,MAAM,KACV;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAiB9C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,cACV,iBAAiB,kCAEnB,QAAQ,2BACO,MAAM,EAAE,6BACN,MAAM,EAAE,KACjC,iBAmEF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAuBrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAY,MAAM,aAE3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,MAAM,EAAE,EAS1D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC;;;;;MAUzC,6BASH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,aAChB,oBAAoB,EAAE,KAC9B,6BAA6B,EAe/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,gBAAiB,MAAM,EAAE,WAExD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,EAAE,WAE3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,EAAE,QAAQ,MAAM,EAAE,EAAE,yBASvE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,MAG7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAAM,GAAG,IAYzD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,KAAG,CAAC,MAAM,EAAE,OAAO,CAUnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAOhD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,gBACnB,MAAM,EAAE,qBAEpB,MAAM,EA2BR,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,YACf,MAAM,WACN,MAAM,oCAKhB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAClB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAEd,MAAM,GAAG,IAEX,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;eACL,MAAM,KAAK,kBAAkB,GAAG,SAAS;YACpD,MAAM,UACP,MAAM,EAAE;mBAGD,OAAO,MAAM,EAAE,eAAe,CAAC;mBAC/B,MAAM,EAAE;CAqBxB,CAAC"}
1
+ {"version":3,"file":"utils.d.cts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,iCAA6B;AACvE,OAAO,EAAE,QAAQ,EAA0B,iCAA6B;AACxE,OAAO,KAAK,EACV,oBAAoB,EACpB,6BAA6B,EAC9B,+BAA2B;AAE5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAgB;AAInE;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,MAAuC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAkBD,eAAO,MAAM,4BAA4B,QAClC,MAAM,KACV;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAiB9C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,cACV,iBAAiB,kCAEnB,QAAQ,2BACO,MAAM,EAAE,6BACN,MAAM,EAAE,KACjC,iBAmEF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAuBrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAY,MAAM,aAE3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,MAAM,EAAE,EAS1D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC;;;;;MAUzC,6BASH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,aAChB,oBAAoB,EAAE,KAC9B,6BAA6B,EAe/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,gBAAiB,MAAM,EAAE,WAExD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,EAAE,WAE3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,EAAE,QAAQ,MAAM,EAAE,EAAE,yBASvE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,MAG7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAAM,GAAG,IAYzD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,KAAG,CAAC,MAAM,EAAE,OAAO,CAUnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAOhD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,gBACnB,MAAM,EAAE,qBAEpB,MAAM,EA2BR,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,WAAW,MAAM,WAE7D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAClB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAEd,MAAM,GAAG,IAEX,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;eACL,MAAM,KAAK,kBAAkB,GAAG,SAAS;YACpD,MAAM,UACP,MAAM,EAAE;mBAED,OAAO,MAAM,EAAE,eAAe,CAAC;mBAC/B,MAAM,EAAE;CAqBxB,CAAC"}
package/dist/utils.d.mts CHANGED
@@ -146,12 +146,9 @@ export declare const generateParentDomains: (sourceParts: string[], limit?: numb
146
146
  *
147
147
  * @param chainId - The chain ID.
148
148
  * @param address - The token address.
149
- * @param caseSensitive - When `true`, the address is kept as-is (for chains
150
- * like Solana where addresses are case-sensitive). When `false` (default),
151
- * the address is lowercased (appropriate for EVM).
152
149
  * @returns The cache key.
153
150
  */
154
- export declare const buildCacheKey: (chainId: string, address: string, caseSensitive?: boolean) => string;
151
+ export declare const buildCacheKey: (chainId: string, address: string) => string;
155
152
  /**
156
153
  * Resolves the chain name from a chain ID.
157
154
  *
@@ -198,7 +195,6 @@ export declare const resolveChainName: (chainId: string, mapping?: {
198
195
  readonly '0x2eb': "flow-evm";
199
196
  readonly '0x8f': "monad";
200
197
  readonly '0x3e7': "hyperevm";
201
- readonly solana: "solana";
202
198
  }) => string | null;
203
199
  /**
204
200
  * Split tokens into cached results and tokens that need to be fetched.
@@ -207,14 +203,11 @@ export declare const resolveChainName: (chainId: string, mapping?: {
207
203
  * @param cache.get - Method to retrieve cached data by key.
208
204
  * @param chainId - The chain ID.
209
205
  * @param tokens - Array of token addresses.
210
- * @param caseSensitive - When `true`, token addresses are kept as-is (for
211
- * chains like Solana where addresses are case-sensitive). When `false`
212
- * (default), addresses are lowercased (appropriate for EVM).
213
206
  * @returns Object containing cached results and tokens to fetch.
214
207
  */
215
208
  export declare const splitCacheHits: (cache: {
216
209
  get: (key: string) => TokenScanCacheData | undefined;
217
- }, chainId: string, tokens: string[], caseSensitive?: boolean) => {
210
+ }, chainId: string, tokens: string[]) => {
218
211
  cachedResults: Record<string, TokenScanResult>;
219
212
  tokensToFetch: string[];
220
213
  };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,iCAA6B;AACvE,OAAO,EAAE,QAAQ,EAA0B,iCAA6B;AACxE,OAAO,KAAK,EACV,oBAAoB,EACpB,6BAA6B,EAC9B,+BAA2B;AAE5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAgB;AAInE;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,MAAuC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAkBD,eAAO,MAAM,4BAA4B,QAClC,MAAM,KACV;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAiB9C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,cACV,iBAAiB,kCAEnB,QAAQ,2BACO,MAAM,EAAE,6BACN,MAAM,EAAE,KACjC,iBAmEF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAuBrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAY,MAAM,aAE3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,MAAM,EAAE,EAS1D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC;;;;;MAUzC,6BASH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,aAChB,oBAAoB,EAAE,KAC9B,6BAA6B,EAe/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,gBAAiB,MAAM,EAAE,WAExD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,EAAE,WAE3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,EAAE,QAAQ,MAAM,EAAE,EAAE,yBASvE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,MAG7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAAM,GAAG,IAYzD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,KAAG,CAAC,MAAM,EAAE,OAAO,CAUnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAOhD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,gBACnB,MAAM,EAAE,qBAEpB,MAAM,EA2BR,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,aAAa,YACf,MAAM,WACN,MAAM,oCAKhB,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAClB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAEd,MAAM,GAAG,IAEX,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc;eACL,MAAM,KAAK,kBAAkB,GAAG,SAAS;YACpD,MAAM,UACP,MAAM,EAAE;mBAGD,OAAO,MAAM,EAAE,eAAe,CAAC;mBAC/B,MAAM,EAAE;CAqBxB,CAAC"}
1
+ {"version":3,"file":"utils.d.mts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,iBAAiB,EAAE,iCAA6B;AACvE,OAAO,EAAE,QAAQ,EAA0B,iCAA6B;AACxE,OAAO,KAAK,EACV,oBAAoB,EACpB,6BAA6B,EAC9B,+BAA2B;AAE5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,oBAAgB;AAInE;;;;GAIG;AACH,eAAO,MAAM,YAAY,QAAO,MAAuC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,CAElE;AAkBD,eAAO,MAAM,4BAA4B,QAClC,MAAM,KACV;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAiB9C,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,UAAU,cACV,iBAAiB,kCAEnB,QAAQ,2BACO,MAAM,EAAE,6BACN,MAAM,EAAE,KACjC,iBAmEF,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,OAAO,GACd,OAAO,CAAC,MAAM,IAAI,iBAAiB,CAuBrC;AAED;;;;;GAKG;AACH,eAAO,MAAM,aAAa,WAAY,MAAM,aAE3C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SAAU,MAAM,EAAE,KAAG,MAAM,EAAE,EAS1D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gCAAgC;;;;;MAUzC,6BASH,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,aAChB,oBAAoB,EAAE,KAC9B,6BAA6B,EAe/B,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,gBAAiB,MAAM,EAAE,WAExD,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,gBAAiB,MAAM,EAAE,WAE3D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,qBAAqB,WAAY,MAAM,EAAE,QAAQ,MAAM,EAAE,EAAE,yBASvE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,MAG7C,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAAM,GAAG,IAYzD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,qBAAqB,QAAS,MAAM,KAAG,CAAC,MAAM,EAAE,OAAO,CAUnE,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAAS,MAAM,KAAG,MAOhD,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,qBAAqB,gBACnB,MAAM,EAAE,qBAEpB,MAAM,EA2BR,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,YAAa,MAAM,WAAW,MAAM,WAE7D,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,YAClB,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAEd,MAAM,GAAG,IAEX,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc;eACL,MAAM,KAAK,kBAAkB,GAAG,SAAS;YACpD,MAAM,UACP,MAAM,EAAE;mBAED,OAAO,MAAM,EAAE,eAAe,CAAC;mBAC/B,MAAM,EAAE;CAqBxB,CAAC"}
package/dist/utils.mjs CHANGED
@@ -347,14 +347,10 @@ export const generateParentDomains = (sourceParts, limit = 5) => {
347
347
  *
348
348
  * @param chainId - The chain ID.
349
349
  * @param address - The token address.
350
- * @param caseSensitive - When `true`, the address is kept as-is (for chains
351
- * like Solana where addresses are case-sensitive). When `false` (default),
352
- * the address is lowercased (appropriate for EVM).
353
350
  * @returns The cache key.
354
351
  */
355
- export const buildCacheKey = (chainId, address, caseSensitive = false) => {
356
- const normalizedAddress = caseSensitive ? address : address.toLowerCase();
357
- return `${chainId.toLowerCase()}:${normalizedAddress}`;
352
+ export const buildCacheKey = (chainId, address) => {
353
+ return `${chainId.toLowerCase()}:${address.toLowerCase()}`;
358
354
  };
359
355
  /**
360
356
  * Resolves the chain name from a chain ID.
@@ -373,27 +369,24 @@ export const resolveChainName = (chainId, mapping = DEFAULT_CHAIN_ID_TO_NAME) =>
373
369
  * @param cache.get - Method to retrieve cached data by key.
374
370
  * @param chainId - The chain ID.
375
371
  * @param tokens - Array of token addresses.
376
- * @param caseSensitive - When `true`, token addresses are kept as-is (for
377
- * chains like Solana where addresses are case-sensitive). When `false`
378
- * (default), addresses are lowercased (appropriate for EVM).
379
372
  * @returns Object containing cached results and tokens to fetch.
380
373
  */
381
- export const splitCacheHits = (cache, chainId, tokens, caseSensitive = false) => {
374
+ export const splitCacheHits = (cache, chainId, tokens) => {
382
375
  const cachedResults = {};
383
376
  const tokensToFetch = [];
384
- for (const address of tokens) {
385
- const normalizedAddress = caseSensitive ? address : address.toLowerCase();
386
- const key = buildCacheKey(chainId, normalizedAddress, caseSensitive);
377
+ for (const addr of tokens) {
378
+ const normalizedAddr = addr.toLowerCase();
379
+ const key = buildCacheKey(chainId, normalizedAddr);
387
380
  const hit = cache.get(key);
388
381
  if (hit) {
389
- cachedResults[normalizedAddress] = {
382
+ cachedResults[normalizedAddr] = {
390
383
  result_type: hit.result_type,
391
384
  chain: chainId,
392
- address: normalizedAddress,
385
+ address: normalizedAddr,
393
386
  };
394
387
  }
395
388
  else {
396
- tokensToFetch.push(normalizedAddress);
389
+ tokensToFetch.push(normalizedAddr);
397
390
  }
398
391
  }
399
392
  return { cachedResults, tokensToFetch };
@@ -1 +1 @@
1
- {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToHex } from '@noble/hashes/utils';\nimport { sha256 } from 'ethereum-cryptography/sha256';\n\nimport { deleteFromTrie, insertToTrie, deepCopyPathTrie } from './PathTrie';\nimport type { Hotlist, PhishingListState } from './PhishingController';\nimport { ListKeys, phishingListKeyNameMap } from './PhishingController';\nimport type {\n PhishingDetectorList,\n PhishingDetectorConfiguration,\n} from './PhishingDetector';\nimport { DEFAULT_CHAIN_ID_TO_NAME } from './types';\nimport type { TokenScanCacheData, TokenScanResult } from './types';\n\nconst DEFAULT_TOLERANCE = 3;\n\n/**\n * Fetches current epoch time in seconds.\n *\n * @returns the Date.now() time in seconds instead of miliseconds. backend files rely on timestamps in seconds since epoch.\n */\nexport const fetchTimeNow = (): number => Math.round(Date.now() / 1000);\n\n/**\n * Rounds a Unix timestamp down to the nearest minute.\n *\n * @param unixTimestamp - The Unix timestamp to be rounded.\n * @returns The rounded Unix timestamp.\n */\nexport function roundToNearestMinute(unixTimestamp: number): number {\n return Math.floor(unixTimestamp / 60) * 60;\n}\n\n/**\n * Split a string into two pieces, using the first period as the delimiter.\n *\n * @param stringToSplit - The string to split.\n * @returns An array of length two containing the beginning and end of the string.\n */\nconst splitStringByPeriod = <Start extends string, End extends string>(\n stringToSplit: `${Start}.${End}`,\n): [Start, End] => {\n const periodIndex = stringToSplit.indexOf('.');\n return [\n stringToSplit.slice(0, periodIndex) as Start,\n stringToSplit.slice(periodIndex + 1) as End,\n ];\n};\n\nexport const getHostnameAndPathComponents = (\n url: string,\n): { hostname: string; pathComponents: string[] } => {\n const urlWithProtocol = url.startsWith('http') ? url : `https://${url}`;\n try {\n const { hostname, pathname } = new URL(urlWithProtocol);\n return {\n hostname: hostname.toLowerCase(),\n pathComponents: pathname\n .split('/')\n .filter(Boolean)\n .map((component) => decodeURIComponent(component)),\n };\n } catch {\n return {\n hostname: '',\n pathComponents: [],\n };\n }\n};\n\n/**\n * Determines which diffs are applicable to the listState, then applies those diffs.\n *\n * @param listState - the stalelist or the existing liststate that diffs will be applied to.\n * @param hotlistDiffs - the diffs to apply to the listState if valid.\n * @param listKey - the key associated with the input/output phishing list state.\n * @param recentlyAddedC2Domains - list of hashed C2 domains to add to the local c2 domain blocklist\n * @param recentlyRemovedC2Domains - list of hashed C2 domains to remove from the local c2 domain blocklist\n * @returns the new list state\n */\nexport const applyDiffs = (\n listState: PhishingListState,\n hotlistDiffs: Hotlist,\n listKey: ListKeys,\n recentlyAddedC2Domains: string[] = [],\n recentlyRemovedC2Domains: string[] = [],\n): PhishingListState => {\n // filter to remove diffs that were added before the lastUpdate time.\n // filter to remove diffs that aren't applicable to the specified list (by listKey).\n const diffsToApply = hotlistDiffs.filter(\n ({ timestamp, targetList }) =>\n timestamp > listState.lastUpdated &&\n splitStringByPeriod(targetList)[0] === listKey,\n );\n\n // the reason behind using latestDiffTimestamp as the lastUpdated time\n // is so that we can benefit server-side from memoization due to end client's\n // `GET /v1/diffSince/:timestamp` requests lining up with\n // our periodic updates (which create diffs at specific timestamps).\n let latestDiffTimestamp = listState.lastUpdated;\n\n const listSets = {\n allowlist: new Set(listState.allowlist),\n blocklist: new Set(listState.blocklist),\n fuzzylist: new Set(listState.fuzzylist),\n c2DomainBlocklist: new Set(listState.c2DomainBlocklist),\n };\n\n // deep copy of blocklistPaths to avoid mutating the original\n const newBlocklistPaths = deepCopyPathTrie(listState.blocklistPaths);\n\n for (const { isRemoval, targetList, url, timestamp } of diffsToApply) {\n const targetListType = splitStringByPeriod(targetList)[1];\n if (timestamp > latestDiffTimestamp) {\n latestDiffTimestamp = timestamp;\n }\n\n if (isRemoval) {\n if (targetListType === 'blocklistPaths') {\n deleteFromTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].delete(url);\n }\n continue;\n }\n\n if (targetListType === 'blocklistPaths') {\n insertToTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].add(url);\n }\n }\n\n if (listKey === ListKeys.EthPhishingDetectConfig) {\n for (const hash of recentlyAddedC2Domains) {\n listSets.c2DomainBlocklist.add(hash);\n }\n for (const hash of recentlyRemovedC2Domains) {\n listSets.c2DomainBlocklist.delete(hash);\n }\n }\n\n return {\n c2DomainBlocklist: Array.from(listSets.c2DomainBlocklist),\n allowlist: Array.from(listSets.allowlist),\n blocklist: Array.from(listSets.blocklist),\n fuzzylist: Array.from(listSets.fuzzylist),\n blocklistPaths: newBlocklistPaths,\n version: listState.version,\n name: phishingListKeyNameMap[listKey],\n tolerance: listState.tolerance,\n lastUpdated: latestDiffTimestamp,\n };\n};\n\n/**\n * Validates the configuration object for the phishing detector.\n *\n * @param config - the configuration object to validate.\n * @throws an error if the configuration is invalid.\n */\nexport function validateConfig(\n config: unknown,\n): asserts config is PhishingListState {\n if (config === null || typeof config !== 'object') {\n throw new Error('Invalid config');\n }\n\n if ('tolerance' in config && !('fuzzylist' in config)) {\n throw new Error('Fuzzylist tolerance provided without fuzzylist');\n }\n\n if (\n 'name' in config &&\n (typeof config.name !== 'string' || config.name === '')\n ) {\n throw new Error(\"Invalid config parameter: 'name'\");\n }\n\n if (\n 'version' in config &&\n (!['number', 'string'].includes(typeof config.version) ||\n config.version === '')\n ) {\n throw new Error(\"Invalid config parameter: 'version'\");\n }\n}\n\n/**\n * Converts a domain string to a list of domain parts.\n *\n * @param domain - the domain string to convert.\n * @returns the list of domain parts.\n */\nexport const domainToParts = (domain: string) => {\n return domain.split('.').reverse();\n};\n\n/**\n * Converts a list of domain strings to a list of domain parts.\n *\n * @param list - the list of domain strings to convert.\n * @returns the list of domain parts.\n */\nexport const processDomainList = (list: string[]): string[][] => {\n return list.reduce<string[][]>((acc, domain) => {\n if (typeof domain !== 'string') {\n console.warn(`Invalid domain value in list: ${JSON.stringify(domain)}`);\n return acc;\n }\n acc.push(domainToParts(domain));\n return acc;\n }, []);\n};\n\n/**\n * Gets the default phishing detector configuration.\n *\n * @param override - the optional override for the configuration.\n * @param override.allowlist - the optional allowlist to override.\n * @param override.blocklist - the optional blocklist to override.\n * @param override.fuzzylist - the optional fuzzylist to override.\n * @param override.tolerance - the optional tolerance to override.\n * @returns the default phishing detector configuration.\n */\nexport const getDefaultPhishingDetectorConfig = ({\n allowlist = [],\n blocklist = [],\n fuzzylist = [],\n tolerance = DEFAULT_TOLERANCE,\n}: {\n allowlist?: string[];\n blocklist?: string[];\n fuzzylist?: string[];\n tolerance?: number;\n}): PhishingDetectorConfiguration => {\n return {\n allowlist: processDomainList(allowlist),\n // We can assume that blocklist is already separated into hostname-only entries\n // and hostname+path entries so we do not need to separate it again.\n blocklist: processDomainList(blocklist),\n fuzzylist: processDomainList(fuzzylist),\n tolerance,\n };\n};\n\n/**\n * Processes the configurations for the phishing detector, filtering out any invalid configs.\n *\n * @param configs - The configurations to process.\n * @returns An array of processed and valid configurations.\n */\nexport const processConfigs = (\n configs: PhishingDetectorList[] = [],\n): PhishingDetectorConfiguration[] => {\n return configs\n .filter((config) => {\n try {\n validateConfig(config);\n return true;\n } catch (error) {\n console.error(error);\n return false;\n }\n })\n .map((config) => ({\n ...config,\n ...getDefaultPhishingDetectorConfig(config),\n }));\n};\n\n/**\n * Converts a list of domain parts to a domain string.\n *\n * @param domainParts - the list of domain parts.\n * @returns the domain string.\n */\nexport const domainPartsToDomain = (domainParts: string[]) => {\n return domainParts.slice().reverse().join('.');\n};\n\n/**\n * Converts a list of domain parts to a fuzzy form.\n *\n * @param domainParts - the list of domain parts.\n * @returns the fuzzy form of the domain.\n */\nexport const domainPartsToFuzzyForm = (domainParts: string[]) => {\n return domainParts.slice(1).reverse().join('.');\n};\n\n/**\n * Matches the target parts, ignoring extra subdomains on source.\n *\n * @param source - the source domain parts.\n * @param list - the list of domain parts to match against.\n * @returns the parts for the first found matching entry.\n */\nexport const matchPartsAgainstList = (source: string[], list: string[][]) => {\n return list.find((target) => {\n // target domain has more parts than source, fail\n if (target.length > source.length) {\n return false;\n }\n // source matches target or (is deeper subdomain)\n return target.every((part, index) => source[index] === part);\n });\n};\n\n/**\n * Generate the SHA-256 hash of a hostname.\n *\n * @param hostname - The hostname to hash.\n * @returns The SHA-256 hash of the hostname.\n */\nexport const sha256Hash = (hostname: string): string => {\n const hashBuffer = sha256(new TextEncoder().encode(hostname.toLowerCase()));\n return bytesToHex(hashBuffer);\n};\n\n/**\n * Extracts the hostname from a URL.\n *\n * @param url - The URL to extract the hostname from.\n * @returns The hostname extracted from the URL, or null if the URL is invalid.\n */\nexport const getHostnameFromUrl = (url: string): string | null => {\n let hostname;\n try {\n hostname = new URL(url).hostname;\n // above will not throw if 'http://.' is passed. in fact, any string with a dot will pass.\n if (!hostname || hostname.split('.').join('') === '') {\n return null;\n }\n } catch {\n return null;\n }\n return hostname;\n};\n\n/**\n * getHostnameFromWebUrl returns the hostname from a web URL.\n * It returns the hostname and a boolean indicating if the hostname is valid.\n *\n * @param url - The web URL to extract the hostname from.\n * @returns A tuple containing the extracted hostname and a boolean indicating if the hostname is valid.\n * @example\n * getHostnameFromWebUrl('https://example.com') // Returns: ['example.com', true]\n * getHostnameFromWebUrl('example.com') // Returns: ['', false]\n * getHostnameFromWebUrl('https://') // Returns: ['', false]\n * getHostnameFromWebUrl('') // Returns: ['', false]\n */\nexport const getHostnameFromWebUrl = (url: string): [string, boolean] => {\n if (\n !url.toLowerCase().startsWith('http://') &&\n !url.toLowerCase().startsWith('https://')\n ) {\n return ['', false];\n }\n\n const hostname = getHostnameFromUrl(url);\n return [hostname || '', Boolean(hostname)];\n};\n\nexport const getPathnameFromUrl = (url: string): string => {\n try {\n const { pathname } = new URL(url);\n return pathname;\n } catch {\n return '';\n }\n};\n\n/**\n * Generates all possible parent domains up to a specified limit.\n *\n * @param sourceParts - The list of domain parts in normal order (e.g., ['evil', 'domain', 'co', 'uk']).\n * @param limit - The maximum number of parent domains to generate (default is 5).\n * @returns An array of parent domains starting from the base TLD to the most specific subdomain.\n * @example\n * generateParentDomains(['evil', 'domain', 'co', 'uk'], 5)\n * // Returns: ['co.uk', 'domain.co.uk', 'evil.domain.co.uk']\n *\n * generateParentDomains(['uk'], 5)\n * // Returns: ['uk']\n *\n * generateParentDomains(['sub', 'example', 'com'], 5)\n * // Returns: ['example.com', 'sub.example.com']\n */\nexport const generateParentDomains = (\n sourceParts: string[],\n limit = 5,\n): string[] => {\n const domains: string[] = [];\n\n if (sourceParts.length === 0) {\n return domains;\n }\n\n if (sourceParts.length === 1) {\n // Single-segment hostname (e.g., 'uk')\n domains.push(sourceParts[0].toLowerCase());\n } else {\n // Start with the base domain or TLD (last two labels, e.g., 'co.uk' or 'example.com')\n const baseDomain = sourceParts.slice(-2).join('.');\n domains.push(baseDomain.toLowerCase());\n\n // Iteratively add one subdomain level at a time, up to the specified limit\n for (\n let i = sourceParts.length - 3;\n i >= 0 && domains.length < limit;\n i--\n ) {\n const domain = sourceParts.slice(i).join('.');\n domains.push(domain.toLowerCase());\n }\n }\n\n return domains;\n};\n\n/**\n * Builds a cache key for a token scan result.\n *\n * @param chainId - The chain ID.\n * @param address - The token address.\n * @param caseSensitive - When `true`, the address is kept as-is (for chains\n * like Solana where addresses are case-sensitive). When `false` (default),\n * the address is lowercased (appropriate for EVM).\n * @returns The cache key.\n */\nexport const buildCacheKey = (\n chainId: string,\n address: string,\n caseSensitive = false,\n) => {\n const normalizedAddress = caseSensitive ? address : address.toLowerCase();\n return `${chainId.toLowerCase()}:${normalizedAddress}`;\n};\n\n/**\n * Resolves the chain name from a chain ID.\n *\n * @param chainId - The chain ID.\n * @param mapping - The mapping of chain IDs to chain names.\n * @returns The chain name.\n */\nexport const resolveChainName = (\n chainId: string,\n mapping = DEFAULT_CHAIN_ID_TO_NAME,\n): string | null => {\n return mapping[chainId.toLowerCase() as keyof typeof mapping] ?? null;\n};\n\n/**\n * Split tokens into cached results and tokens that need to be fetched.\n *\n * @param cache - Cache-like object with get method.\n * @param cache.get - Method to retrieve cached data by key.\n * @param chainId - The chain ID.\n * @param tokens - Array of token addresses.\n * @param caseSensitive - When `true`, token addresses are kept as-is (for\n * chains like Solana where addresses are case-sensitive). When `false`\n * (default), addresses are lowercased (appropriate for EVM).\n * @returns Object containing cached results and tokens to fetch.\n */\nexport const splitCacheHits = (\n cache: { get: (key: string) => TokenScanCacheData | undefined },\n chainId: string,\n tokens: string[],\n caseSensitive = false,\n): {\n cachedResults: Record<string, TokenScanResult>;\n tokensToFetch: string[];\n} => {\n const cachedResults: Record<string, TokenScanResult> = {};\n const tokensToFetch: string[] = [];\n\n for (const address of tokens) {\n const normalizedAddress = caseSensitive ? address : address.toLowerCase();\n const key = buildCacheKey(chainId, normalizedAddress, caseSensitive);\n const hit = cache.get(key);\n if (hit) {\n cachedResults[normalizedAddress] = {\n result_type: hit.result_type,\n chain: chainId,\n address: normalizedAddress,\n };\n } else {\n tokensToFetch.push(normalizedAddress);\n }\n }\n\n return { cachedResults, tokensToFetch };\n};\n"]}
1
+ {"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { bytesToHex } from '@noble/hashes/utils';\nimport { sha256 } from 'ethereum-cryptography/sha256';\n\nimport { deleteFromTrie, insertToTrie, deepCopyPathTrie } from './PathTrie';\nimport type { Hotlist, PhishingListState } from './PhishingController';\nimport { ListKeys, phishingListKeyNameMap } from './PhishingController';\nimport type {\n PhishingDetectorList,\n PhishingDetectorConfiguration,\n} from './PhishingDetector';\nimport { DEFAULT_CHAIN_ID_TO_NAME } from './types';\nimport type { TokenScanCacheData, TokenScanResult } from './types';\n\nconst DEFAULT_TOLERANCE = 3;\n\n/**\n * Fetches current epoch time in seconds.\n *\n * @returns the Date.now() time in seconds instead of miliseconds. backend files rely on timestamps in seconds since epoch.\n */\nexport const fetchTimeNow = (): number => Math.round(Date.now() / 1000);\n\n/**\n * Rounds a Unix timestamp down to the nearest minute.\n *\n * @param unixTimestamp - The Unix timestamp to be rounded.\n * @returns The rounded Unix timestamp.\n */\nexport function roundToNearestMinute(unixTimestamp: number): number {\n return Math.floor(unixTimestamp / 60) * 60;\n}\n\n/**\n * Split a string into two pieces, using the first period as the delimiter.\n *\n * @param stringToSplit - The string to split.\n * @returns An array of length two containing the beginning and end of the string.\n */\nconst splitStringByPeriod = <Start extends string, End extends string>(\n stringToSplit: `${Start}.${End}`,\n): [Start, End] => {\n const periodIndex = stringToSplit.indexOf('.');\n return [\n stringToSplit.slice(0, periodIndex) as Start,\n stringToSplit.slice(periodIndex + 1) as End,\n ];\n};\n\nexport const getHostnameAndPathComponents = (\n url: string,\n): { hostname: string; pathComponents: string[] } => {\n const urlWithProtocol = url.startsWith('http') ? url : `https://${url}`;\n try {\n const { hostname, pathname } = new URL(urlWithProtocol);\n return {\n hostname: hostname.toLowerCase(),\n pathComponents: pathname\n .split('/')\n .filter(Boolean)\n .map((component) => decodeURIComponent(component)),\n };\n } catch {\n return {\n hostname: '',\n pathComponents: [],\n };\n }\n};\n\n/**\n * Determines which diffs are applicable to the listState, then applies those diffs.\n *\n * @param listState - the stalelist or the existing liststate that diffs will be applied to.\n * @param hotlistDiffs - the diffs to apply to the listState if valid.\n * @param listKey - the key associated with the input/output phishing list state.\n * @param recentlyAddedC2Domains - list of hashed C2 domains to add to the local c2 domain blocklist\n * @param recentlyRemovedC2Domains - list of hashed C2 domains to remove from the local c2 domain blocklist\n * @returns the new list state\n */\nexport const applyDiffs = (\n listState: PhishingListState,\n hotlistDiffs: Hotlist,\n listKey: ListKeys,\n recentlyAddedC2Domains: string[] = [],\n recentlyRemovedC2Domains: string[] = [],\n): PhishingListState => {\n // filter to remove diffs that were added before the lastUpdate time.\n // filter to remove diffs that aren't applicable to the specified list (by listKey).\n const diffsToApply = hotlistDiffs.filter(\n ({ timestamp, targetList }) =>\n timestamp > listState.lastUpdated &&\n splitStringByPeriod(targetList)[0] === listKey,\n );\n\n // the reason behind using latestDiffTimestamp as the lastUpdated time\n // is so that we can benefit server-side from memoization due to end client's\n // `GET /v1/diffSince/:timestamp` requests lining up with\n // our periodic updates (which create diffs at specific timestamps).\n let latestDiffTimestamp = listState.lastUpdated;\n\n const listSets = {\n allowlist: new Set(listState.allowlist),\n blocklist: new Set(listState.blocklist),\n fuzzylist: new Set(listState.fuzzylist),\n c2DomainBlocklist: new Set(listState.c2DomainBlocklist),\n };\n\n // deep copy of blocklistPaths to avoid mutating the original\n const newBlocklistPaths = deepCopyPathTrie(listState.blocklistPaths);\n\n for (const { isRemoval, targetList, url, timestamp } of diffsToApply) {\n const targetListType = splitStringByPeriod(targetList)[1];\n if (timestamp > latestDiffTimestamp) {\n latestDiffTimestamp = timestamp;\n }\n\n if (isRemoval) {\n if (targetListType === 'blocklistPaths') {\n deleteFromTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].delete(url);\n }\n continue;\n }\n\n if (targetListType === 'blocklistPaths') {\n insertToTrie(url, newBlocklistPaths);\n } else {\n listSets[targetListType].add(url);\n }\n }\n\n if (listKey === ListKeys.EthPhishingDetectConfig) {\n for (const hash of recentlyAddedC2Domains) {\n listSets.c2DomainBlocklist.add(hash);\n }\n for (const hash of recentlyRemovedC2Domains) {\n listSets.c2DomainBlocklist.delete(hash);\n }\n }\n\n return {\n c2DomainBlocklist: Array.from(listSets.c2DomainBlocklist),\n allowlist: Array.from(listSets.allowlist),\n blocklist: Array.from(listSets.blocklist),\n fuzzylist: Array.from(listSets.fuzzylist),\n blocklistPaths: newBlocklistPaths,\n version: listState.version,\n name: phishingListKeyNameMap[listKey],\n tolerance: listState.tolerance,\n lastUpdated: latestDiffTimestamp,\n };\n};\n\n/**\n * Validates the configuration object for the phishing detector.\n *\n * @param config - the configuration object to validate.\n * @throws an error if the configuration is invalid.\n */\nexport function validateConfig(\n config: unknown,\n): asserts config is PhishingListState {\n if (config === null || typeof config !== 'object') {\n throw new Error('Invalid config');\n }\n\n if ('tolerance' in config && !('fuzzylist' in config)) {\n throw new Error('Fuzzylist tolerance provided without fuzzylist');\n }\n\n if (\n 'name' in config &&\n (typeof config.name !== 'string' || config.name === '')\n ) {\n throw new Error(\"Invalid config parameter: 'name'\");\n }\n\n if (\n 'version' in config &&\n (!['number', 'string'].includes(typeof config.version) ||\n config.version === '')\n ) {\n throw new Error(\"Invalid config parameter: 'version'\");\n }\n}\n\n/**\n * Converts a domain string to a list of domain parts.\n *\n * @param domain - the domain string to convert.\n * @returns the list of domain parts.\n */\nexport const domainToParts = (domain: string) => {\n return domain.split('.').reverse();\n};\n\n/**\n * Converts a list of domain strings to a list of domain parts.\n *\n * @param list - the list of domain strings to convert.\n * @returns the list of domain parts.\n */\nexport const processDomainList = (list: string[]): string[][] => {\n return list.reduce<string[][]>((acc, domain) => {\n if (typeof domain !== 'string') {\n console.warn(`Invalid domain value in list: ${JSON.stringify(domain)}`);\n return acc;\n }\n acc.push(domainToParts(domain));\n return acc;\n }, []);\n};\n\n/**\n * Gets the default phishing detector configuration.\n *\n * @param override - the optional override for the configuration.\n * @param override.allowlist - the optional allowlist to override.\n * @param override.blocklist - the optional blocklist to override.\n * @param override.fuzzylist - the optional fuzzylist to override.\n * @param override.tolerance - the optional tolerance to override.\n * @returns the default phishing detector configuration.\n */\nexport const getDefaultPhishingDetectorConfig = ({\n allowlist = [],\n blocklist = [],\n fuzzylist = [],\n tolerance = DEFAULT_TOLERANCE,\n}: {\n allowlist?: string[];\n blocklist?: string[];\n fuzzylist?: string[];\n tolerance?: number;\n}): PhishingDetectorConfiguration => {\n return {\n allowlist: processDomainList(allowlist),\n // We can assume that blocklist is already separated into hostname-only entries\n // and hostname+path entries so we do not need to separate it again.\n blocklist: processDomainList(blocklist),\n fuzzylist: processDomainList(fuzzylist),\n tolerance,\n };\n};\n\n/**\n * Processes the configurations for the phishing detector, filtering out any invalid configs.\n *\n * @param configs - The configurations to process.\n * @returns An array of processed and valid configurations.\n */\nexport const processConfigs = (\n configs: PhishingDetectorList[] = [],\n): PhishingDetectorConfiguration[] => {\n return configs\n .filter((config) => {\n try {\n validateConfig(config);\n return true;\n } catch (error) {\n console.error(error);\n return false;\n }\n })\n .map((config) => ({\n ...config,\n ...getDefaultPhishingDetectorConfig(config),\n }));\n};\n\n/**\n * Converts a list of domain parts to a domain string.\n *\n * @param domainParts - the list of domain parts.\n * @returns the domain string.\n */\nexport const domainPartsToDomain = (domainParts: string[]) => {\n return domainParts.slice().reverse().join('.');\n};\n\n/**\n * Converts a list of domain parts to a fuzzy form.\n *\n * @param domainParts - the list of domain parts.\n * @returns the fuzzy form of the domain.\n */\nexport const domainPartsToFuzzyForm = (domainParts: string[]) => {\n return domainParts.slice(1).reverse().join('.');\n};\n\n/**\n * Matches the target parts, ignoring extra subdomains on source.\n *\n * @param source - the source domain parts.\n * @param list - the list of domain parts to match against.\n * @returns the parts for the first found matching entry.\n */\nexport const matchPartsAgainstList = (source: string[], list: string[][]) => {\n return list.find((target) => {\n // target domain has more parts than source, fail\n if (target.length > source.length) {\n return false;\n }\n // source matches target or (is deeper subdomain)\n return target.every((part, index) => source[index] === part);\n });\n};\n\n/**\n * Generate the SHA-256 hash of a hostname.\n *\n * @param hostname - The hostname to hash.\n * @returns The SHA-256 hash of the hostname.\n */\nexport const sha256Hash = (hostname: string): string => {\n const hashBuffer = sha256(new TextEncoder().encode(hostname.toLowerCase()));\n return bytesToHex(hashBuffer);\n};\n\n/**\n * Extracts the hostname from a URL.\n *\n * @param url - The URL to extract the hostname from.\n * @returns The hostname extracted from the URL, or null if the URL is invalid.\n */\nexport const getHostnameFromUrl = (url: string): string | null => {\n let hostname;\n try {\n hostname = new URL(url).hostname;\n // above will not throw if 'http://.' is passed. in fact, any string with a dot will pass.\n if (!hostname || hostname.split('.').join('') === '') {\n return null;\n }\n } catch {\n return null;\n }\n return hostname;\n};\n\n/**\n * getHostnameFromWebUrl returns the hostname from a web URL.\n * It returns the hostname and a boolean indicating if the hostname is valid.\n *\n * @param url - The web URL to extract the hostname from.\n * @returns A tuple containing the extracted hostname and a boolean indicating if the hostname is valid.\n * @example\n * getHostnameFromWebUrl('https://example.com') // Returns: ['example.com', true]\n * getHostnameFromWebUrl('example.com') // Returns: ['', false]\n * getHostnameFromWebUrl('https://') // Returns: ['', false]\n * getHostnameFromWebUrl('') // Returns: ['', false]\n */\nexport const getHostnameFromWebUrl = (url: string): [string, boolean] => {\n if (\n !url.toLowerCase().startsWith('http://') &&\n !url.toLowerCase().startsWith('https://')\n ) {\n return ['', false];\n }\n\n const hostname = getHostnameFromUrl(url);\n return [hostname || '', Boolean(hostname)];\n};\n\nexport const getPathnameFromUrl = (url: string): string => {\n try {\n const { pathname } = new URL(url);\n return pathname;\n } catch {\n return '';\n }\n};\n\n/**\n * Generates all possible parent domains up to a specified limit.\n *\n * @param sourceParts - The list of domain parts in normal order (e.g., ['evil', 'domain', 'co', 'uk']).\n * @param limit - The maximum number of parent domains to generate (default is 5).\n * @returns An array of parent domains starting from the base TLD to the most specific subdomain.\n * @example\n * generateParentDomains(['evil', 'domain', 'co', 'uk'], 5)\n * // Returns: ['co.uk', 'domain.co.uk', 'evil.domain.co.uk']\n *\n * generateParentDomains(['uk'], 5)\n * // Returns: ['uk']\n *\n * generateParentDomains(['sub', 'example', 'com'], 5)\n * // Returns: ['example.com', 'sub.example.com']\n */\nexport const generateParentDomains = (\n sourceParts: string[],\n limit = 5,\n): string[] => {\n const domains: string[] = [];\n\n if (sourceParts.length === 0) {\n return domains;\n }\n\n if (sourceParts.length === 1) {\n // Single-segment hostname (e.g., 'uk')\n domains.push(sourceParts[0].toLowerCase());\n } else {\n // Start with the base domain or TLD (last two labels, e.g., 'co.uk' or 'example.com')\n const baseDomain = sourceParts.slice(-2).join('.');\n domains.push(baseDomain.toLowerCase());\n\n // Iteratively add one subdomain level at a time, up to the specified limit\n for (\n let i = sourceParts.length - 3;\n i >= 0 && domains.length < limit;\n i--\n ) {\n const domain = sourceParts.slice(i).join('.');\n domains.push(domain.toLowerCase());\n }\n }\n\n return domains;\n};\n\n/**\n * Builds a cache key for a token scan result.\n *\n * @param chainId - The chain ID.\n * @param address - The token address.\n * @returns The cache key.\n */\nexport const buildCacheKey = (chainId: string, address: string) => {\n return `${chainId.toLowerCase()}:${address.toLowerCase()}`;\n};\n\n/**\n * Resolves the chain name from a chain ID.\n *\n * @param chainId - The chain ID.\n * @param mapping - The mapping of chain IDs to chain names.\n * @returns The chain name.\n */\nexport const resolveChainName = (\n chainId: string,\n mapping = DEFAULT_CHAIN_ID_TO_NAME,\n): string | null => {\n return mapping[chainId.toLowerCase() as keyof typeof mapping] ?? null;\n};\n\n/**\n * Split tokens into cached results and tokens that need to be fetched.\n *\n * @param cache - Cache-like object with get method.\n * @param cache.get - Method to retrieve cached data by key.\n * @param chainId - The chain ID.\n * @param tokens - Array of token addresses.\n * @returns Object containing cached results and tokens to fetch.\n */\nexport const splitCacheHits = (\n cache: { get: (key: string) => TokenScanCacheData | undefined },\n chainId: string,\n tokens: string[],\n): {\n cachedResults: Record<string, TokenScanResult>;\n tokensToFetch: string[];\n} => {\n const cachedResults: Record<string, TokenScanResult> = {};\n const tokensToFetch: string[] = [];\n\n for (const addr of tokens) {\n const normalizedAddr = addr.toLowerCase();\n const key = buildCacheKey(chainId, normalizedAddr);\n const hit = cache.get(key);\n if (hit) {\n cachedResults[normalizedAddr] = {\n result_type: hit.result_type,\n chain: chainId,\n address: normalizedAddr,\n };\n } else {\n tokensToFetch.push(normalizedAddr);\n }\n }\n\n return { cachedResults, tokensToFetch };\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask-previews/phishing-controller",
3
- "version": "16.2.0-preview-6a225bc30",
3
+ "version": "16.2.0-preview-e7b1aa6",
4
4
  "description": "Maintains a periodically updated list of approved and unapproved website origins",
5
5
  "keywords": [
6
6
  "MetaMask",