42 lines
1.6 KiB
JavaScript
42 lines
1.6 KiB
JavaScript
// 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,
|
|
};
|