Skip to content

Commit

Permalink
fix(SNI): do not use the default db for SNI
Browse files Browse the repository at this point in the history
  • Loading branch information
andris9 committed Apr 29, 2024
1 parent 5af8f24 commit a6c53eb
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 28 deletions.
35 changes: 17 additions & 18 deletions lib/acme/certs.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ const log = require('npmlog');
const { Resolver } = require('dns').promises;
const resolver = new Resolver();
const Joi = require('joi');
const db = require('../db');
const { SettingsHandler } = require('../settings-handler');

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

const ensureAcme = async acmeOptions => {
const ensureAcme = async (acmeOptions, certHandler) => {
if (!settings) {
settings = new SettingsHandler({ db: db.database });
settings = new SettingsHandler({ db: certHandler.database });
}

if (acmeInitialized) {
Expand Down Expand Up @@ -78,7 +77,7 @@ const ensureAcme = async acmeOptions => {
};

const getAcmeAccount = async (acmeOptions, certHandler) => {
await ensureAcme(acmeOptions);
await ensureAcme(acmeOptions, certHandler);

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

Expand Down Expand Up @@ -121,7 +120,7 @@ const getAcmeAccount = async (acmeOptions, certHandler) => {
};
};

const validateDomain = async domain => {
const validateDomain = async (domain, certHandler) => {
// check domain name format
const validation = Joi.string()
.domain({ tlds: { allow: true } })
Expand All @@ -136,9 +135,9 @@ const validateDomain = async domain => {
}

// check CAA support
const caaDomains = config.acme.caaDomains.map(normalizeDomain).filter(d => d);
const caaDomains = certHandler.acme?.caaDomains.map(normalizeDomain).filter(d => d);

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

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

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

try {
// throws if can not validate domain
await validateDomain(domain);
await validateDomain(domain, certHandler);
log.info('ACME', 'Domain validation for %s passed', domain);
} catch (err) {
log.error('ACME', 'Failed to validate domain %s: %s', domain, err.message);
log.error('ACME', 'Failed to validate domain %s: %s', domain, err.stack);
return certificateData;
}

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

const jwkPrivateKey = pem2jwk(privateKey);
Expand All @@ -236,7 +235,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
domains: [domain],
challenges: {
'http-01': AcmeChallenge.create({
db: db.database
db: certHandler.database
})
}
};
Expand Down Expand Up @@ -290,16 +289,16 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
return await certHandler.getRecord({ _id: certificateData._id }, true);
} catch (err) {
try {
await db.redis.multi().set(domainSafeLockKey, 1).expire(domainSafeLockKey, BLOCK_RENEW_AFTER_ERROR_TTL).exec();
await certHandler.redis.multi().set(domainSafeLockKey, 1).expire(domainSafeLockKey, BLOCK_RENEW_AFTER_ERROR_TTL).exec();
} catch (err) {
log.error('ACME', 'Redis call failed key=%s domains=%s error=%s', domainSafeLockKey, domain, err.message);
log.error('ACME', 'Redis call failed key=%s domains=%s error=%s', domainSafeLockKey, domain, err.stack);
}

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

if (certificateData && certificateData._id) {
try {
await db.database.collection('certs').findOneAndUpdate(
await certHandler.database.collection('certs').findOneAndUpdate(
{ _id: certificateData._id },
{
$set: {
Expand All @@ -312,7 +311,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
}
);
} catch (err) {
log.error('ACME', 'Failed to update certificate record domain=%s error=%s', domain, err.message);
log.error('ACME', 'Failed to update certificate record domain=%s error=%s', domain, err.stack);
}

certHandler.loggelf({
Expand All @@ -335,7 +334,7 @@ const acquireCert = async (domain, acmeOptions, certificateData, certHandler) =>
try {
await releaseLock(lock);
} catch (err) {
log.error('Lock', 'Failed to release lock for %s: %s', domainOpLockKey, err);
log.error('Lock', 'Failed to release lock for %s: %s', domainOpLockKey, err.stack);
}
}
};
Expand Down
19 changes: 9 additions & 10 deletions lib/cert-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ class CertHandler {

this.users = options.users;

this.acmeConfig = options.acmeConfig;
this.acme = options.acmeConfig;

this.ctxCache = new Map();

Expand Down Expand Up @@ -368,7 +368,7 @@ class CertHandler {
servername = this.getCertName(parsedCert);
}
} catch (err) {
log.error('Certs', 'Failed to parse certificate. error=%s', err.message);
log.error('Certs', 'Failed to parse certificate. error=%s', err.stack);
}
}

Expand Down Expand Up @@ -635,7 +635,7 @@ class CertHandler {
try {
certData = await this.autogenerateAcmeCertificate(servername);
} catch (err) {
log.error('Certs', 'Failed to generate certificate. domain=%s error=%s', servername, err.message);
log.error('Certs', 'Failed to generate certificate. domain=%s error=%s', servername, err.stack);
}

if (!certData || !certData.privateKey || !certData.cert) {
Expand Down Expand Up @@ -688,12 +688,12 @@ class CertHandler {
const subdomain = domain.substring(0, dotPos).toLowerCase().trim();
const maindomain = tools.normalizeDomain(domain.substring(dotPos + 1));

if (!this.acmeConfig.autogenerate?.cnameMapping?.hasOwnProperty(subdomain)) {
if (!this.acme.autogenerate?.cnameMapping?.hasOwnProperty(subdomain)) {
log.verbose('Certs', 'Skip ACME. reason="unsupported subdomain" action=precheck domain=%s', domain);
return false;
}

let subdomainTargets = [].concat(this.acmeConfig.autogenerate?.cnameMapping?.[subdomain] || []);
let subdomainTargets = [].concat(this.acme.autogenerate?.cnameMapping?.[subdomain] || []);
if (!subdomainTargets.length) {
// unsupported subdomain
log.verbose('Certs', 'Skip ACME. reason="unsupported subdomain" action=precheck domain=%s', domain);
Expand All @@ -705,7 +705,7 @@ class CertHandler {
try {
resolved = await resolver.resolveCname(domain);
} catch (err) {
log.error('Certs', 'DNS CNAME query failed. action=precheck domain=%s error=%s', domain, err.message);
log.error('Certs', 'DNS CNAME query failed. action=precheck domain=%s error=%s', domain, err.stack);
return false;
}

Expand All @@ -722,8 +722,7 @@ class CertHandler {
}

// CAA check

const caaDomains = this.acmeConfig.caaDomains?.map(domain => tools.normalizeDomain(domain)).filter(d => d);
const caaDomains = this.acme.caaDomains?.map(domain => tools.normalizeDomain(domain)).filter(d => d);

let parts = domain.split('.');
for (let i = 0; i < parts.length - 1; i++) {
Expand Down Expand Up @@ -763,7 +762,7 @@ class CertHandler {
async autogenerateAcmeCertificate(servername) {
let domain = tools.normalizeDomain(servername);

if (!this.acmeConfig.autogenerate?.enabled) {
if (!this.acme.autogenerate?.enabled) {
// can not create autogenerated TLS certificates
log.verbose('Certs', 'Skip ACME. reason="Certificate autogeneration not enabled" action=precheck domain=%s', domain);
return false;
Expand All @@ -790,7 +789,7 @@ class CertHandler {
});

if (certInsertResult) {
let certData = await getCertificate(servername, this.acmeConfig, this);
let certData = await getCertificate(servername, this.acme, this);
log.verbose('Certs', 'ACME certificate result. servername=%s status=%s', servername, certData && certData.status);
return certData || false;
}
Expand Down

0 comments on commit a6c53eb

Please sign in to comment.