@cocreate/acme 1.3.0 → 1.3.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/CHANGELOG.md +16 -0
- package/demo/index.html +19 -19
- package/docs/index.html +336 -330
- package/package.json +1 -1
- package/src/index.js +346 -300
package/src/index.js
CHANGED
|
@@ -1,310 +1,356 @@
|
|
|
1
|
-
const { Client, forge } = require(
|
|
2
|
-
const fs = require(
|
|
3
|
-
const util = require(
|
|
4
|
-
const exec = util.promisify(require(
|
|
1
|
+
const { Client, forge } = require("acme-client");
|
|
2
|
+
const fs = require("fs");
|
|
3
|
+
const util = require("node:util");
|
|
4
|
+
const exec = util.promisify(require("node:child_process").exec);
|
|
5
5
|
|
|
6
|
-
const certificates = {}
|
|
7
|
-
const email =
|
|
8
|
-
const keyPath =
|
|
9
|
-
let client
|
|
10
|
-
const hosts = {}
|
|
6
|
+
const certificates = {};
|
|
7
|
+
const email = "ssl@cocreate.app";
|
|
8
|
+
const keyPath = "/etc/certificates/";
|
|
9
|
+
let client;
|
|
10
|
+
const hosts = {};
|
|
11
11
|
|
|
12
12
|
// Run this once per server to generate random constants
|
|
13
|
-
const DAYS = Math.floor(Math.random() * 7);
|
|
14
|
-
const HOURS = Math.floor(Math.random() * 24);
|
|
15
|
-
const MINUTES = Math.floor(Math.random() * 60);
|
|
13
|
+
const DAYS = Math.floor(Math.random() * 7); // Random days between 0-6
|
|
14
|
+
const HOURS = Math.floor(Math.random() * 24); // Random hours between 0-23
|
|
15
|
+
const MINUTES = Math.floor(Math.random() * 60); // Random minutes between 0-59
|
|
16
16
|
|
|
17
17
|
// Store these constants in a configuration file, environment variable, or database
|
|
18
18
|
|
|
19
19
|
class CoCreateAcme {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
20
|
+
constructor(proxy, crud) {
|
|
21
|
+
this.proxy = proxy;
|
|
22
|
+
this.crud = crud;
|
|
23
|
+
// this.check = this.checkCertificate
|
|
24
|
+
this.init().catch((err) => {
|
|
25
|
+
console.error("Error initializing ACME client:", err);
|
|
26
|
+
// TODO: Handle initialization error (possibly retry or exit)
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async init() {
|
|
31
|
+
await exec("sudo mkdir -p /etc/certificates");
|
|
32
|
+
await exec("sudo chmod 777 /etc/certificates");
|
|
33
|
+
|
|
34
|
+
// if (!fs.existsSync(keyPath)) {
|
|
35
|
+
// fs.mkdirSync(keyPath, { recursive: true }); // Create the directory if it doesn't exist
|
|
36
|
+
// }
|
|
37
|
+
|
|
38
|
+
const accountKeyPath = keyPath + "account.pem";
|
|
39
|
+
|
|
40
|
+
let accountKey = "";
|
|
41
|
+
let isNewAccount = false; // Flag to check if the account is new
|
|
42
|
+
|
|
43
|
+
// Check if the account key exists and load it; otherwise, create a new one
|
|
44
|
+
if (!fs.existsSync(accountKeyPath)) {
|
|
45
|
+
fs.writeFileSync(accountKeyPath, accountKey); // Store the account key
|
|
46
|
+
accountKey = await forge.createPrivateKey();
|
|
47
|
+
isNewAccount = true; // New account, so will need to register it
|
|
48
|
+
fs.writeFileSync(accountKeyPath, accountKey); // Store the account key
|
|
49
|
+
// fs.chmodSync(accountKeyPath, '400')
|
|
50
|
+
} else {
|
|
51
|
+
accountKey = fs.readFileSync(accountKeyPath, "utf8");
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Initialize the ACME client with the account key
|
|
55
|
+
client = new Client({
|
|
56
|
+
directoryUrl: "https://acme-v02.api.letsencrypt.org/directory", // https://acme-v02.api.letsencrypt.org/directory https://acme-staging-v02.api.letsencrypt.org/directory
|
|
57
|
+
accountKey: accountKey
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
// Register the new account if it was just created
|
|
61
|
+
if (isNewAccount) {
|
|
62
|
+
try {
|
|
63
|
+
// Attempt to create an account
|
|
64
|
+
await client.createAccount({
|
|
65
|
+
termsOfServiceAgreed: true,
|
|
66
|
+
contact: ["mailto:" + email]
|
|
67
|
+
});
|
|
68
|
+
console.log("ACME account created successfully!");
|
|
69
|
+
} catch (error) {
|
|
70
|
+
fs.unlinkSync(accountKeyPath);
|
|
71
|
+
// Handle errors that occur during account creation
|
|
72
|
+
console.error("Error creating ACME account:", error.message);
|
|
73
|
+
// Depending on the type of error, you might want to retry, log the error, alert someone, etc.
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
async requestCertificate(
|
|
79
|
+
host,
|
|
80
|
+
hostPosition,
|
|
81
|
+
hostObject,
|
|
82
|
+
organization_id,
|
|
83
|
+
wildcard = false
|
|
84
|
+
) {
|
|
85
|
+
try {
|
|
86
|
+
const self = this;
|
|
87
|
+
|
|
88
|
+
const hostKeyPath = keyPath + host + "/";
|
|
89
|
+
if (!fs.existsSync(hostKeyPath)) {
|
|
90
|
+
fs.mkdirSync(hostKeyPath, { recursive: true });
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const domains = wildcard ? [host, `*.${host}`] : [host];
|
|
94
|
+
|
|
95
|
+
/* Create certificate request */
|
|
96
|
+
let [key, csr] = await forge.createCsr({
|
|
97
|
+
commonName: domains[0],
|
|
98
|
+
altNames: domains
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
let challenge_id = "";
|
|
102
|
+
|
|
103
|
+
/* Request certificate */
|
|
104
|
+
const cert = await client.auto({
|
|
105
|
+
csr,
|
|
106
|
+
email: [email], // Replace with your email
|
|
107
|
+
termsOfServiceAgreed: true,
|
|
108
|
+
challengeCreateFn: async (
|
|
109
|
+
authz,
|
|
110
|
+
challenge,
|
|
111
|
+
keyAuthorization
|
|
112
|
+
) => {
|
|
113
|
+
console.log(
|
|
114
|
+
`Challenge added for host: ${host} token: ${challenge.token}`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
if (challenge.type === "http-01") {
|
|
118
|
+
const httpChallenge = await self.crud.send({
|
|
119
|
+
method: "object.create",
|
|
120
|
+
host,
|
|
121
|
+
array: "files",
|
|
122
|
+
object: {
|
|
123
|
+
"content-type": "text/plain",
|
|
124
|
+
directory: "acme-challenge",
|
|
125
|
+
host: [authz.identifier.value],
|
|
126
|
+
name: challenge.token,
|
|
127
|
+
organization_id: "652c8d62679eca03e0b116a7",
|
|
128
|
+
path: "/.well-known/acme-challenge/",
|
|
129
|
+
pathname: `/.well-known/acme-challenge/${challenge.token}`,
|
|
130
|
+
public: "true",
|
|
131
|
+
src: keyAuthorization
|
|
132
|
+
},
|
|
133
|
+
organization_id
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
if (
|
|
137
|
+
httpChallenge &&
|
|
138
|
+
httpChallenge.object &&
|
|
139
|
+
httpChallenge.object[0]
|
|
140
|
+
)
|
|
141
|
+
challenge_id = httpChallenge.object[0]._id;
|
|
142
|
+
else console.error("error creating challenge url");
|
|
143
|
+
} else if (challenge.type === "dns-01") {
|
|
144
|
+
// Calculate the DNS TXT record value
|
|
145
|
+
const dnsRecordName = `_acme-challenge.${authz.identifier.value}`;
|
|
146
|
+
const dnsRecordValue =
|
|
147
|
+
await client.getChallengeKeyAuthorization(
|
|
148
|
+
challenge
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
console.log(`Add this TXT record to your DNS:`);
|
|
152
|
+
console.log(`Name: ${dnsRecordName}`);
|
|
153
|
+
console.log(`Value: ${dnsRecordValue}`);
|
|
154
|
+
|
|
155
|
+
// Here, implement the logic to add the TXT record to your DNS
|
|
156
|
+
// await updateDnsTxtRecord(dnsRecordName, dnsRecordValue); // Hypothetical function to update DNS
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
challengeRemoveFn: async (
|
|
161
|
+
authz,
|
|
162
|
+
challenge,
|
|
163
|
+
keyAuthorization
|
|
164
|
+
) => {
|
|
165
|
+
/* Clean up challenge response here if necessary */
|
|
166
|
+
console.log(
|
|
167
|
+
`Challenge removed for token: ${challenge.token}`
|
|
168
|
+
);
|
|
169
|
+
if (challenge.type === "http-01") {
|
|
170
|
+
self.crud.send({
|
|
171
|
+
method: "object.delete",
|
|
172
|
+
host,
|
|
173
|
+
array: "files",
|
|
174
|
+
object: {
|
|
175
|
+
_id: challenge_id
|
|
176
|
+
},
|
|
177
|
+
organization_id
|
|
178
|
+
});
|
|
179
|
+
} else if (challenge.type === "dns-01") {
|
|
180
|
+
// await removeDnsTxtRecord(challenge); // A hypothetical function to clean up DNS
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
let expires = await forge.readCertificateInfo(cert);
|
|
186
|
+
expires = expires.notAfter;
|
|
187
|
+
this.setCertificate(
|
|
188
|
+
host,
|
|
189
|
+
expires,
|
|
190
|
+
organization_id,
|
|
191
|
+
hostKeyPath,
|
|
192
|
+
cert,
|
|
193
|
+
key
|
|
194
|
+
);
|
|
195
|
+
|
|
196
|
+
key = key.toString("utf8");
|
|
197
|
+
|
|
198
|
+
this.crud.send({
|
|
199
|
+
method: "object.update",
|
|
200
|
+
host,
|
|
201
|
+
array: "organizations",
|
|
202
|
+
object: {
|
|
203
|
+
_id: organization_id,
|
|
204
|
+
[`host[${hostPosition}]`]: {
|
|
205
|
+
...hostObject,
|
|
206
|
+
name: host,
|
|
207
|
+
cert,
|
|
208
|
+
key,
|
|
209
|
+
expires
|
|
210
|
+
}
|
|
211
|
+
},
|
|
212
|
+
organization_id
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
console.log(`Certificate successfully created for ${host}!'`);
|
|
216
|
+
return true;
|
|
217
|
+
} catch (error) {
|
|
218
|
+
console.log(`Certificate failed to create for ${host}!`);
|
|
219
|
+
delete hosts[host];
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
async getCertificate(host, organization_id) {
|
|
225
|
+
const hostKeyPath = keyPath + host + "/";
|
|
226
|
+
let hostPosition, hostObject;
|
|
227
|
+
|
|
228
|
+
let organization = await this.crud.getOrganization({
|
|
229
|
+
host,
|
|
230
|
+
organization_id
|
|
231
|
+
});
|
|
232
|
+
if (organization.error) return false;
|
|
233
|
+
if (!organization_id) organization_id = organization._id;
|
|
234
|
+
|
|
235
|
+
if (organization.host) {
|
|
236
|
+
for (let i = 0; i < organization.host.length; i++) {
|
|
237
|
+
if (organization.host[i].name === host) {
|
|
238
|
+
hostPosition = i;
|
|
239
|
+
hostObject = organization.host[i];
|
|
240
|
+
if (organization.host[i].cert && organization.host[i].key) {
|
|
241
|
+
let expires = await forge.readCertificateInfo(
|
|
242
|
+
organization.host[i].cert
|
|
243
|
+
);
|
|
244
|
+
expires = expires.notAfter;
|
|
245
|
+
if (this.isValid(expires)) {
|
|
246
|
+
this.setCertificate(
|
|
247
|
+
host,
|
|
248
|
+
expires,
|
|
249
|
+
organization_id,
|
|
250
|
+
hostKeyPath,
|
|
251
|
+
organization.host[i].cert,
|
|
252
|
+
organization.host[i].key
|
|
253
|
+
);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
if (!hostPosition && hostPosition !== 0) return false;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return await this.requestCertificate(
|
|
265
|
+
host,
|
|
266
|
+
hostPosition,
|
|
267
|
+
hostObject,
|
|
268
|
+
organization_id,
|
|
269
|
+
false
|
|
270
|
+
);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async checkCertificate(host, organization_id, pathname = "") {
|
|
274
|
+
let hostname = host.split(":")[0];
|
|
275
|
+
if (
|
|
276
|
+
hostname === "localhost" ||
|
|
277
|
+
hostname === "127.0.0.1" ||
|
|
278
|
+
pathname.startsWith("/.well-known/acme-challenge/")
|
|
279
|
+
)
|
|
280
|
+
return true;
|
|
281
|
+
|
|
282
|
+
if (certificates[host]) {
|
|
283
|
+
return true;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const hostKeyPath = keyPath + host + "/";
|
|
287
|
+
if (fs.existsSync(hostKeyPath + "fullchain.pem")) {
|
|
288
|
+
let cert = fs.readFileSync(hostKeyPath + "fullchain.pem", "utf8");
|
|
289
|
+
let expires = await forge.readCertificateInfo(cert);
|
|
290
|
+
expires = expires.notAfter;
|
|
291
|
+
if (this.isValid(expires)) {
|
|
292
|
+
this.setCertificate(host, expires, organization_id);
|
|
293
|
+
return true;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
if (!hosts[host])
|
|
298
|
+
hosts[host] = await this.getCertificate(host, organization_id);
|
|
299
|
+
return hosts[host];
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
isValid(expires) {
|
|
303
|
+
let currentDate = new Date();
|
|
304
|
+
currentDate.setDate(currentDate.getDate() + DAYS);
|
|
305
|
+
currentDate.setHours(currentDate.getHours() + HOURS);
|
|
306
|
+
currentDate.setMinutes(currentDate.getMinutes() + MINUTES);
|
|
307
|
+
|
|
308
|
+
if (expires && currentDate < expires) {
|
|
309
|
+
return true; // SSL is still valid, no need to renew
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
setCertificate(host, expires, organization_id, hostKeyPath, cert, key) {
|
|
314
|
+
// let expireDate = new Date(expires);
|
|
315
|
+
// let currentDate = new Date();
|
|
316
|
+
|
|
317
|
+
// Adjust the expireDate by the DAYS, HOURS, and MINUTES constants
|
|
318
|
+
// expireDate.setDate(expireDate.getDate() - DAYS); // Subtracting to renew earlier
|
|
319
|
+
// expireDate.setHours(expireDate.getHours() - HOURS);
|
|
320
|
+
// expireDate.setMinutes(expireDate.getMinutes() - MINUTES);
|
|
321
|
+
|
|
322
|
+
// Calculate the time difference in milliseconds
|
|
323
|
+
// let timeoutDuration = expireDate.getTime() - currentDate.getTime();
|
|
324
|
+
|
|
325
|
+
// Ensure we're not setting a negative timeout in case of past dates or errors
|
|
326
|
+
// timeoutDuration = Math.max(timeoutDuration, 0);
|
|
327
|
+
|
|
328
|
+
// Clear any existing timeout for the host
|
|
329
|
+
// if (certificates[host] && certificates[host].timeout) {
|
|
330
|
+
// clearTimeout(certificates[host].timeout);
|
|
331
|
+
// }
|
|
332
|
+
|
|
333
|
+
// Set the timeout to call checkCertificate before the actual expiration
|
|
334
|
+
// let timeout = setTimeout(() => {
|
|
335
|
+
// this.checkCertificate(host, organization_id);
|
|
336
|
+
// }, timeoutDuration);
|
|
337
|
+
|
|
338
|
+
// Store the timeout and organization_id for later reference or cancellation
|
|
339
|
+
|
|
340
|
+
if (hostKeyPath) {
|
|
341
|
+
if (!fs.existsSync(hostKeyPath)) {
|
|
342
|
+
fs.mkdirSync(hostKeyPath, { recursive: true });
|
|
343
|
+
}
|
|
344
|
+
fs.writeFileSync(hostKeyPath + "fullchain.pem", cert);
|
|
345
|
+
// fs.chmodSync(keyPath + 'fullchain.pem', '444')
|
|
346
|
+
fs.writeFileSync(hostKeyPath + "private-key.pem", key);
|
|
347
|
+
// fs.chmodSync(keyPath + 'private-key.pem', '400')
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
this.proxy.createServer(host);
|
|
351
|
+
|
|
352
|
+
certificates[host] = { expires, organization_id };
|
|
353
|
+
}
|
|
308
354
|
}
|
|
309
355
|
|
|
310
356
|
module.exports = CoCreateAcme;
|