caa 11.0.0 → 11.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +60 -111
- package/package.json +19 -16
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# caa
|
|
2
2
|
[](https://www.npmjs.org/package/caa) [](https://www.npmjs.org/package/caa) [](https://packagephobia.com/result?p=caa)
|
|
3
3
|
|
|
4
|
-
> [
|
|
4
|
+
> [rfc8659](https://www.rfc-editor.org/rfc/rfc8659)-conform CAA record lookup and validation
|
|
5
5
|
|
|
6
6
|
## Usage
|
|
7
7
|
|
package/dist/index.d.ts
CHANGED
|
@@ -7,13 +7,12 @@ type CaaOpts = {
|
|
|
7
7
|
servers?: Array<string>;
|
|
8
8
|
dnsSocket?: any;
|
|
9
9
|
};
|
|
10
|
-
type CaaRecord = {
|
|
10
|
+
export type CaaRecord = {
|
|
11
11
|
flags: number;
|
|
12
12
|
tag: string;
|
|
13
13
|
value: string;
|
|
14
14
|
issuerCritical: boolean;
|
|
15
15
|
};
|
|
16
|
-
declare function caa(name: string, opts?: CaaOpts): Promise<Array<CaaRecord>>;
|
|
17
|
-
declare function caaMatches(name: string, ca: string, opts?: CaaOpts): Promise<boolean>;
|
|
18
|
-
//#endregion
|
|
19
|
-
export { CaaRecord, caa, caaMatches };
|
|
16
|
+
export declare function caa(name: string, opts?: CaaOpts): Promise<Array<CaaRecord>>;
|
|
17
|
+
export declare function caaMatches(name: string, ca: string, opts?: CaaOpts): Promise<boolean>;
|
|
18
|
+
//#endregion
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getServers } from "node:dns";
|
|
2
2
|
import { promisify } from "node:util";
|
|
3
|
+
import { domainToASCII } from "node:url";
|
|
3
4
|
import dnsSocket from "dns-socket";
|
|
4
5
|
|
|
5
6
|
//#region node_modules/.pnpm/tlds@1.261.0/node_modules/tlds/index.json
|
|
@@ -1451,130 +1452,78 @@ const defaults = {
|
|
|
1451
1452
|
recursions: 50,
|
|
1452
1453
|
retries: 12,
|
|
1453
1454
|
port: 53,
|
|
1454
|
-
servers: ["8.8.8.8", "8.8.4.4"]
|
|
1455
|
-
dnsSocket: void 0
|
|
1455
|
+
servers: ["8.8.8.8", "8.8.4.4"]
|
|
1456
1456
|
};
|
|
1457
1457
|
const tldSet = new Set(tlds_default);
|
|
1458
|
+
const knownTags = /* @__PURE__ */ new Set([
|
|
1459
|
+
"issue",
|
|
1460
|
+
"issuewild",
|
|
1461
|
+
"iodef",
|
|
1462
|
+
"contactemail",
|
|
1463
|
+
"contactphone",
|
|
1464
|
+
"accounturi",
|
|
1465
|
+
"validationmethods"
|
|
1466
|
+
]);
|
|
1467
|
+
const okRcodes = /* @__PURE__ */ new Set(["NXDOMAIN", "NOERROR"]);
|
|
1458
1468
|
const isTLD = (name) => tldSet.has(name);
|
|
1459
|
-
const isWildcard = (name) => name.
|
|
1460
|
-
const parent = (name) => name.split(".").
|
|
1461
|
-
function selectServer(servers, retries, tries) {
|
|
1462
|
-
return servers[(tries - retries) % servers.length];
|
|
1463
|
-
}
|
|
1469
|
+
const isWildcard = (name) => name.startsWith("*.");
|
|
1470
|
+
const parent = (name) => name.split(".").slice(1).join(".");
|
|
1464
1471
|
function normalizeName(name = "") {
|
|
1465
|
-
|
|
1466
|
-
|
|
1472
|
+
const wildcard = isWildcard(name);
|
|
1473
|
+
const base = wildcard ? name.slice(2) : name;
|
|
1474
|
+
let ascii = domainToASCII(base) || base.toLowerCase();
|
|
1475
|
+
if (ascii.endsWith(".") && ascii.length > 1) ascii = ascii.slice(0, -1);
|
|
1476
|
+
return wildcard ? `*.${ascii}` : ascii;
|
|
1467
1477
|
}
|
|
1468
|
-
const resolve = async ({ name, query, servers, port, recursions, retries, tries, ignoreTLDs }) => {
|
|
1469
|
-
name = normalizeName(name);
|
|
1470
|
-
if (!name) return [];
|
|
1471
|
-
if (ignoreTLDs && isTLD(name)) return [];
|
|
1472
|
-
if (recursions <= 0 || retries <= 0) return [];
|
|
1473
|
-
name = name.replace(/^\*\./, "");
|
|
1474
|
-
let res;
|
|
1475
|
-
try {
|
|
1476
|
-
res = await query({ questions: [{
|
|
1477
|
-
name,
|
|
1478
|
-
type: "CAA"
|
|
1479
|
-
}] }, port, selectServer(servers, retries, tries));
|
|
1480
|
-
} catch {
|
|
1481
|
-
if (retries <= 0) return [];
|
|
1482
|
-
retries -= 1;
|
|
1483
|
-
return await resolve({
|
|
1484
|
-
name,
|
|
1485
|
-
query,
|
|
1486
|
-
servers,
|
|
1487
|
-
port,
|
|
1488
|
-
recursions,
|
|
1489
|
-
retries,
|
|
1490
|
-
tries,
|
|
1491
|
-
ignoreTLDs
|
|
1492
|
-
});
|
|
1493
|
-
}
|
|
1494
|
-
if (!res || !res.answers && !["NXDOMAIN", "NOERROR"].includes(res.rcode)) {
|
|
1495
|
-
if (retries <= 0) return [];
|
|
1496
|
-
retries -= 1;
|
|
1497
|
-
return await resolve({
|
|
1498
|
-
name,
|
|
1499
|
-
query,
|
|
1500
|
-
servers,
|
|
1501
|
-
port,
|
|
1502
|
-
recursions,
|
|
1503
|
-
retries,
|
|
1504
|
-
tries,
|
|
1505
|
-
ignoreTLDs
|
|
1506
|
-
});
|
|
1507
|
-
}
|
|
1508
|
-
const records = {};
|
|
1509
|
-
if (res?.answers?.length) for (const { name, type, data } of res.answers || {}) {
|
|
1510
|
-
if (!name || !type || !data) continue;
|
|
1511
|
-
if (!records[type]) records[type] = [];
|
|
1512
|
-
records[type].push({
|
|
1513
|
-
name,
|
|
1514
|
-
data
|
|
1515
|
-
});
|
|
1516
|
-
}
|
|
1517
|
-
if (records.CAA?.length) {
|
|
1518
|
-
const caas = records.CAA.filter((record) => record.name === name).map((record) => record.data);
|
|
1519
|
-
if (caas.length) return caas;
|
|
1520
|
-
}
|
|
1521
|
-
let alias;
|
|
1522
|
-
if (records.CNAME?.length) {
|
|
1523
|
-
const dest = records.CNAME.find((record) => record.name === name);
|
|
1524
|
-
if (dest) alias = dest.data;
|
|
1525
|
-
} else if (records.DNAME?.length) {
|
|
1526
|
-
const dest = records.DNAME.find((record) => record.name === name);
|
|
1527
|
-
if (dest) alias = name.replace(dest.name, dest.data);
|
|
1528
|
-
}
|
|
1529
|
-
if (alias && records.CAA?.length) return records.CAA.filter((record) => record.name === alias && record.data).map((record) => record.data);
|
|
1530
|
-
if (!isTLD(name)) {
|
|
1531
|
-
recursions -= 1;
|
|
1532
|
-
return await resolve({
|
|
1533
|
-
name: parent(name),
|
|
1534
|
-
query,
|
|
1535
|
-
servers,
|
|
1536
|
-
port,
|
|
1537
|
-
recursions,
|
|
1538
|
-
retries,
|
|
1539
|
-
tries,
|
|
1540
|
-
ignoreTLDs
|
|
1541
|
-
});
|
|
1542
|
-
} else return [];
|
|
1543
|
-
};
|
|
1544
1478
|
async function caa(name, opts = {}) {
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1479
|
+
const ignoreTLDs = opts.ignoreTLDs ?? defaults.ignoreTLDs;
|
|
1480
|
+
const recursions = opts.recursions ?? defaults.recursions;
|
|
1481
|
+
const retries = opts.retries ?? defaults.retries;
|
|
1482
|
+
const port = opts.port ?? defaults.port;
|
|
1483
|
+
let servers;
|
|
1484
|
+
if (opts.servers?.length) servers = opts.servers;
|
|
1485
|
+
else {
|
|
1486
|
+
const sys = getServers();
|
|
1487
|
+
servers = sys.length ? sys : defaults.servers;
|
|
1549
1488
|
}
|
|
1550
|
-
opts = {
|
|
1551
|
-
...defaults,
|
|
1552
|
-
...opts
|
|
1553
|
-
};
|
|
1554
1489
|
const socket = opts.dnsSocket || dnsSocket();
|
|
1555
1490
|
const query = promisify(socket.query.bind(socket));
|
|
1556
|
-
const
|
|
1557
|
-
name
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1491
|
+
const climb = async (name, recursionsLeft, retriesLeft) => {
|
|
1492
|
+
if (!name) return [];
|
|
1493
|
+
if (ignoreTLDs && isTLD(name)) return [];
|
|
1494
|
+
if (recursionsLeft <= 0 || retriesLeft <= 0) return [];
|
|
1495
|
+
const server = servers[(retries - retriesLeft) % servers.length];
|
|
1496
|
+
let res;
|
|
1497
|
+
try {
|
|
1498
|
+
res = await query({ questions: [{
|
|
1499
|
+
name,
|
|
1500
|
+
type: "CAA"
|
|
1501
|
+
}] }, port, server);
|
|
1502
|
+
} catch {
|
|
1503
|
+
res = null;
|
|
1504
|
+
}
|
|
1505
|
+
if (!res || !res.answers && !okRcodes.has(res.rcode)) return climb(name, recursionsLeft, retriesLeft - 1);
|
|
1506
|
+
const caas = [];
|
|
1507
|
+
for (const ans of res.answers || []) if (ans?.type === "CAA" && ans.data) caas.push(ans.data);
|
|
1508
|
+
if (caas.length) return caas;
|
|
1509
|
+
if (isTLD(name)) return [];
|
|
1510
|
+
return climb(parent(name), recursionsLeft - 1, retriesLeft);
|
|
1511
|
+
};
|
|
1512
|
+
const result = await climb(normalizeName(name).replace(/^\*\./, ""), recursions, retries);
|
|
1566
1513
|
if (!opts.dnsSocket) socket.destroy();
|
|
1567
|
-
return
|
|
1514
|
+
return result;
|
|
1568
1515
|
}
|
|
1569
1516
|
async function caaMatches(name, ca, opts = {}) {
|
|
1570
|
-
|
|
1517
|
+
const wildcard = isWildcard(name);
|
|
1571
1518
|
ca = normalizeName(ca);
|
|
1572
|
-
const
|
|
1573
|
-
if (!
|
|
1574
|
-
|
|
1575
|
-
const
|
|
1576
|
-
const
|
|
1577
|
-
if (
|
|
1519
|
+
const records = await caa(name, opts);
|
|
1520
|
+
if (!records.length) return true;
|
|
1521
|
+
if (records.some((r) => r.issuerCritical && !knownTags.has(r.tag))) return false;
|
|
1522
|
+
const issueNames = [];
|
|
1523
|
+
const issueWildNames = [];
|
|
1524
|
+
for (const r of records) if (r.tag === "issue") issueNames.push(normalizeName(r.value.split(";")[0].trim()));
|
|
1525
|
+
else if (r.tag === "issuewild") issueWildNames.push(normalizeName(r.value.split(";")[0].trim()));
|
|
1526
|
+
const names = wildcard && issueWildNames.length ? issueWildNames : issueNames;
|
|
1578
1527
|
return !names.length || names.includes(ca);
|
|
1579
1528
|
}
|
|
1580
1529
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "caa",
|
|
3
|
-
"version": "11.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "11.0.2",
|
|
4
|
+
"description": "rfc8659-conform CAA record lookup and validation",
|
|
5
5
|
"author": "silverwind <me@silverwind.io>",
|
|
6
|
-
"repository":
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/silverwind/caa.git"
|
|
9
|
+
},
|
|
7
10
|
"license": "BSD-2-Clause",
|
|
8
11
|
"type": "module",
|
|
9
12
|
"sideEffects": false,
|
|
@@ -20,20 +23,20 @@
|
|
|
20
23
|
"dns-socket": "^4.2.2"
|
|
21
24
|
},
|
|
22
25
|
"devDependencies": {
|
|
23
|
-
"@types/node": "
|
|
24
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
25
|
-
"eslint": "
|
|
26
|
-
"eslint-config-silverwind": "
|
|
26
|
+
"@types/node": "26.6.2",
|
|
27
|
+
"@typescript/native-preview": "7.0.0-dev.20260707.2",
|
|
28
|
+
"eslint": "10.11.0",
|
|
29
|
+
"eslint-config-silverwind": "151.0.0",
|
|
27
30
|
"jest-extended": "7.0.0",
|
|
28
31
|
"tlds": "1.261.0",
|
|
29
|
-
"tsdown": "0.
|
|
30
|
-
"tsdown-config-silverwind": "
|
|
31
|
-
"typescript": "6.0.
|
|
32
|
-
"typescript-config-silverwind": "
|
|
33
|
-
"updates": "
|
|
34
|
-
"updates-config-silverwind": "
|
|
35
|
-
"versions": "15.
|
|
36
|
-
"vitest": "
|
|
37
|
-
"vitest-config-silverwind": "
|
|
32
|
+
"tsdown": "0.23.0",
|
|
33
|
+
"tsdown-config-silverwind": "4.1.1",
|
|
34
|
+
"typescript": "6.0.3",
|
|
35
|
+
"typescript-config-silverwind": "21.0.0",
|
|
36
|
+
"updates": "19.0.0",
|
|
37
|
+
"updates-config-silverwind": "4.0.6",
|
|
38
|
+
"versions": "15.5.0",
|
|
39
|
+
"vitest": "5.0.2",
|
|
40
|
+
"vitest-config-silverwind": "12.0.4"
|
|
38
41
|
}
|
|
39
42
|
}
|