diff --git a/dnsconfig.js b/dnsconfig.js index c0f2396..30372bb 100644 --- a/dnsconfig.js +++ b/dnsconfig.js @@ -1,6 +1,8 @@ // @ts-check /// +require("./helpers.js"); + var REG_101DOMAIN = NewRegistrar("none"); var DNS_CLOUDFLARE = NewDnsProvider("cloudflare"); @@ -141,153 +143,3 @@ cnames("arirex.me", rexcloud, [ CNAME(i.toLowerCase() + ".servarr", rexbox, CF_COMMENT(i)) ); }); - -/* ****************************************************************************************************************** *\ - 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; -} diff --git a/helpers.js b/helpers.js new file mode 100644 index 0000000..07d2657 --- /dev/null +++ b/helpers.js @@ -0,0 +1,152 @@ +/* ****************************************************************************************************************** *\ + 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; +}