Files
DNSControl/dnsconfig.js
T
Ari 5afb9f48f5 feat(openalias): add BTC, ETH, and LTC OpenAlias records
Extends OpenAlias configuration with Bitcoin, Ethereum, and Litecoin donation addresses alongside the existing Monero entry.

Also tightens the openalias() helper to use strict type checks.
2026-03-22 17:41:49 -04:00

294 lines
12 KiB
JavaScript

// @ts-check
/// <reference path="types-dnscontrol.d.ts" />
var REG_101DOMAIN = NewRegistrar("none");
var DNS_CLOUDFLARE = NewDnsProvider("cloudflare");
/* ****************************************************************************************************************** *\
Defaults & Common Records
\* ****************************************************************************************************************** */
var rexbox = "rexbox.prm.achl.fr.";
var rexcloud = "rexcloud.cld.achl.fr.";
var reportEmail = "mailto:0acbbb8a-1558-419a-ab2d-3f2773a1247d@arirex.email";
var dmarcRecord = DMARC_BUILDER({
policy: "reject",
subdomainPolicy: "reject",
alignmentDKIM: "strict",
alignmentSPF: "strict",
rua: [reportEmail],
ruf: [reportEmail],
percent: 100,
failureOptions: "1",
});
DEFAULTS(
DnsProvider(DNS_CLOUDFLARE),
DefaultTTL(1),
CF_MANAGE_COMMENTS, // opt into comments syncing
CAA_BUILDER({
iodef: reportEmail,
iodef_critical: true,
issue: ["letsencrypt.org"],
issue_critical: true,
issuewild: ["letsencrypt.org"],
issuewild_critical: true,
issuevmc: "none",
issuevmc_critical: true,
issuemail: "none",
issuemail_critical: true,
}),
);
/* ****************************************************************************************************************** *\
Managed Domains
\* ****************************************************************************************************************** */
/* -------------------------------------------------------------------------- *\
Primary Domains
\* -------------------------------------------------------------------------- */
D("arirex.me", REG_101DOMAIN,
ALIAS("@", rexbox),
protonmail("6fd60590dc31588ca5a85c7e311649ff5f93cab2", "dodai2qaszneyk5jeyfloq24ttjcqfer2gdopw3nfmxn3bugtw2hq"),
// Verifications
TXT("_discord", "dh=1c93b7effbe0bf428cb55d33175c2721ef715bb6", CF_COMMENT("Discord Verify")),
TXT("_atproto", "did=did:plc:53kf45pcsqgayjmoau42lhsk", CF_COMMENT("BlueSky Verify")),
TXT("_github-pages-challenge-arirexouium", "0b62c2fb7a8422145d5b5e6637257d", CF_COMMENT("GitHub Pages Verify")),
// OpenAlias
openalias("xmr", "89dQNyY3E9gJGYrEeRw4EFAdezWQg7BBbHJdBpLRwrjH52ngNfAYRcEhAHQotCswGxTeSoFi5nQ7Gf86kySmXzuQE9CXjUH", { name: "AriRexouium", checksum: true, }),
openalias("btc", "3DQEYUDquSvh6DX54o2Gw1TXT9ZGWWoRTh", { name: "AriRexouium", checksum: true, }),
openalias("eth", "0x3489c73A2F3DE6236624d43a3767f4dB8181d0c4", { name: "AriRexouium", checksum: true, }),
openalias("ltc", "Lg6sV5PfRrBvpQoAzsyCcWMs26aq5VBssS", { name: "AriRexouium", checksum: true, }),
);
D("achl.fr", REG_101DOMAIN,
ALIAS("@", rexbox),
protonmail("a5142b961ee71079de475ab173095ae7a8497159", "dptdmdzwbeybqhgo544aqzi6w7vqiojzxbbm6hoev3nni5kewj4ga"),
// On-prem & Cloud Servers
IGNORE("rexbox.prm", "A"), // Managed by qmcgaw/ddns-updater
A("rexcloud.cld", "5.161.231.128"),
AAAA("rexcloud.cld", "2a01:4ff:f0:e504::"),
// Verifications
TXT("_discord", "dh=d041188169640d1f23c6b379d97935981a7a07da", CF_COMMENT("Discord Verify")),
TXT("_github-pages-challenge-arirexouium", "134234f292827135d74e0637efc575", CF_COMMENT("GitHub Pages Verify")),
);
/* -------------------------------------------------------------------------- *\
Email Proxy Domains
\* -------------------------------------------------------------------------- */
D("arirex.email", REG_101DOMAIN,
simplelogin("ngmfowygibangqmiobjznfmjhxniyi"),
);
D("achlfr.email", REG_101DOMAIN,
simplelogin("rsykypqtapcymkryscyoajdlajvqmx"),
);
/* ****************************************************************************************************************** *\
Service Records
\* ****************************************************************************************************************** */
/* -------------------------------------------------------------------------- *\
RexBox Services
\* -------------------------------------------------------------------------- */
cnames("arirex.me", rexbox, [
"Chhoto URL@l",
"Enclosed@bin",
"IT Tools@it",
"Karakeep@karakeep",
"Matrix > Client@chat",
"Matrix > Server@matrix",
"Ntfy@ntfy",
"OpenWebUI@ai",
"Pocket ID@id",
"Traefik@traefik",
"Traefik Forward Auth@auth",
]);
cnames("achl.fr", rexbox, [
"Matrix > Client@chat",
"Matrix > Server@matrix",
]);
minecraft("Frantic", "frantic.mc", "arirex.me", 63548);
minecraft("The Furry Cult", "thefurrycult.mc", "arirex.me", 54924);
/* -------------------------------------------------------------------------- *\
RexCloud Services
\* -------------------------------------------------------------------------- */
cnames("arirex.me", rexcloud, [
"Beszel@beszel",
"Gitea@git",
// "IPFS Subdomain Gateway@*.ipfs.gw",
// "IPFS Subdomain Gateway@*.ipns.gw",
// "IPFS Path Gateway@gw",
"SearXNG@search",
]);
/* -------------------------------------------------------------------------- *\
Media Server
\* -------------------------------------------------------------------------- */
[
"qBittorrent", // Downloader
"Jellyfin", "Jellyseerr", // Provider & Requester
"Prowlarr", "Profilarr", // Synchronization
"Radarr", "Sonarr", "Lidarr", // Movies, Shows, Music
].forEach(function(i) {
D_EXTEND("arirex.me",
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;
}