@certd/acme-client 1.39.11 → 1.39.13
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/dist/api.d.ts +151 -0
- package/{src → dist}/api.js +2 -38
- package/dist/auto.d.ts +9 -0
- package/{src → dist}/auto.js +45 -79
- package/dist/axios.d.ts +8 -0
- package/{src → dist}/axios.js +3 -31
- package/dist/client.d.ts +396 -0
- package/{src → dist}/client.js +16 -108
- package/dist/crypto/forge.d.ts +174 -0
- package/{src → dist}/crypto/forge.js +7 -63
- package/dist/crypto/index.d.ts +215 -0
- package/{src → dist}/crypto/index.js +2 -87
- package/dist/error.d.ts +3 -0
- package/{src → dist}/error.js +1 -3
- package/dist/http.d.ts +135 -0
- package/{src → dist}/http.js +3 -65
- package/dist/index.d.ts +58 -0
- package/dist/index.js +90 -0
- package/dist/logger.d.ts +15 -0
- package/{src → dist}/logger.js +4 -9
- package/dist/rfc8555.d.ts +106 -0
- package/dist/rfc8555.js +25 -0
- package/dist/types.d.ts +117 -0
- package/dist/types.js +1 -0
- package/dist/util.d.ts +85 -0
- package/{src → dist}/util.js +11 -76
- package/dist/verify.d.ts +14 -0
- package/dist/verify.js +214 -0
- package/dist/wait.d.ts +1 -0
- package/{src → dist}/wait.js +1 -0
- package/package.json +18 -12
- package/types/index.d.ts +15 -4
- package/types/index.test-d.ts +10 -3
- package/src/index.js +0 -106
- package/src/verify.js +0 -231
package/dist/verify.js
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
/**
|
|
3
|
+
* ACME challenge verification
|
|
4
|
+
*/
|
|
5
|
+
import dnsSdk from "dns";
|
|
6
|
+
import https from 'https';
|
|
7
|
+
import { log as defaultLog } from './logger.js';
|
|
8
|
+
import axios from './axios.js';
|
|
9
|
+
import * as util from './util.js';
|
|
10
|
+
import { isAlpnCertificateAuthorizationValid } from './crypto/index.js';
|
|
11
|
+
import { utils } from '@certd/basic';
|
|
12
|
+
const dns = dnsSdk.promises;
|
|
13
|
+
let walkFromAuthoritative = true;
|
|
14
|
+
export function setWalkFromAuthoritative(value = true) {
|
|
15
|
+
walkFromAuthoritative = value;
|
|
16
|
+
}
|
|
17
|
+
export function createChallengeFn(opts = {}) {
|
|
18
|
+
const logger = opts?.logger || { info: defaultLog, error: defaultLog, warn: defaultLog, debug: defaultLog };
|
|
19
|
+
const log = function (...args) {
|
|
20
|
+
logger.info(...args);
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Verify ACME HTTP challenge
|
|
24
|
+
*
|
|
25
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.3
|
|
26
|
+
*
|
|
27
|
+
* @param {object} authz Identifier authorization
|
|
28
|
+
* @param {object} challenge Authorization challenge
|
|
29
|
+
* @param {string} keyAuthorization Challenge key authorization
|
|
30
|
+
* @param {string} [suffix] URL suffix
|
|
31
|
+
* @returns {Promise<boolean>}
|
|
32
|
+
*/
|
|
33
|
+
async function verifyHttpChallenge(authz, challenge, keyAuthorization, suffix = `/.well-known/acme-challenge/${challenge.token}`) {
|
|
34
|
+
async function doQuery(challengeUrl) {
|
|
35
|
+
log(`正在测试请求 ${challengeUrl} `);
|
|
36
|
+
// const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
|
37
|
+
// const challengeUrl = `https://${authz.identifier.value}:${httpsPort}${suffix}`;
|
|
38
|
+
/* May redirect to HTTPS with invalid/self-signed cert - https://letsencrypt.org/docs/challenge-types/#http-01-challenge */
|
|
39
|
+
const httpsAgent = new https.Agent({ rejectUnauthorized: false });
|
|
40
|
+
log(`Sending HTTP query to ${authz.identifier.value}, suffix: ${suffix}, port: ${httpPort}`);
|
|
41
|
+
let data = "";
|
|
42
|
+
try {
|
|
43
|
+
const resp = await axios.get(challengeUrl, { httpsAgent });
|
|
44
|
+
data = (resp.data || '').replace(/\s+$/, '');
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
log(`[error] HTTP request error from ${authz.identifier.value}`, e.message);
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
if (!data || (data !== keyAuthorization)) {
|
|
51
|
+
log(`[error] Authorization not found in HTTP response from ${authz.identifier.value}`);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
return true;
|
|
55
|
+
}
|
|
56
|
+
const httpPort = axios.defaults.acmeSettings.httpChallengePort || 80;
|
|
57
|
+
let host = authz.identifier.value;
|
|
58
|
+
if (utils.domain.isIpv6(host)) {
|
|
59
|
+
host = `[${host}]`;
|
|
60
|
+
}
|
|
61
|
+
const challengeUrl = `http://${host}:${httpPort}${suffix}`;
|
|
62
|
+
if (!await doQuery(challengeUrl)) {
|
|
63
|
+
const httpsPort = axios.defaults.acmeSettings.httpsChallengePort || 443;
|
|
64
|
+
const httpsChallengeUrl = `https://${host}:${httpsPort}${suffix}`;
|
|
65
|
+
const res = await doQuery(httpsChallengeUrl);
|
|
66
|
+
if (!res) {
|
|
67
|
+
throw new Error(`[error] 验证失败,请检查以上测试url是否可以正常访问`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
log(`Key authorization match for ${challenge.type}/${authz.identifier.value}, ACME challenge verified`);
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Walk DNS until TXT records are found
|
|
75
|
+
*/
|
|
76
|
+
async function walkDnsChallengeRecord(recordName, resolver = dns, deep = 0) {
|
|
77
|
+
let records = [];
|
|
78
|
+
const isAuthoritative = resolver === dns;
|
|
79
|
+
/* Resolve TXT records */
|
|
80
|
+
try {
|
|
81
|
+
log(`检查域名 ${recordName} 的TXT记录(from ${isAuthoritative ? '本地DNS' : '权威DNS服务器'})`);
|
|
82
|
+
const txtRecords = await resolver.resolveTxt(recordName);
|
|
83
|
+
if (txtRecords && txtRecords.length) {
|
|
84
|
+
log(`找到 ${txtRecords.length} 条 TXT记录( ${recordName})`);
|
|
85
|
+
log(`TXT records: ${JSON.stringify(txtRecords)}`);
|
|
86
|
+
records = records.concat(...txtRecords);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
90
|
+
log(`解析 TXT 记录出错, ${recordName} :${e.message}`);
|
|
91
|
+
}
|
|
92
|
+
/* Resolve CNAME record first */
|
|
93
|
+
try {
|
|
94
|
+
log(`检查是否存在CNAME映射: ${recordName}`);
|
|
95
|
+
const cnameRecords = await resolver.resolveCname(recordName);
|
|
96
|
+
if (cnameRecords.length) {
|
|
97
|
+
const cnameRecord = cnameRecords[0];
|
|
98
|
+
log(`已找到${recordName}的CNAME记录,将检查: ${cnameRecord}`);
|
|
99
|
+
let res = await walkTxtRecord(cnameRecord, deep + 1);
|
|
100
|
+
if (res && res.length) {
|
|
101
|
+
log(`从CNAME中找到TXT记录: ${JSON.stringify(res)}`);
|
|
102
|
+
records = records.concat(...res);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
log(`没有CNAME映射(${recordName})`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (e) {
|
|
110
|
+
log(`检查CNAME出错(${recordName}) :${e.message}`);
|
|
111
|
+
}
|
|
112
|
+
return records;
|
|
113
|
+
}
|
|
114
|
+
async function walkTxtRecord(recordName, deep = 0) {
|
|
115
|
+
if (deep > 5) {
|
|
116
|
+
log(`walkTxtRecord too deep (#${deep}) , skip walk`);
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
const txtRecords = [];
|
|
120
|
+
try {
|
|
121
|
+
/* Default DNS resolver first */
|
|
122
|
+
log('从本地DNS服务器获取TXT解析记录');
|
|
123
|
+
const res = await walkDnsChallengeRecord(recordName, dns, deep);
|
|
124
|
+
if (res && res.length > 0) {
|
|
125
|
+
for (const item of res) {
|
|
126
|
+
txtRecords.push(item);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (e) {
|
|
131
|
+
log(`本地获取TXT解析记录失败:${e.message}`);
|
|
132
|
+
}
|
|
133
|
+
if (walkFromAuthoritative !== false) {
|
|
134
|
+
try {
|
|
135
|
+
/* Authoritative DNS resolver */
|
|
136
|
+
log(`从域名权威服务器获取TXT解析记录`);
|
|
137
|
+
const authoritativeResolver = await util.getAuthoritativeDnsResolver(recordName, log);
|
|
138
|
+
const res = await walkDnsChallengeRecord(recordName, authoritativeResolver, deep);
|
|
139
|
+
if (res && res.length > 0) {
|
|
140
|
+
for (const item of res) {
|
|
141
|
+
txtRecords.push(item);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
log(`权威服务器获取TXT解析记录失败:${e.message}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
log(`跳过从权威服务器获取TXT解析记录`);
|
|
151
|
+
}
|
|
152
|
+
if (txtRecords.length === 0) {
|
|
153
|
+
throw new Error(`没有找到TXT解析记录(${recordName})`);
|
|
154
|
+
}
|
|
155
|
+
return txtRecords;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Verify ACME DNS challenge
|
|
159
|
+
*
|
|
160
|
+
* https://datatracker.ietf.org/doc/html/rfc8555#section-8.4
|
|
161
|
+
*
|
|
162
|
+
* @param {object} authz Identifier authorization
|
|
163
|
+
* @param {object} challenge Authorization challenge
|
|
164
|
+
* @param {string} keyAuthorization Challenge key authorization
|
|
165
|
+
* @param {string} [prefix] DNS prefix
|
|
166
|
+
* @returns {Promise<boolean>}
|
|
167
|
+
*/
|
|
168
|
+
async function verifyDnsChallenge(authz, challenge, keyAuthorization, prefix = '_acme-challenge.') {
|
|
169
|
+
const recordName = `${prefix}${authz.identifier.value}`;
|
|
170
|
+
log(`本地校验TXT记录): ${recordName}`);
|
|
171
|
+
let recordValues = await walkTxtRecord(recordName, 0, walkFromAuthoritative);
|
|
172
|
+
//去重
|
|
173
|
+
recordValues = [...new Set(recordValues)];
|
|
174
|
+
log(`DNS查询成功, 找到 ${recordValues.length} 条TXT记录:${recordValues}`);
|
|
175
|
+
if (!recordValues.length || !recordValues.includes(keyAuthorization)) {
|
|
176
|
+
const err = `没有找到需要的DNS TXT记录: ${recordName},期望:${keyAuthorization},结果:${recordValues}`;
|
|
177
|
+
throw new Error(err);
|
|
178
|
+
}
|
|
179
|
+
log(`关键授权匹配成功(${challenge.type}/${recordName}):${keyAuthorization},校验成功, ACME challenge verified`);
|
|
180
|
+
return true;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Verify ACME TLS ALPN challenge
|
|
184
|
+
*
|
|
185
|
+
* https://datatracker.ietf.org/doc/html/rfc8737
|
|
186
|
+
*
|
|
187
|
+
* @param {object} authz Identifier authorization
|
|
188
|
+
* @param {object} challenge Authorization challenge
|
|
189
|
+
* @param {string} keyAuthorization Challenge key authorization
|
|
190
|
+
* @returns {Promise<boolean>}
|
|
191
|
+
*/
|
|
192
|
+
async function verifyTlsAlpnChallenge(authz, challenge, keyAuthorization) {
|
|
193
|
+
const tlsAlpnPort = axios.defaults.acmeSettings.tlsAlpnChallengePort || 443;
|
|
194
|
+
const host = authz.identifier.value;
|
|
195
|
+
log(`Establishing TLS connection with host: ${host}:${tlsAlpnPort}`);
|
|
196
|
+
const certificate = await util.retrieveTlsAlpnCertificate(host, tlsAlpnPort);
|
|
197
|
+
log('Certificate received from server successfully, matching key authorization in ALPN');
|
|
198
|
+
if (!isAlpnCertificateAuthorizationValid(certificate, keyAuthorization)) {
|
|
199
|
+
throw new Error(`Authorization not found in certificate from ${authz.identifier.value}`);
|
|
200
|
+
}
|
|
201
|
+
log(`Key authorization match for ${challenge.type}/${authz.identifier.value}, ACME challenge verified`);
|
|
202
|
+
return true;
|
|
203
|
+
}
|
|
204
|
+
return {
|
|
205
|
+
challenges: {
|
|
206
|
+
'http-01': verifyHttpChallenge,
|
|
207
|
+
'dns-01': verifyDnsChallenge,
|
|
208
|
+
'tls-alpn-01': verifyTlsAlpnChallenge,
|
|
209
|
+
},
|
|
210
|
+
walkTxtRecord,
|
|
211
|
+
walkDnsChallengeRecord,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
// createChallengeFn({logger:{info:console.log}}).walkDnsChallengeRecord("handsfree.work")
|
package/dist/wait.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function wait(ms: any): Promise<unknown>;
|
package/{src → dist}/wait.js
RENAMED
package/package.json
CHANGED
|
@@ -3,22 +3,22 @@
|
|
|
3
3
|
"description": "Simple and unopinionated ACME client",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "nmorsman",
|
|
6
|
-
"version": "1.39.
|
|
6
|
+
"version": "1.39.13",
|
|
7
7
|
"type": "module",
|
|
8
|
-
"module": "
|
|
9
|
-
"main": "
|
|
10
|
-
"types": "
|
|
8
|
+
"module": "./dist/index.js",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
11
|
"license": "MIT",
|
|
12
12
|
"homepage": "https://github.com/publishlab/node-acme-client",
|
|
13
13
|
"engines": {
|
|
14
14
|
"node": ">= 18"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"
|
|
17
|
+
"dist",
|
|
18
18
|
"types"
|
|
19
19
|
],
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@certd/basic": "^1.39.
|
|
21
|
+
"@certd/basic": "^1.39.13",
|
|
22
22
|
"@peculiar/x509": "^1.11.0",
|
|
23
23
|
"asn1js": "^3.0.5",
|
|
24
24
|
"axios": "^1.9.0",
|
|
@@ -35,10 +35,12 @@
|
|
|
35
35
|
"@typescript-eslint/parser": "^8.26.1",
|
|
36
36
|
"chai": "^4.4.1",
|
|
37
37
|
"chai-as-promised": "^7.1.2",
|
|
38
|
+
"cross-env": "^7.0.3",
|
|
38
39
|
"eslint": "^8.57.0",
|
|
39
40
|
"eslint-config-prettier": "^8.5.0",
|
|
40
41
|
"eslint-plugin-import": "^2.29.1",
|
|
41
42
|
"eslint-plugin-prettier": "^4.2.1",
|
|
43
|
+
"esmock": "^2.7.5",
|
|
42
44
|
"jsdoc-to-markdown": "^8.0.1",
|
|
43
45
|
"mocha": "^10.6.0",
|
|
44
46
|
"nock": "^13.5.4",
|
|
@@ -47,13 +49,17 @@
|
|
|
47
49
|
"typescript": "^5.4.2"
|
|
48
50
|
},
|
|
49
51
|
"scripts": {
|
|
50
|
-
"build
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
52
|
+
"before-build": "node -e \"const fs=require('fs');fs.rmSync('dist',{recursive:true,force:true});fs.rmSync('tsconfig.tsbuildinfo',{force:true});\"",
|
|
53
|
+
"build": "npm run before-build && tsc --skipLibCheck",
|
|
54
|
+
"build-docs": "jsdoc2md dist/client.js > docs/client.md && jsdoc2md dist/crypto/index.js > docs/crypto.md && jsdoc2md dist/crypto/forge.js > docs/forge.md",
|
|
55
|
+
"lint": "eslint \"src/**/*.ts\" \"types/**/*.ts\"",
|
|
56
|
+
"lint-types": "tsd --files \"types/index.test-d.ts\"",
|
|
57
|
+
"prepublishOnly": "npm run build && npm run build-docs",
|
|
54
58
|
"test": "mocha -t 60000 \"test/setup.js\" \"test/**/*.spec.js\"",
|
|
59
|
+
"before-test:unit": "node -e \"const fs=require('fs');fs.rmSync('dist-test',{recursive:true,force:true});fs.rmSync('tsconfig.test.tsbuildinfo',{force:true});\"",
|
|
60
|
+
"test:unit": "cross-env NODE_ENV=unittest npm run before-test:unit && cross-env NODE_ENV=unittest tsc -p tsconfig.test.json --skipLibCheck && cross-env NODE_ENV=unittest mocha -t 60000 \"dist-test/**/*.test.js\"",
|
|
55
61
|
"pub": "npm publish",
|
|
56
|
-
"compile": "
|
|
62
|
+
"compile": "tsc --skipLibCheck --watch"
|
|
57
63
|
},
|
|
58
64
|
"repository": {
|
|
59
65
|
"type": "git",
|
|
@@ -70,5 +76,5 @@
|
|
|
70
76
|
"bugs": {
|
|
71
77
|
"url": "https://github.com/publishlab/node-acme-client/issues"
|
|
72
78
|
},
|
|
73
|
-
"gitHead": "
|
|
79
|
+
"gitHead": "9f7d766cb386b299d4098141f4a47d23e16975e3"
|
|
74
80
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -4,8 +4,6 @@
|
|
|
4
4
|
|
|
5
5
|
import { AxiosInstance } from 'axios';
|
|
6
6
|
import * as rfc8555 from './rfc8555';
|
|
7
|
-
import {CancelError} from '../src/error.js'
|
|
8
|
-
export * from '../src/error.js'
|
|
9
7
|
|
|
10
8
|
export type PrivateKeyBuffer = Buffer;
|
|
11
9
|
export type PublicKeyBuffer = Buffer;
|
|
@@ -115,6 +113,15 @@ export const directory: {
|
|
|
115
113
|
zerossl: {
|
|
116
114
|
staging: string,
|
|
117
115
|
production: string
|
|
116
|
+
},
|
|
117
|
+
sslcom: {
|
|
118
|
+
staging: string,
|
|
119
|
+
production: string,
|
|
120
|
+
ec: string
|
|
121
|
+
},
|
|
122
|
+
litessl: {
|
|
123
|
+
staging: string,
|
|
124
|
+
production: string
|
|
118
125
|
}
|
|
119
126
|
};
|
|
120
127
|
|
|
@@ -211,12 +218,16 @@ export const agents: any;
|
|
|
211
218
|
* Logger
|
|
212
219
|
*/
|
|
213
220
|
|
|
221
|
+
export class CancelError extends Error {
|
|
222
|
+
constructor(message?: string);
|
|
223
|
+
}
|
|
224
|
+
|
|
214
225
|
export function setLogger(fn: (message: any, ...args: any[]) => void): void;
|
|
215
226
|
|
|
216
227
|
export function createChallengeFn(opts?: {logger?:any}): any;
|
|
217
228
|
// export function walkTxtRecord(record: any): Promise<string[]>;
|
|
218
229
|
export function getAuthoritativeDnsResolver(record:string): Promise<any>;
|
|
219
230
|
|
|
220
|
-
export
|
|
231
|
+
export function resolveDomainBySoaRecord(domain: string): Promise<string>;
|
|
221
232
|
|
|
222
|
-
export function
|
|
233
|
+
export function setWalkFromAuthoritative(value?: boolean): void;
|
package/types/index.test-d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* acme-client type definition tests
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import * as acme from '
|
|
5
|
+
import * as acme from '..';
|
|
6
6
|
|
|
7
7
|
(async () => {
|
|
8
8
|
/* Client */
|
|
@@ -10,6 +10,7 @@ import * as acme from 'acme-client';
|
|
|
10
10
|
|
|
11
11
|
const client = new acme.Client({
|
|
12
12
|
accountKey,
|
|
13
|
+
sslProvider: 'letsencrypt',
|
|
13
14
|
directoryUrl: acme.directory.letsencrypt.staging
|
|
14
15
|
});
|
|
15
16
|
|
|
@@ -52,7 +53,10 @@ import * as acme from 'acme-client';
|
|
|
52
53
|
/* Auto */
|
|
53
54
|
await client.auto({
|
|
54
55
|
csr: certCsr,
|
|
55
|
-
challengeCreateFn: async (authz,
|
|
56
|
+
challengeCreateFn: async (authz, keyAuthorization) => ({
|
|
57
|
+
challenge: authz.challenges[0],
|
|
58
|
+
keyAuthorization: await keyAuthorization(authz.challenges[0])
|
|
59
|
+
}),
|
|
56
60
|
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {}
|
|
57
61
|
});
|
|
58
62
|
|
|
@@ -63,7 +67,10 @@ import * as acme from 'acme-client';
|
|
|
63
67
|
skipChallengeVerification: false,
|
|
64
68
|
challengePriority: ['http-01', 'dns-01'],
|
|
65
69
|
preferredChain: 'DST Root CA X3',
|
|
66
|
-
challengeCreateFn: async (authz,
|
|
70
|
+
challengeCreateFn: async (authz, keyAuthorization) => ({
|
|
71
|
+
challenge: authz.challenges[0],
|
|
72
|
+
keyAuthorization: await keyAuthorization(authz.challenges[0])
|
|
73
|
+
}),
|
|
67
74
|
challengeRemoveFn: async (authz, challenge, keyAuthorization) => {}
|
|
68
75
|
});
|
|
69
76
|
})();
|
package/src/index.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* acme-client
|
|
3
|
-
*/
|
|
4
|
-
import AcmeClinet from './client.js'
|
|
5
|
-
export const Client = AcmeClinet
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Directory URLs
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
export const directory = {
|
|
12
|
-
buypass: {
|
|
13
|
-
staging: 'https://api.test4.buypass.no/acme/directory',
|
|
14
|
-
production: 'https://api.buypass.com/acme/directory',
|
|
15
|
-
},
|
|
16
|
-
google: {
|
|
17
|
-
staging: 'https://dv.acme-v02.test-api.pki.goog/directory',
|
|
18
|
-
production: 'https://dv.acme-v02.api.pki.goog/directory',
|
|
19
|
-
},
|
|
20
|
-
letsencrypt: {
|
|
21
|
-
staging: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
|
22
|
-
production: 'https://acme-v02.api.letsencrypt.org/directory',
|
|
23
|
-
},
|
|
24
|
-
letsencrypt_staging: {
|
|
25
|
-
production: 'https://acme-staging-v02.api.letsencrypt.org/directory',
|
|
26
|
-
},
|
|
27
|
-
zerossl: {
|
|
28
|
-
staging: 'https://acme.zerossl.com/v2/DV90',
|
|
29
|
-
production: 'https://acme.zerossl.com/v2/DV90',
|
|
30
|
-
},
|
|
31
|
-
sslcom:{
|
|
32
|
-
staging: 'https://acme.ssl.com/sslcom-dv-rsa',
|
|
33
|
-
production: 'https://acme.ssl.com/sslcom-dv-rsa',
|
|
34
|
-
ec: 'https://acme.ssl.com/sslcom-dv-ecc',
|
|
35
|
-
},
|
|
36
|
-
litessl: {
|
|
37
|
-
staging: 'https://acme.litessl.com/acme/v2/directory',
|
|
38
|
-
production: 'https://acme.litessl.com/acme/v2/directory',
|
|
39
|
-
},
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export function getDirectoryUrl(opts) {
|
|
43
|
-
const {sslProvider, pkType} = opts
|
|
44
|
-
const list= directory[sslProvider]
|
|
45
|
-
if (!list) {
|
|
46
|
-
throw new Error(`sslProvider ${sslProvider} not found`)
|
|
47
|
-
}
|
|
48
|
-
let pkTypePrefix = pkType || 'rsa'
|
|
49
|
-
if (pkType) {
|
|
50
|
-
pkTypePrefix = pkType.toLowerCase().split("_")[0]
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (pkTypePrefix && list[pkTypePrefix]) {
|
|
54
|
-
return list[pkTypePrefix]
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return list.production
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
export function getAllSslProviderDomains() {
|
|
62
|
-
const list = Object.values(directory).map((item) => {
|
|
63
|
-
let url = item.production.replace('https://', '')
|
|
64
|
-
url = url.substring(0, url.indexOf('/'))
|
|
65
|
-
return url
|
|
66
|
-
})
|
|
67
|
-
return list
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
let sslProviderReverseProxies = {}
|
|
71
|
-
|
|
72
|
-
function initSslProviderReverseProxies() {
|
|
73
|
-
for (const sslProvider of getAllSslProviderDomains()) {
|
|
74
|
-
sslProviderReverseProxies[sslProvider] = ""
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
initSslProviderReverseProxies()
|
|
78
|
-
|
|
79
|
-
export function getSslProviderReverseProxies() {
|
|
80
|
-
return sslProviderReverseProxies
|
|
81
|
-
}
|
|
82
|
-
export function setSslProviderReverseProxies(reverseProxies) {
|
|
83
|
-
Object.assign(sslProviderReverseProxies, reverseProxies)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Crypto
|
|
88
|
-
*/
|
|
89
|
-
|
|
90
|
-
export * as crypto from './crypto/index.js'
|
|
91
|
-
export * as forge from './crypto/forge.js'
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* Axios
|
|
95
|
-
*/
|
|
96
|
-
|
|
97
|
-
export * from './axios.js'
|
|
98
|
-
/**
|
|
99
|
-
* Logger
|
|
100
|
-
*/
|
|
101
|
-
|
|
102
|
-
export * from './logger.js'
|
|
103
|
-
export * from './verify.js'
|
|
104
|
-
export * from './error.js'
|
|
105
|
-
|
|
106
|
-
export * from './util.js'
|