Files
AutistMask/tests/phishingDomains.test.js
user 01839d9c47
All checks were successful
check / check (push) Successful in 22s
feat: add Etherscan label scraping and MetaMask phishing domain blocklist
- Add etherscanLabels module: scrapes Etherscan address pages for
  phishing/scam labels (Fake_Phishing*, Exploiter, scam warnings).
  Integrated as best-effort async check in addressWarnings.

- Add phishingDomains module: fetches MetaMask's eth-phishing-detect
  blocklist (~231K domains) at runtime, caches in memory, refreshes
  every 24h. Checks hostnames with subdomain matching and whitelist
  overrides.

- Integrate domain phishing checks into all approval flows:
  connection requests, transaction approvals, and signature requests
  show a prominent red warning banner when the requesting site is on
  the MetaMask blocklist.

- Add unit tests for both modules (12 tests for etherscanLabels
  parsing, 15 tests for phishingDomains matching).

Closes #114
2026-03-01 05:03:42 -08:00

167 lines
5.7 KiB
JavaScript

const {
isPhishingDomain,
loadConfig,
getBlocklistSize,
hostnameVariants,
_reset,
} = require("../src/shared/phishingDomains");
// Reset state before each test to avoid cross-test contamination.
beforeEach(() => {
_reset();
});
describe("phishingDomains", () => {
describe("hostnameVariants", () => {
test("returns exact hostname plus parent domains", () => {
const variants = hostnameVariants("sub.evil.com");
expect(variants).toEqual(["sub.evil.com", "evil.com"]);
});
test("returns just the hostname for a bare domain", () => {
const variants = hostnameVariants("example.com");
expect(variants).toEqual(["example.com"]);
});
test("handles deep subdomain chains", () => {
const variants = hostnameVariants("a.b.c.d.com");
expect(variants).toEqual([
"a.b.c.d.com",
"b.c.d.com",
"c.d.com",
"d.com",
]);
});
test("lowercases hostnames", () => {
const variants = hostnameVariants("Evil.COM");
expect(variants).toEqual(["evil.com"]);
});
});
describe("loadConfig + isPhishingDomain", () => {
test("detects exact blacklisted domain", () => {
loadConfig({
blacklist: ["evil-phishing.com", "scam-swap.xyz"],
whitelist: [],
});
expect(isPhishingDomain("evil-phishing.com")).toBe(true);
expect(isPhishingDomain("scam-swap.xyz")).toBe(true);
});
test("returns false for clean domains", () => {
loadConfig({
blacklist: ["evil-phishing.com"],
whitelist: [],
});
expect(isPhishingDomain("etherscan.io")).toBe(false);
expect(isPhishingDomain("uniswap.org")).toBe(false);
});
test("detects subdomain of blacklisted domain", () => {
loadConfig({
blacklist: ["evil-phishing.com"],
whitelist: [],
});
expect(isPhishingDomain("app.evil-phishing.com")).toBe(true);
expect(isPhishingDomain("sub.app.evil-phishing.com")).toBe(true);
});
test("whitelist overrides blacklist", () => {
loadConfig({
blacklist: ["metamask.io"],
whitelist: ["metamask.io"],
});
expect(isPhishingDomain("metamask.io")).toBe(false);
});
test("whitelist on parent domain overrides blacklist", () => {
loadConfig({
blacklist: ["sub.legit.com"],
whitelist: ["legit.com"],
});
expect(isPhishingDomain("sub.legit.com")).toBe(false);
});
test("case-insensitive matching", () => {
loadConfig({
blacklist: ["Evil-Phishing.COM"],
whitelist: [],
});
expect(isPhishingDomain("evil-phishing.com")).toBe(true);
expect(isPhishingDomain("EVIL-PHISHING.COM")).toBe(true);
});
test("returns false for empty/null hostname", () => {
loadConfig({
blacklist: ["evil.com"],
whitelist: [],
});
expect(isPhishingDomain("")).toBe(false);
expect(isPhishingDomain(null)).toBe(false);
});
test("getBlocklistSize reflects loaded config", () => {
loadConfig({
blacklist: ["a.com", "b.com", "c.com"],
whitelist: ["d.com"],
});
expect(getBlocklistSize()).toBe(3);
});
test("handles config with no blacklist/whitelist keys", () => {
loadConfig({});
expect(isPhishingDomain("anything.com")).toBe(false);
expect(getBlocklistSize()).toBe(0);
});
test("re-loading config replaces previous data", () => {
loadConfig({
blacklist: ["old-scam.com"],
whitelist: [],
});
expect(isPhishingDomain("old-scam.com")).toBe(true);
loadConfig({
blacklist: ["new-scam.com"],
whitelist: [],
});
expect(isPhishingDomain("old-scam.com")).toBe(false);
expect(isPhishingDomain("new-scam.com")).toBe(true);
});
});
describe("real-world MetaMask blocklist patterns", () => {
test("detects known phishing domains from MetaMask list", () => {
loadConfig({
blacklist: [
"uniswap-trade.web.app",
"hopprotocol.pro",
"blast-pools.pages.dev",
],
whitelist: [],
});
expect(isPhishingDomain("uniswap-trade.web.app")).toBe(true);
expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
expect(isPhishingDomain("blast-pools.pages.dev")).toBe(true);
});
test("does not flag legitimate domains whitelisted by MetaMask", () => {
loadConfig({
blacklist: ["opensea.pro"],
whitelist: [
"opensea.io",
"metamask.io",
"etherscan.io",
"opensea.pro",
],
});
expect(isPhishingDomain("opensea.io")).toBe(false);
expect(isPhishingDomain("metamask.io")).toBe(false);
expect(isPhishingDomain("etherscan.io")).toBe(false);
// opensea.pro is both blacklisted and whitelisted — whitelist wins
expect(isPhishingDomain("opensea.pro")).toBe(false);
});
});
});