Skip to content

Commit 1a0272d

Browse files
committed
Merge branch 'master' of github.com:nodemailer/wildduck
2 parents 3f1c3e0 + ebbbec8 commit 1a0272d

10 files changed

+271
-75
lines changed

CHANGELOG.md

+23
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,28 @@
11
# Changelog
22

3+
## [1.43.3](https://github.com/nodemailer/wildduck/compare/v1.43.2...v1.43.3) (2024-05-02)
4+
5+
6+
### Bug Fixes
7+
8+
* **api-storage:** Added all storage endpoints to API docs generation ZMS-149 ([#675](https://github.com/nodemailer/wildduck/issues/675)) ([8e9af88](https://github.com/nodemailer/wildduck/commit/8e9af88a62960207d68f28fb71cd540be7a66fd5))
9+
* **autsni:** Fixed garbage collection for unfinished certificates ([5bf6c86](https://github.com/nodemailer/wildduck/commit/5bf6c865428d743f7ce328647146c95e07f3ace2))
10+
11+
## [1.43.2](https://github.com/nodemailer/wildduck/compare/v1.43.1...v1.43.2) (2024-04-29)
12+
13+
14+
### Bug Fixes
15+
16+
* **SNI:** do not use the default db for SNI ([a6c53eb](https://github.com/nodemailer/wildduck/commit/a6c53eba1fb3a6ed929050742b8681dafc472ce8))
17+
18+
## [1.43.1](https://github.com/nodemailer/wildduck/compare/v1.43.0...v1.43.1) (2024-04-29)
19+
20+
21+
### Bug Fixes
22+
23+
* **api-submit:** Added submission api endpoint to api docs generation ([#676](https://github.com/nodemailer/wildduck/issues/676)) ([82133df](https://github.com/nodemailer/wildduck/commit/82133df0c9b01e9bf4fcfcfea6ed660f37aeffe3))
24+
* **SNI:** disable SNI certificate autogeneration by default ([ecbdc9b](https://github.com/nodemailer/wildduck/commit/ecbdc9be5fefeebc71452f621dcd72e0844955ca))
25+
326
## [1.43.0](https://github.com/nodemailer/wildduck/compare/v1.42.6...v1.43.0) (2024-04-29)
427

528

config/acme.toml

+6-4
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,19 @@ keyExponent = 65537
1919

2020
[autogenerate]
2121
# If enabled then automatically generates TLS certificates based on SNI servernames
22-
enabled = true
22+
enabled = false
23+
2324
[autogenerate.cnameMapping]
2425
# Sudomain CNAME mapping
2526
# "abc" = ["def.com"] means that if the SNI servername domain is "abc.{domain}"
2627
# then there must be a CNAME record for this domain that points to "def.com".
2728
# If multiple CNAME targets are defined (eg ["def.com", "bef.com"], then at least 1 must match.
2829
# Additionally, there must be at least 1 email account with "@{domain}" address.
2930
# If there is no match, then TLS certificate is not generated.
30-
imap = ["imap.example.com"]
31-
smtp = ["smtp.example.com"]
32-
pop3 = ["imap.example.com"]
31+
32+
# imap = ["imap.example.com"]
33+
# smtp = ["smtp.example.com"]
34+
# pop3 = ["imap.example.com"]
3335

3436
[agent]
3537
# If enabled then starts a HTTP server that listens for ACME verification requests

indexes.yaml

+9
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,15 @@ indexes:
631631
expires: 1
632632
'_acme.lastRenewalCheck': 1
633633

634+
- collection: certs
635+
index:
636+
name: garbage_check
637+
key:
638+
acme: 1
639+
updated: 1
640+
expires: 1
641+
autogenerated: 1
642+
634643
- collection: audits
635644
index:
636645
name: user_expire_time

lib/acme/certs.js

+17-18
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ const log = require('npmlog');
1313
const { Resolver } = require('dns').promises;
1414
const resolver = new Resolver();
1515
const Joi = require('joi');
16-
const db = require('../db');
1716
const { SettingsHandler } = require('../settings-handler');
1817

1918
if (config.resolver && config.resolver.ns && config.resolver.ns.length) {
@@ -40,9 +39,9 @@ let acmeInitialized = false;
4039
let acmeInitializing = false;
4140
let acmeInitPending = [];
4241

43-
const ensureAcme = async acmeOptions => {
42+
const ensureAcme = async (acmeOptions, certHandler) => {
4443
if (!settings) {
45-
settings = new SettingsHandler({ db: db.database });
44+
settings = new SettingsHandler({ db: certHandler.database });
4645
}
4746

4847
if (acmeInitialized) {
@@ -78,7 +77,7 @@ const ensureAcme = async acmeOptions => {
7877
};
7978

8079
const getAcmeAccount = async (acmeOptions, certHandler) => {
81-
await ensureAcme(acmeOptions);
80+
await ensureAcme(acmeOptions, certHandler);
8281

8382
const entryKey = `acme:account:${acmeOptions.key}`;
8483

@@ -121,7 +120,7 @@ const getAcmeAccount = async (acmeOptions, certHandler) => {
121120
};
122121
};
123122

124-
const validateDomain = async domain => {
123+
const validateDomain = async (domain, certHandler) => {
125124
// check domain name format
126125
const validation = Joi.string()
127126
.domain({ tlds: { allow: true } })
@@ -136,9 +135,9 @@ const validateDomain = async domain => {
136135
}
137136

138137
// check CAA support
139-
const caaDomains = config.acme.caaDomains.map(normalizeDomain).filter(d => d);
138+
const caaDomains = certHandler.acme?.caaDomains.map(normalizeDomain).filter(d => d);
140139

141-
if (caaDomains.length) {
140+
if (caaDomains?.length) {
142141
let parts = domain.split('.');
143142
for (let i = 0; i < parts.length - 1; i++) {
144143
let subdomain = parts.slice(i).join('.');
@@ -169,7 +168,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
169168
const domainSafeLockKey = `d:lock:safe:${domain}`;
170169
const domainOpLockKey = `d:lock:op:${domain}`;
171170

172-
if (await db.redis.exists(domainSafeLockKey)) {
171+
if (await certHandler.redis.exists(domainSafeLockKey)) {
173172
// nothing to do here, renewal blocked
174173
log.info('ACME', 'Renewal blocked by failsafe lock for %s', domain);
175174

@@ -179,17 +178,17 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
179178

180179
try {
181180
// throws if can not validate domain
182-
await validateDomain(domain);
181+
await validateDomain(domain, certHandler);
183182
log.info('ACME', 'Domain validation for %s passed', domain);
184183
} catch (err) {
185-
log.error('ACME', 'Failed to validate domain %s: %s', domain, err.message);
184+
log.error('ACME', 'Failed to validate domain %s: %s', domain, err.stack);
186185
return certificateData;
187186
}
188187

189188
// Use locking to avoid race conditions, first try gets the lock, others wait until first is finished
190189
if (!getLock) {
191190
let lock = new Lock({
192-
redis: db.redis,
191+
redis: certHandler.redis,
193192
namespace: 'acme'
194193
});
195194
getLock = (...args) => lock.waitAcquireLock(...args);
@@ -212,7 +211,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
212211
if (!privateKey) {
213212
// generate new key
214213
log.info('ACME', 'Provision new private key for %s', domain);
215-
privateKey = await certHandler.resetPrivateKey({ _id: certificateData._id }, config.acme);
214+
privateKey = await certHandler.resetPrivateKey({ _id: certificateData._id }, certHandler.acme);
216215
}
217216

218217
const jwkPrivateKey = pem2jwk(privateKey);
@@ -236,7 +235,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
236235
domains: [domain],
237236
challenges: {
238237
'http-01': AcmeChallenge.create({
239-
db: db.database
238+
db: certHandler.database
240239
})
241240
}
242241
};
@@ -290,16 +289,16 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
290289
return await certHandler.getRecord({ _id: certificateData._id }, true);
291290
} catch (err) {
292291
try {
293-
await db.redis.multi().set(domainSafeLockKey, 1).expire(domainSafeLockKey, BLOCK_RENEW_AFTER_ERROR_TTL).exec();
292+
await certHandler.redis.multi().set(domainSafeLockKey, 1).expire(domainSafeLockKey, BLOCK_RENEW_AFTER_ERROR_TTL).exec();
294293
} catch (err) {
295-
log.error('ACME', 'Redis call failed key=%s domains=%s error=%s', domainSafeLockKey, domain, err.message);
294+
log.error('ACME', 'Redis call failed key=%s domains=%s error=%s', domainSafeLockKey, domain, err.stack);
296295
}
297296

298297
log.error('ACME', 'Failed to generate certificate domains=%s error=%s', domain, err.stack);
299298

300299
if (certificateData && certificateData._id) {
301300
try {
302-
await db.database.collection('certs').findOneAndUpdate(
301+
await certHandler.database.collection('certs').findOneAndUpdate(
303302
{ _id: certificateData._id },
304303
{
305304
$set: {
@@ -312,7 +311,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
312311
}
313312
);
314313
} catch (err) {
315-
log.error('ACME', 'Failed to update certificate record domain=%s error=%s', domain, err.message);
314+
log.error('ACME', 'Failed to update certificate record domain=%s error=%s', domain, err.stack);
316315
}
317316

318317
certHandler.loggelf({
@@ -335,7 +334,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
335334
try {
336335
await releaseLock(lock);
337336
} catch (err) {
338-
log.error('Lock', 'Failed to release lock for %s: %s', domainOpLockKey, err);
337+
log.error('Lock', 'Failed to release lock for %s: %s', domainOpLockKey, err.stack);
339338
}
340339
}
341340
};

0 commit comments

Comments
 (0)