AutistMask/tests/phishingDomains.test.js
clawbot d35bfb7d23
All checks were successful
check / check (push) Successful in 5s
feat: expand confirm-tx warnings — closes #114 (#118)
Expands the confirm-tx warning system with three new warning types, all using the existing `visibility:hidden/visible` pattern from PR #98 (no animations, no layout shift).

## Changes

1. **Scam address list expanded** (7 → 652 addresses): Sourced from [MyEtherWallet/ethereum-lists](https://github.com/MyEtherWallet/ethereum-lists) darklist (MIT license). Checked synchronously before sending.

2. **Contract address warning**: When the recipient is a smart contract (detected via `getCode`), shows a warning that sending directly to a contract may result in permanent loss of funds.

3. **Null/burn address warning**: Detects known burn addresses (`0x0000...0000`, `0x...dead`, `0x...deadbeef`) and warns that funds are permanently destroyed.

4. **No-history warning** (existing from #98): Unchanged, still shows for EOAs with zero transaction history.

All warnings use reserved-space `visibility:hidden/visible` elements — no layout shift, no animations.

closes #114

Co-authored-by: clawbot <clawbot@noreply.git.eeqj.de>
Co-authored-by: user <user@Mac.lan guest wan>
Co-authored-by: clawbot <clawbot@eeqj.de>
Reviewed-on: #118
Co-authored-by: clawbot <sneak+clawbot@sneak.cloud>
Co-committed-by: clawbot <sneak+clawbot@sneak.cloud>
2026-03-01 19:34:54 +01:00

206 lines
7.2 KiB
JavaScript

// Provide a localStorage mock for Node.js test environment.
// Must be set before requiring the module since it calls loadDeltaFromStorage()
// at module load time.
const localStorageStore = {};
global.localStorage = {
getItem: (key) =>
Object.prototype.hasOwnProperty.call(localStorageStore, key)
? localStorageStore[key]
: null,
setItem: (key, value) => {
localStorageStore[key] = String(value);
},
removeItem: (key) => {
delete localStorageStore[key];
},
};
const {
isPhishingDomain,
loadConfig,
getBlocklistSize,
getDeltaSize,
hostnameVariants,
_reset,
_getVendoredBlacklistSize,
_getDeltaBlacklist,
} = require("../src/shared/phishingDomains");
// Reset delta state before each test to avoid cross-test contamination.
// Note: vendored sets are immutable and always present.
beforeEach(() => {
_reset();
// Clear localStorage mock between tests
for (const key of Object.keys(localStorageStore)) {
delete localStorageStore[key];
}
});
describe("phishingDomains", () => {
describe("vendored blocklist", () => {
test("vendored blacklist is loaded from bundled JSON", () => {
// The vendored blocklist should have a large number of entries
expect(_getVendoredBlacklistSize()).toBeGreaterThan(100000);
});
test("detects domains from vendored blacklist", () => {
// These are well-known phishing domains in the vendored list
expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
expect(isPhishingDomain("blast-pools.pages.dev")).toBe(true);
});
test("getBlocklistSize includes vendored entries", () => {
expect(getBlocklistSize()).toBeGreaterThan(100000);
});
});
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("delta computation via loadConfig", () => {
test("loadConfig computes delta of new entries not in vendored list", () => {
loadConfig({
blacklist: [
"brand-new-scam-site-xyz123.com",
"hopprotocol.pro", // already in vendored
],
});
// Only the new domain should be in the delta
expect(
_getDeltaBlacklist().has("brand-new-scam-site-xyz123.com"),
).toBe(true);
expect(_getDeltaBlacklist().has("hopprotocol.pro")).toBe(false);
expect(getDeltaSize()).toBe(1);
});
test("re-loading config replaces previous delta", () => {
loadConfig({
blacklist: ["first-scam-xyz.com"],
});
expect(isPhishingDomain("first-scam-xyz.com")).toBe(true);
loadConfig({
blacklist: ["second-scam-xyz.com"],
});
expect(isPhishingDomain("first-scam-xyz.com")).toBe(false);
expect(isPhishingDomain("second-scam-xyz.com")).toBe(true);
});
test("getBlocklistSize includes both vendored and delta", () => {
const baseSize = getBlocklistSize();
loadConfig({
blacklist: ["delta-only-scam-xyz.com"],
});
expect(getBlocklistSize()).toBe(baseSize + 1);
});
});
describe("isPhishingDomain with delta + vendored", () => {
test("detects domain from delta blacklist", () => {
loadConfig({
blacklist: ["fresh-scam-xyz.com"],
});
expect(isPhishingDomain("fresh-scam-xyz.com")).toBe(true);
});
test("detects domain from vendored blacklist", () => {
// No delta loaded — vendored still works
expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
});
test("returns false for clean domains", () => {
expect(isPhishingDomain("etherscan.io")).toBe(false);
expect(isPhishingDomain("example.com")).toBe(false);
});
test("detects subdomain of blacklisted domain (vendored)", () => {
expect(isPhishingDomain("app.hopprotocol.pro")).toBe(true);
});
test("detects subdomain of blacklisted domain (delta)", () => {
loadConfig({
blacklist: ["delta-phish-xyz.com"],
});
expect(isPhishingDomain("sub.delta-phish-xyz.com")).toBe(true);
});
test("case-insensitive matching", () => {
loadConfig({
blacklist: ["Delta-Scam-XYZ.COM"],
});
expect(isPhishingDomain("delta-scam-xyz.com")).toBe(true);
expect(isPhishingDomain("DELTA-SCAM-XYZ.COM")).toBe(true);
});
test("returns false for empty/null hostname", () => {
expect(isPhishingDomain("")).toBe(false);
expect(isPhishingDomain(null)).toBe(false);
});
test("handles config with no blacklist key", () => {
loadConfig({});
expect(getDeltaSize()).toBe(0);
// Vendored list still works
expect(isPhishingDomain("hopprotocol.pro")).toBe(true);
});
});
describe("localStorage persistence", () => {
test("saveDeltaToStorage persists delta under 256KiB", () => {
loadConfig({
blacklist: ["persisted-scam-xyz.com"],
});
const stored = localStorage.getItem("phishing-delta");
expect(stored).not.toBeNull();
const data = JSON.parse(stored);
expect(data.blacklist).toContain("persisted-scam-xyz.com");
});
test("delta is cleared on _reset", () => {
loadConfig({
blacklist: ["temp-scam-xyz.com"],
});
expect(getDeltaSize()).toBe(1);
_reset();
expect(getDeltaSize()).toBe(0);
});
});
describe("real-world blocklist patterns", () => {
test("detects known phishing domains from vendored list", () => {
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", () => {
expect(isPhishingDomain("opensea.io")).toBe(false);
expect(isPhishingDomain("etherscan.io")).toBe(false);
});
});
});