@abtnode/certificate-manager 1.16.20-beta-cf6dfce1 → 1.16.20-beta-148929e2
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/libs/acme-manager.js +64 -38
- package/libs/acme-wrapper.js +5 -2
- package/package.json +7 -7
- package/sdk/manager.js +7 -3
- package/states/certificate.js +8 -0
package/libs/acme-manager.js
CHANGED
|
@@ -41,11 +41,11 @@ class Manager extends EventEmitter {
|
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
await this.
|
|
44
|
+
await this.createOrRenewCert({ ...data, challenges: { 'http-01': http01 } });
|
|
45
45
|
},
|
|
46
46
|
options: {
|
|
47
|
-
maxRetries: 0,
|
|
48
|
-
retryDelay:
|
|
47
|
+
maxRetries: process.env.NODE_ENV === 'production' ? 5 : 0,
|
|
48
|
+
retryDelay: 10 * 1000,
|
|
49
49
|
maxTimeout: 60 * 1000, // throw timeout error after 1 minutes
|
|
50
50
|
id: (job) => this.getJobId(job),
|
|
51
51
|
},
|
|
@@ -61,17 +61,41 @@ class Manager extends EventEmitter {
|
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
63
|
|
|
64
|
-
|
|
65
|
-
|
|
64
|
+
/*
|
|
65
|
+
* @param {string} domain
|
|
66
|
+
* @param {object} options
|
|
67
|
+
* @param {number} options.delay - delay time in ms
|
|
68
|
+
* @return {Promise<void>}
|
|
69
|
+
*/
|
|
70
|
+
async pushToJobQueue(domain, { delay = 0, metadata } = {}) {
|
|
71
|
+
const jobData = { domain, subscriberEmail: this.maintainerEmail, delay, metadata };
|
|
66
72
|
|
|
67
73
|
const job = await this.queue.get(this.getJobId(jobData));
|
|
68
74
|
|
|
69
75
|
if (!job) {
|
|
70
|
-
this.queue.push(jobData);
|
|
76
|
+
const newJob = this.queue.push(jobData);
|
|
77
|
+
newJob.on('failed', async (data) => {
|
|
78
|
+
const tmpDomain = data?.job?.domain;
|
|
79
|
+
if (tmpDomain) {
|
|
80
|
+
await states.certificate.updateStatus(tmpDomain, CERT_STATUS.error);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
this.emit('cert.error', data.job);
|
|
84
|
+
logger.error(`create certificate for ${tmpDomain} job failed`, { domain: tmpDomain, error: data.error });
|
|
85
|
+
});
|
|
71
86
|
}
|
|
72
87
|
}
|
|
73
88
|
|
|
74
|
-
|
|
89
|
+
/**
|
|
90
|
+
*
|
|
91
|
+
* @param {object} data
|
|
92
|
+
* @param {string} data.domain
|
|
93
|
+
* @param {string} data.siteId
|
|
94
|
+
* @param {object} options
|
|
95
|
+
* @param {number} options.delay - delay time in ms
|
|
96
|
+
* @returns
|
|
97
|
+
*/
|
|
98
|
+
async add({ domain, siteId }, { delay = 0, metadata } = {}) {
|
|
75
99
|
if (!domain) {
|
|
76
100
|
throw new Error('domain is required when add domain');
|
|
77
101
|
}
|
|
@@ -80,13 +104,13 @@ class Manager extends EventEmitter {
|
|
|
80
104
|
if (!cert) {
|
|
81
105
|
cert = await states.certificate.insert({
|
|
82
106
|
domain,
|
|
107
|
+
siteId,
|
|
83
108
|
source: CERT_SOURCE.letsEncrypt,
|
|
84
109
|
status: CERT_STATUS.waiting,
|
|
85
110
|
});
|
|
86
111
|
}
|
|
87
112
|
|
|
88
|
-
await this.pushToJobQueue(domain);
|
|
89
|
-
|
|
113
|
+
await this.pushToJobQueue(domain, { delay, metadata });
|
|
90
114
|
return cert;
|
|
91
115
|
}
|
|
92
116
|
|
|
@@ -111,7 +135,7 @@ class Manager extends EventEmitter {
|
|
|
111
135
|
};
|
|
112
136
|
}
|
|
113
137
|
|
|
114
|
-
async
|
|
138
|
+
async createOrRenewCert({ domain, subscriberEmail, force = false, challenges, metadata }) {
|
|
115
139
|
try {
|
|
116
140
|
if (!domain) {
|
|
117
141
|
throw new Error('domain is required when create certificate');
|
|
@@ -120,7 +144,7 @@ class Manager extends EventEmitter {
|
|
|
120
144
|
const cert = await states.certificate.findOne({ domain });
|
|
121
145
|
if (!cert) {
|
|
122
146
|
logger.warn(`create certificate failed: the cert ${domain} does not exist`);
|
|
123
|
-
return;
|
|
147
|
+
return null;
|
|
124
148
|
}
|
|
125
149
|
|
|
126
150
|
let status = CERT_STATUS.creating;
|
|
@@ -131,18 +155,41 @@ class Manager extends EventEmitter {
|
|
|
131
155
|
|
|
132
156
|
if (force === false && days > this.renewalOffsetInDay) {
|
|
133
157
|
logger.info(`no need to renewal ${cert.domain}, the certificate will expires more than ${days} days`);
|
|
134
|
-
return;
|
|
158
|
+
return null;
|
|
135
159
|
}
|
|
136
160
|
|
|
137
161
|
status = CERT_STATUS.renewaling;
|
|
138
162
|
}
|
|
139
163
|
|
|
140
164
|
await states.certificate.updateStatus(cert.domain, status);
|
|
141
|
-
await this.acme.create({
|
|
165
|
+
const data = await this.acme.create({
|
|
142
166
|
subject: cert.domain,
|
|
143
167
|
subscriberEmail,
|
|
144
168
|
challenges,
|
|
145
169
|
});
|
|
170
|
+
|
|
171
|
+
logger.info(`create certificate for ${domain} job success`);
|
|
172
|
+
|
|
173
|
+
const [count, certs] = await states.certificate.update(
|
|
174
|
+
{ domain: data.subject },
|
|
175
|
+
{
|
|
176
|
+
$set: {
|
|
177
|
+
domain: data.subject,
|
|
178
|
+
status: CERT_STATUS.generated,
|
|
179
|
+
certificate: data.fullchain,
|
|
180
|
+
privateKey: data.privkey,
|
|
181
|
+
},
|
|
182
|
+
}
|
|
183
|
+
);
|
|
184
|
+
|
|
185
|
+
if (count === 0) {
|
|
186
|
+
throw new Error(`update certificate for ${domain} failed`);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
logger.info(`updated ${count} certificate for ${domain} job success`);
|
|
190
|
+
|
|
191
|
+
this.emit('cert.issued', { id: cert.id, domain: data.subject, metadata });
|
|
192
|
+
return certs[0];
|
|
146
193
|
} catch (error) {
|
|
147
194
|
logger.error(`create certificate for ${domain} job failed`, error);
|
|
148
195
|
throw error;
|
|
@@ -151,7 +198,11 @@ class Manager extends EventEmitter {
|
|
|
151
198
|
|
|
152
199
|
async checkRenewalCerts() {
|
|
153
200
|
logger.info('run renewal certificate job');
|
|
201
|
+
|
|
154
202
|
const certs = await states.certificate.findRenewCerts(this.renewalOffsetInDay);
|
|
203
|
+
|
|
204
|
+
logger.info(`found ${certs.length} certs need to renewal`);
|
|
205
|
+
|
|
155
206
|
for (const cert of certs) {
|
|
156
207
|
// eslint-disable-next-line no-await-in-loop
|
|
157
208
|
await this.pushToJobQueue(cert.domain);
|
|
@@ -177,31 +228,6 @@ Manager.getInstance = async ({ maintainerEmail, baseDataDir }) => {
|
|
|
177
228
|
|
|
178
229
|
await instance.acme.init();
|
|
179
230
|
|
|
180
|
-
instance.acme.on('cert.issued', async (data) => {
|
|
181
|
-
await states.certificate.update(
|
|
182
|
-
{ domain: data.subject },
|
|
183
|
-
{
|
|
184
|
-
$set: {
|
|
185
|
-
domain: data.subject,
|
|
186
|
-
status: CERT_STATUS.generated,
|
|
187
|
-
certificate: data.fullchain,
|
|
188
|
-
privateKey: data.privkey,
|
|
189
|
-
},
|
|
190
|
-
}
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
const cert = await states.certificate.findOne({ domain: data.subject });
|
|
194
|
-
instance.emit('cert.issued', { id: cert.id, domain: cert.domain });
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
instance.acme.on('cert.error', async (data) => {
|
|
198
|
-
if (data.domain) {
|
|
199
|
-
await states.certificate.updateStatus(data.domain, CERT_STATUS.error);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
instance.emit('cert.error', data);
|
|
203
|
-
});
|
|
204
|
-
|
|
205
231
|
return instance;
|
|
206
232
|
};
|
|
207
233
|
|
package/libs/acme-wrapper.js
CHANGED
|
@@ -85,17 +85,20 @@ class AcmeWrapper extends EventEmitter {
|
|
|
85
85
|
|
|
86
86
|
logger.info('certificates generated!');
|
|
87
87
|
|
|
88
|
-
|
|
88
|
+
const data = {
|
|
89
89
|
subject,
|
|
90
90
|
privkey: serverPem,
|
|
91
91
|
cert: pems.cert,
|
|
92
92
|
chain: pems.chain,
|
|
93
93
|
fullchain,
|
|
94
94
|
challenges,
|
|
95
|
-
}
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
return data;
|
|
96
98
|
} catch (error) {
|
|
97
99
|
logger.error('create certificate error', { domain: subject, error });
|
|
98
100
|
this.emit('cert.error', { domain: subject, error_message: error.message });
|
|
101
|
+
throw error;
|
|
99
102
|
}
|
|
100
103
|
}
|
|
101
104
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abtnode/certificate-manager",
|
|
3
|
-
"version": "1.16.20-beta-
|
|
3
|
+
"version": "1.16.20-beta-148929e2",
|
|
4
4
|
"description": "Manage ABT Node SSL certificates",
|
|
5
5
|
"author": "polunzh <polunzh@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/ArcBlock/blocklet-server#readme",
|
|
@@ -32,11 +32,11 @@
|
|
|
32
32
|
"url": "https://github.com/ArcBlock/blocklet-server/issues"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@abtnode/cron": "1.16.20-beta-
|
|
36
|
-
"@abtnode/logger": "1.16.20-beta-
|
|
37
|
-
"@abtnode/models": "1.16.20-beta-
|
|
38
|
-
"@abtnode/queue": "1.16.20-beta-
|
|
39
|
-
"@abtnode/util": "1.16.20-beta-
|
|
35
|
+
"@abtnode/cron": "1.16.20-beta-148929e2",
|
|
36
|
+
"@abtnode/logger": "1.16.20-beta-148929e2",
|
|
37
|
+
"@abtnode/models": "1.16.20-beta-148929e2",
|
|
38
|
+
"@abtnode/queue": "1.16.20-beta-148929e2",
|
|
39
|
+
"@abtnode/util": "1.16.20-beta-148929e2",
|
|
40
40
|
"@fidm/x509": "^1.2.1",
|
|
41
41
|
"@greenlock/manager": "^3.1.0",
|
|
42
42
|
"@root/acme": "^3.1.0",
|
|
@@ -49,5 +49,5 @@
|
|
|
49
49
|
"lodash.get": "^4.4.2",
|
|
50
50
|
"punycode": "^2.1.1"
|
|
51
51
|
},
|
|
52
|
-
"gitHead": "
|
|
52
|
+
"gitHead": "99e23380f73b63a8e63ce1fe8f75908194df5d80"
|
|
53
53
|
}
|
package/sdk/manager.js
CHANGED
|
@@ -128,15 +128,19 @@ class Manager extends EventEmitter {
|
|
|
128
128
|
|
|
129
129
|
/**
|
|
130
130
|
* 生成域名,certificate-manager 会自动生成并更新该证书
|
|
131
|
-
* @param {
|
|
131
|
+
* @param {object} data
|
|
132
|
+
* @param {string} data.domain
|
|
133
|
+
* @param {string} data.siteId
|
|
134
|
+
* @param {object} options
|
|
135
|
+
* @param {number} options.delay - delay time in ms
|
|
132
136
|
* @returns
|
|
133
137
|
*/
|
|
134
|
-
issue(domain) {
|
|
138
|
+
issue({ domain, siteId }, options) {
|
|
135
139
|
if (!domain) {
|
|
136
140
|
throw new Error('domain is required');
|
|
137
141
|
}
|
|
138
142
|
|
|
139
|
-
return this.acmeManager.add(domain.toLowerCase());
|
|
143
|
+
return this.acmeManager.add({ domain: domain.toLowerCase(), siteId }, options);
|
|
140
144
|
}
|
|
141
145
|
|
|
142
146
|
async upsertByDomain(tmpData) {
|
package/states/certificate.js
CHANGED
|
@@ -17,6 +17,14 @@ class Certificate extends BaseState {
|
|
|
17
17
|
return super.update({ domain }, { $set: { status } });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
updateStatusById(id, status) {
|
|
21
|
+
if (!Object.values(CERT_STATUS).includes(status)) {
|
|
22
|
+
throw new Error('invalid domain status');
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return super.update({ id }, { $set: { status } });
|
|
26
|
+
}
|
|
27
|
+
|
|
20
28
|
insert(data) {
|
|
21
29
|
if (data.certificate) {
|
|
22
30
|
data.meta = getCertInfo(data.certificate);
|