/* ****************************************************************************************************************** *\ Helper Functions \* ****************************************************************************************************************** */ /* -------------------------------------------------------------------------- *\ Basic Builders \* -------------------------------------------------------------------------- */ /** * Create CNAME records from "comment@subdomain" strings * @param {string} domain - Domain to extend * @param {string} target - Server target * @param {string[]} records - Array of "comment@subdomain" strings */ function cnames(domain, target, records) { records.forEach(function(rec) { var part = rec.split("@"); D_EXTEND(domain, CNAME(part[1], target, CF_COMMENT(part[0]))); }); } /** * Create a Minecraft server subdomain with CNAME and SRV records * @param {string} comment - Human-readable server name * @param {string} subdomain - Subdomain for the server * @param {string} domain - Domain to extend * @param {number} port - Port the server listens on */ function minecraft(comment, subdomain, domain, port) { var fqdn = subdomain + "." + domain + "."; D_EXTEND(domain, CNAME(subdomain, rexbox, CF_COMMENT("Minecraft > " + comment)), SRV("_minecraft._tcp." + subdomain, 0, 0, port, fqdn, CF_COMMENT("Minecraft > " + comment)), ); } /* -------------------------------------------------------------------------- *\ Email Builders \* -------------------------------------------------------------------------- */ /** * Generate ProtonMail DNS records (MX, SPF, DMARC, verification, DKIM) * @param {string} verification - ProtonMail verification token * @param {string} dkimKey - ProtonMail DKIM domain key * @returns {DomainModifier[]} Array of DNS records */ function protonmail(verification, dkimKey) { return [ // Stage 1: Verify TXT("@", "protonmail-verification=" + verification, CF_COMMENT("ProtonMail Verify")), // Stage 2: MX MX("@", 10, "mail.protonmail.ch.", CF_COMMENT("ProtonMail MX")), MX("@", 20, "mailsec.protonmail.ch.", CF_COMMENT("ProtonMail MX")), // Stage 3: SPF TXT("@", "v=spf1 include:_spf.protonmail.ch mx ~all", CF_COMMENT("ProtonMail SPF")), // Stage 3: DKIM CNAME("protonmail._domainkey", "protonmail.domainkey." + dkimKey + ".domains.proton.ch.", CF_COMMENT("ProtonMail DKIM")), CNAME("protonmail2._domainkey", "protonmail2.domainkey." + dkimKey + ".domains.proton.ch.", CF_COMMENT("ProtonMail DKIM")), CNAME("protonmail3._domainkey", "protonmail3.domainkey." + dkimKey + ".domains.proton.ch.", CF_COMMENT("ProtonMail DKIM")), // Stage 4: DMARC dmarcRecord, ]; } /** * Generate SimpleLogin DNS records (MX, SPF, DMARC, verification, DKIM) * @param {string} verification - SimpleLogin verification token * @returns {DomainModifier[]} Array of DNS records */ function simplelogin(verification) { return [ // Stage 1: Verify TXT("@", "sl-verification=" + verification, CF_COMMENT("SimpleLogin Verify")), // Stage 2: MX MX("@", 10, "mx1.simplelogin.co.", CF_COMMENT("SimpleLogin MX")), MX("@", 20, "mx2.simplelogin.co.", CF_COMMENT("SimpleLogin MX")), // Stage 3: SPF TXT("@", "v=spf1 include:simplelogin.co ~all", CF_COMMENT("SimpleLogin SPF")), // Stage 4: DKIM CNAME("dkim._domainkey", "dkim._domainkey.simplelogin.co.", CF_COMMENT("SimpleLogin DKIM")), CNAME("dkim02._domainkey", "dkim02._domainkey.simplelogin.co.", CF_COMMENT("SimpleLogin DKIM")), CNAME("dkim03._domainkey", "dkim03._domainkey.simplelogin.co.", CF_COMMENT("SimpleLogin DKIM")), // Stage 5: DMARC dmarcRecord, ]; } /* -------------------------------------------------------------------------- *\ OpenAlias Builder \* -------------------------------------------------------------------------- */ /** * Generate OpenAlias TXT record * @param {string} prefix - Application prefix (e.g., "xmr", "btc") * @param {string} address - Recipient address * @param {object} [opts] - Optional key-value pairs * @param {string} [opts.name] - Recipient name * @param {string} [opts.description] - Transaction description * @param {string} [opts.amount] - Transaction amount * @param {string} [opts.paymentId] - Payment ID (e.g., for Monero) * @param {string} [opts.signature] - Address signature * @param {boolean} [opts.checksum] - Optional CRC-32 checksum * @returns {DomainModifier} TXT record */ function openalias(prefix, address, opts) { // Prefix and address are minimum requirement. // Everything else is optional. opts = opts || {}; var record = "oa1:" + prefix + " recipient_address=" + address + ";"; if (typeof opts.name === "string") record += " recipient_name=" + opts.name + ";"; if (typeof opts.description === "string") record += " tx_description=" + opts.description + ";"; if (typeof opts.amount === "string") record += " tx_amount=" + opts.amount + ";"; if (typeof opts.paymentId === "string") record += " tx_payment_id=" + opts.paymentId + ";"; if (typeof opts.signature === "string") record += " address_signature=" + opts.signature + ";"; if (opts.checksum === true) record += " checksum=" + crc32(record.trim()).toString(16).toUpperCase() + ";"; // Checksum must be last: CRC-32 of the record trimmed of surrounding spaces. return TXT("@", record, CF_COMMENT("OpenAlias > " + prefix.toUpperCase() + (opts.name ? " > " + opts.name : ""))); } /** * Calculate CRC-32 checksum of a string * Handles UTF-8 strings correctly for use with DNSControl. * @param {string} str - Input string * @returns {number} CRC-32 value * @see https://github.com/nabijaczleweli/openalias.rs/blob/master/src/crypto_addr.rs */ function crc32(str) { // 1. Generate the CRC Table var table = []; for (var i = 0; i < 256; i++) { var c = i; for (var j = 0; j < 8; j++) { c = (c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); } table[i] = c; } // 2. Convert string to UTF-8 "binary" string // This ensures characters like '€' are treated as 3 bytes, not 1. var utf8Str = unescape(encodeURIComponent(str)); // 3. Calculate CRC var crc = 0xFFFFFFFF; for (var k = 0; k < utf8Str.length; k++) { crc = table[(crc ^ utf8Str.charCodeAt(k)) & 0xFF] ^ (crc >>> 8); } return (crc ^ 0xFFFFFFFF) >>> 0; }