Skip to content

Commit

Permalink
Support multiple domains
Browse files Browse the repository at this point in the history
Closes: #1834
PR-URL: #1836
  • Loading branch information
tshemsedinov committed Jun 5, 2023
1 parent 914b264 commit 2c5b10c
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 26 deletions.
13 changes: 5 additions & 8 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,8 @@ class Application extends events.EventEmitter {
await this.parallel([
this.schemas.load(),
this.static.load(),
this.cert.load(),
this.resources.load(),
this.cert.load(),
(async () => {
await this.lib.load();
await this.db.load();
Expand Down Expand Up @@ -211,14 +211,11 @@ class Application extends events.EventEmitter {
if (threadId === 1) this.console.debug('Deleted: /' + relPath);
});

this.watcher.on('after', (changes) => {
this.watcher.on('before', async (changes) => {
const certPath = path.join(this.path, 'cert');
const changed = changes.some(([name]) => name.startsWith(certPath));
if (!changed) return;
setTimeout(() => {
this.cert.after(changes);
}, timeout);
if (threadId === 1) this.console.debug('New certificates for: *');
const changed = changes.filter(([name]) => name.startsWith(certPath));
if (changed.length === 0) return;
await this.cert.before(changes);
});
}

Expand Down
65 changes: 52 additions & 13 deletions lib/certificates.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
'use strict';

const tls = require('node:tls');
const path = require('node:path');
const { threadId } = require('node:worker_threads');
const { Resources } = require('./resources.js');

class Certificates extends Resources {
Expand All @@ -13,19 +15,56 @@ class Certificates extends Resources {
return this.domains.get(key);
}

after(changes) {
if (!changes) return;
const key = this.files.get('/key.pem');
const cert = this.files.get('/cert.pem');
try {
const creds = tls.createSecureContext({ key, cert });
this.domains.set('*', { key, cert, creds });
if (!this.application.server?.httpServer.setSecureContext) return;
this.application.server.httpServer.setSecureContext({ key, cert });
this.domains.set('*', { key, cert, creds });
} catch (error) {
this.domains.delete('*');
this.application.console.error(error.stack);
async before(changes) {
const folders = new Set();
for (const [name, event] of changes) {
const dir = path.dirname(name);
const folder = path.basename(dir);
folders.add(folder);
if (event === 'change') await super.change(name);
if (event === 'datele') super.delete(name);
}
await this.init([...folders]);
changes.length = 0;
}

folders() {
const folders = new Set();
const files = [...this.files.keys()];
for (const name of files) {
const dir = path.dirname(name);
const folder = path.basename(dir);
folders.add(folder);
}
return [...folders];
}

async load(targetPath) {
await super.load(targetPath);
await this.init();
}

async init(folders = this.folders()) {
for (const domain of folders) {
const key = this.files.get(`/${domain}/key.pem`);
const cert = this.files.get(`/${domain}/cert.pem`);
const domains = this.files.get(`/${domain}/.domains`).toString();
if (!key || !cert || !domains) continue;
const names = domains.split(/[\r\n\s]+/).filter((s) => s.length !== 0);
if (threadId === 1) {
const list = names.join(', ');
this.application.console.log(`New certificate for: ${list}`);
}
try {
const creds = tls.createSecureContext({ key, cert });
const context = { key, cert, creds };
for (const name of names) this.domains.set(name, context);
if (!this.application.server?.httpServer.setSecureContext) continue;
this.application.server.httpServer.setSecureContext({ key, cert });
} catch (error) {
for (const name of names) this.domains.delete(name);
this.application.console.error(error.stack);
}
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions lib/worker.js
Original file line number Diff line number Diff line change
Expand Up @@ -81,18 +81,18 @@ process.on('unhandledRejection', logError('unhandledRejection'));
if (kind === 'server' || kind === 'balancer') {
const options = { ...config.server, port, kind };
if (config.server.protocol === 'https') {
application.cert.after([]);
const domain = application.cert.get('*');
const domain = application.cert.get('localhost');
if (!domain) {
if (threadId === 1) console.error('Can not load TLS certificates');
await stop();
return;
}
const { key, cert, creds } = domain;
const { key, cert } = domain;
Object.assign(options, { key, cert });
options.SNICallback = (servername, callback) => {
if (!creds) callback(new Error(`No certificate for ${servername}`));
callback(null, creds);
const domain = application.cert.get(servername);
if (!domain) callback(new Error(`No certificate for ${servername}`));
callback(null, domain.creds);
};
}
application.server = new Server(application, options);
Expand Down

0 comments on commit 2c5b10c

Please sign in to comment.