@certd/acme-client 1.31.8 → 1.31.10
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/package.json +3 -3
- package/src/util.js +5 -5
- package/src/verify.js +38 -25
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Simple and unopinionated ACME client",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "nmorsman",
|
|
6
|
-
"version": "1.31.
|
|
6
|
+
"version": "1.31.10",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "scr/index.js",
|
|
9
9
|
"main": "src/index.js",
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"types"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@certd/basic": "^1.31.
|
|
21
|
+
"@certd/basic": "^1.31.10",
|
|
22
22
|
"@peculiar/x509": "^1.11.0",
|
|
23
23
|
"asn1js": "^3.0.5",
|
|
24
24
|
"axios": "^1.7.2",
|
|
@@ -67,5 +67,5 @@
|
|
|
67
67
|
"bugs": {
|
|
68
68
|
"url": "https://github.com/publishlab/node-acme-client/issues"
|
|
69
69
|
},
|
|
70
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "2e30fff221c19e46e098b0dc3250a6b7c5e6a5e0"
|
|
71
71
|
}
|
package/src/util.js
CHANGED
|
@@ -219,15 +219,15 @@ function formatResponseError(resp) {
|
|
|
219
219
|
async function resolveDomainBySoaRecord(recordName) {
|
|
220
220
|
try {
|
|
221
221
|
await dns.resolveSoa(recordName);
|
|
222
|
-
log(
|
|
222
|
+
log(`找到${recordName}的SOA记录`);
|
|
223
223
|
return recordName;
|
|
224
224
|
}
|
|
225
225
|
catch (e) {
|
|
226
|
-
log(
|
|
226
|
+
log(`找不到${recordName}的SOA记录,继续往主域名查找`);
|
|
227
227
|
const parentRecordName = recordName.split('.').slice(1).join('.');
|
|
228
228
|
|
|
229
229
|
if (!parentRecordName.includes('.')) {
|
|
230
|
-
throw new Error('
|
|
230
|
+
throw new Error('SOA record查找失败');
|
|
231
231
|
}
|
|
232
232
|
|
|
233
233
|
return resolveDomainBySoaRecord(parentRecordName);
|
|
@@ -242,7 +242,7 @@ async function resolveDomainBySoaRecord(recordName) {
|
|
|
242
242
|
*/
|
|
243
243
|
|
|
244
244
|
async function getAuthoritativeDnsResolver(recordName) {
|
|
245
|
-
log(
|
|
245
|
+
log(`获取域名${recordName}的权威NS服务器: `);
|
|
246
246
|
const resolver = new dns.Resolver();
|
|
247
247
|
|
|
248
248
|
try {
|
|
@@ -250,7 +250,7 @@ async function getAuthoritativeDnsResolver(recordName) {
|
|
|
250
250
|
const domain = await resolveDomainBySoaRecord(recordName);
|
|
251
251
|
|
|
252
252
|
/* Resolve authoritative NS addresses */
|
|
253
|
-
log(
|
|
253
|
+
log(`获取到权威NS服务器name: ${domain}`);
|
|
254
254
|
const nsRecords = await dns.resolveNs(domain);
|
|
255
255
|
log(`域名权威NS服务器:${nsRecords}`);
|
|
256
256
|
const nsAddrArray = await Promise.all(nsRecords.map(async (r) => dns.resolve4(r)));
|
package/src/verify.js
CHANGED
|
@@ -48,46 +48,57 @@ async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix =
|
|
|
48
48
|
* Walk DNS until TXT records are found
|
|
49
49
|
*/
|
|
50
50
|
|
|
51
|
-
async function walkDnsChallengeRecord(recordName, resolver = dns) {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// log(`Checking name for CNAME records: ${recordName}`);
|
|
55
|
-
// const cnameRecords = await resolver.resolveCname(recordName);
|
|
56
|
-
//
|
|
57
|
-
// if (cnameRecords.length) {
|
|
58
|
-
// log(`CNAME record found at ${recordName}, new challenge record name: ${cnameRecords[0]}`);
|
|
59
|
-
// return walkDnsChallengeRecord(cnameRecords[0]);
|
|
60
|
-
// }
|
|
61
|
-
// }
|
|
62
|
-
// catch (e) {
|
|
63
|
-
// log(`No CNAME records found for name: ${recordName}`);
|
|
64
|
-
// }
|
|
51
|
+
async function walkDnsChallengeRecord(recordName, resolver = dns,deep = 0) {
|
|
52
|
+
|
|
53
|
+
let records = [];
|
|
65
54
|
|
|
66
55
|
/* Resolve TXT records */
|
|
67
56
|
try {
|
|
68
|
-
log(
|
|
57
|
+
log(`检查域名 ${recordName} 的TXT记录`);
|
|
69
58
|
const txtRecords = await resolver.resolveTxt(recordName);
|
|
70
59
|
|
|
71
60
|
if (txtRecords && txtRecords.length) {
|
|
72
|
-
log(
|
|
61
|
+
log(`找到 ${txtRecords.length} 条 TXT记录( ${recordName})`);
|
|
73
62
|
log(`TXT records: ${JSON.stringify(txtRecords)}`);
|
|
74
|
-
|
|
63
|
+
records = records.concat(...txtRecords);
|
|
75
64
|
}
|
|
76
|
-
|
|
65
|
+
} catch (e) {
|
|
66
|
+
log(`解析 TXT 记录出错, ${recordName} :${e.message}`);
|
|
77
67
|
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
68
|
+
|
|
69
|
+
/* Resolve CNAME record first */
|
|
70
|
+
try {
|
|
71
|
+
log(`检查是否存在CNAME映射: ${recordName}`);
|
|
72
|
+
const cnameRecords = await resolver.resolveCname(recordName);
|
|
73
|
+
|
|
74
|
+
if (cnameRecords.length) {
|
|
75
|
+
const cnameRecord = cnameRecords[0];
|
|
76
|
+
log(`已找到${recordName}的CNAME记录,将检查: ${cnameRecord}`);
|
|
77
|
+
let res= await walkTxtRecord(cnameRecord,deep+1);
|
|
78
|
+
if (res && res.length) {
|
|
79
|
+
log(`从CNAME中找到TXT记录: ${JSON.stringify(res)}`);
|
|
80
|
+
records = records.concat(...res);
|
|
81
|
+
}
|
|
82
|
+
}else{
|
|
83
|
+
log(`没有CNAME映射(${recordName})`);
|
|
84
|
+
}
|
|
85
|
+
} catch (e) {
|
|
86
|
+
log(`检查CNAME出错(${recordName}) :${e.message}`);
|
|
81
87
|
}
|
|
88
|
+
return records
|
|
82
89
|
}
|
|
83
90
|
|
|
84
|
-
export async function walkTxtRecord(recordName) {
|
|
91
|
+
export async function walkTxtRecord(recordName,deep = 0) {
|
|
92
|
+
if(deep >5){
|
|
93
|
+
log(`walkTxtRecord too deep (#${deep}) , skip walk`)
|
|
94
|
+
return []
|
|
95
|
+
}
|
|
85
96
|
|
|
86
97
|
const txtRecords = []
|
|
87
98
|
try {
|
|
88
99
|
/* Default DNS resolver first */
|
|
89
100
|
log('从本地DNS服务器获取TXT解析记录');
|
|
90
|
-
const res = await walkDnsChallengeRecord(recordName);
|
|
101
|
+
const res = await walkDnsChallengeRecord(recordName,null,deep);
|
|
91
102
|
if (res && res.length > 0) {
|
|
92
103
|
for (const item of res) {
|
|
93
104
|
txtRecords.push(item)
|
|
@@ -102,7 +113,7 @@ export async function walkTxtRecord(recordName) {
|
|
|
102
113
|
/* Authoritative DNS resolver */
|
|
103
114
|
log(`从域名权威服务器获取TXT解析记录`);
|
|
104
115
|
const authoritativeResolver = await util.getAuthoritativeDnsResolver(recordName);
|
|
105
|
-
const res = await walkDnsChallengeRecord(recordName, authoritativeResolver);
|
|
116
|
+
const res = await walkDnsChallengeRecord(recordName, authoritativeResolver,deep);
|
|
106
117
|
if (res && res.length > 0) {
|
|
107
118
|
for (const item of res) {
|
|
108
119
|
txtRecords.push(item)
|
|
@@ -133,7 +144,9 @@ export async function walkTxtRecord(recordName) {
|
|
|
133
144
|
async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = '_acme-challenge.') {
|
|
134
145
|
const recordName = `${prefix}${authz.identifier.value}`;
|
|
135
146
|
log(`本地校验TXT记录): ${recordName}`);
|
|
136
|
-
|
|
147
|
+
let recordValues = await walkTxtRecord(recordName);
|
|
148
|
+
//去重
|
|
149
|
+
recordValues = [...new Set(recordValues)];
|
|
137
150
|
log(`DNS查询成功, 找到 ${recordValues.length} 条TXT记录`);
|
|
138
151
|
if (!recordValues.length || !recordValues.includes(keyAuthorization)) {
|
|
139
152
|
throw new Error(`没有找到需要的DNS TXT记录: ${recordName},期望:${keyAuthorization},结果:${recordValues}`);
|