// The one definition of how a domain becomes a blocklist entry. // // The vendored phishing blocklist ships digests, not domain names: see // phishingDomains.js for why, and script/vendor-blocklist for how the artifact // is produced. Both sides have to agree exactly — a mismatch would silently // match nothing, which is a blocklist that quietly protects no one — so the // rule lives here and is required by both rather than written down twice. // // sha256 truncated to 64 bits. Truncation is what keeps the artifact small // enough to bundle (16 hex characters per entry rather than 64), and 64 bits is // far past what this has to withstand: over ~10^5 entries the chance that any // hostname a user visits collides with an entry it is not is about 10^-14 per // lookup, and a deliberate collision buys an attacker a false phishing warning // on a site they do not control, not a missed one. For scale, Safe Browsing // distributes 32-bit prefixes and resolves the rest against a server; this is // 32 bits more, with no server involved. const { sha256, toUtf8Bytes } = require("ethers"); const HASH_ALGORITHM = "sha256"; const HASH_HEX_CHARS = 16; /** * The blocklist entry for a domain: lowercased, hashed, truncated. * * @param {string} domain * @returns {string} HASH_HEX_CHARS lowercase hex characters, no 0x prefix. */ function hashDomain(domain) { // ethers returns "0x" + 64 hex characters. return sha256(toUtf8Bytes(domain.toLowerCase())).slice( 2, 2 + HASH_HEX_CHARS, ); } module.exports = { HASH_ALGORITHM, HASH_HEX_CHARS, hashDomain, };