Skip to content

Commit

Permalink
Ability to use shared SSL
Browse files Browse the repository at this point in the history
  • Loading branch information
willnode committed Nov 14, 2023
1 parent 7c7d2c3 commit d18b04e
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 8 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "domcloud-bridge",
"version": "0.31.1",
"version": "0.32.0",
"description": "Deployment runner for DOM Cloud",
"main": "app.js",
"engines": {
Expand Down
31 changes: 27 additions & 4 deletions src/executor/nginx.js
Original file line number Diff line number Diff line change
Expand Up @@ -275,8 +275,6 @@ class NginxExecutor {
await spawnSudoUtil('NGINX_GET', [domain]);
return await new Promise((resolve, reject) => {
var src = cat(tmpFile).toString();
// https://github.com/virtualmin/virtualmin-nginx/issues/18
src = src.replace(/ default_server/g, '');
NginxConfFile.createFromSource(src, (err, conf) => {
if (err)
return reject(err);
Expand All @@ -291,8 +289,33 @@ class NginxExecutor {
spawnSudoUtil('NGINX_SET', [domain]).then(() => {
resolve("Done updated\n" + node.toString());
}).catch((err) => {
if (err && err.stderr && err.stderr.includes('nginx: [emerg]')) {
}
reject(err);
})
});
});
})
}
/**
* @param {string} domain
* @param {any} info
*/
async setDirect(domain, info) {
return await executeLock('nginx', async () => {
await spawnSudoUtil('NGINX_GET', [domain]);
return await new Promise((resolve, reject) => {
var src = cat(tmpFile).toString();
NginxConfFile.createFromSource(src, (err, conf) => {
if (err)
return reject(err);
const node = conf.nginx.server[0];
if (!node) {
return reject(new Error(`Cannot find domain ${domain}`));
}
this.applyInfo(node, info);
writeTo(tmpFile, conf.toString());
spawnSudoUtil('NGINX_SET', [domain]).then(() => {
resolve("Done updated\n" + node.toString());
}).catch((err) => {
reject(err);
})
});
Expand Down
41 changes: 38 additions & 3 deletions src/executor/runner.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import path from "path";
import {
detectCanShareSSL,
escapeShell,
getDbName,
getLtsPhp,
Expand Down Expand Up @@ -661,13 +662,47 @@ export async function runConfigSubdomain(config, domaindata, subdomain, sshExec,
await sshExec(`mkdir -p ~/.local/bin; echo -e "\\u23\\u21/bin/bash\\n$(which php${phpVer}) \\u22\\u24\\u40\\u22" > ~/.local/bin/php; chmod +x ~/.local/bin/php`, false);
break;
case 'ssl':
// ssl now also fix any misconfigurations
if (process.env.MODE === 'dev') {
break;
}
if (['off', 'always', 'enforce', 'on'].includes(value)) {
let regenerateSsl = false;
let expectedSslMode = null;
if (['off', 'always', 'on'].includes(value)) {
expectedSslMode = expectedSslMode;
} else if (value == 'letsencrypt') {
regenerateSsl = true;
}
var nginxNodes = await nginxExec.get(subdomain);
var nginxInfos = nginxExec.extractInfo(nginxNodes, subdomain);
var sharedSSL = regenerateSsl ? null : detectCanShareSSL(subdomain);
var changed = false;
var expectCert = sharedSSL ? path.join(sharedSSL, 'ssl.cert') : domaindata['SSL cert file'];
var expectKey = sharedSSL ? path.join(sharedSSL, 'ssl.key') : domaindata['SSL key file'];
if (!expectCert || !expectKey) {
expectedSslMode = 'off';
}
if (expectCert != nginxInfos.ssl_certificate) {
nginxInfos.ssl_certificate = expectCert
changed = true;
}
if (expectKey != nginxInfos.ssl_certificate_key) {
nginxInfos.ssl_certificate_key = expectKey
changed = true;
}
if (domaindata['HTML directory'] != nginxInfos.root) {
nginxInfos.root = domaindata['HTML directory']
changed = true;
}
if (expectedSslMode && expectedSslMode != ["", "off", "always", "on"][nginxInfos.ssl]) {
nginxInfos.config.ssl = expectedSslMode
changed = true;
}
if (changed) {
await writeLog("$> Applying nginx ssl config on " + subdomain);
await writeLog(await nginxExec.setSsl(subdomain, value, ""));
} else if (value == 'letsencrypt' || !value) {
await writeLog(await nginxExec.setDirect(subdomain, nginxInfos));
}
if (regenerateSsl || (!expectedSslMode && !sharedSSL)) {
await writeLog("$> generating ssl cert with let's encrypt");
await spawnSudoUtil('OPENSSL_CLEAN');
await virtExec("generate-letsencrypt-cert", {
Expand Down
27 changes: 27 additions & 0 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ let pythonVersionsList = [];
* @type {Record<string, string>}
*/
let pythonVersionsMap = {};
/**
* @type {Record<string, string>}
*/
let sslWildcardsMap = {};
const pythonConstants = {
// https://raw.githubusercontent.com/indygreg/python-build-standalone/latest-release/latest-release.json
tag: "20230507",
Expand All @@ -41,6 +45,13 @@ export const initUtils = () => {
const rev = fs.readFileSync('.git/HEAD').toString().trim();
revision = rev.indexOf(':') === -1 ? rev : fs.readFileSync('.git/' + rev.substring(5)).toString().trim();
revision = revision.substring(0, 7);
sslWildcardsMap = process.env.SSL_WILDCARDS ? process.env.SSL_WILDCARDS.split(',').reduce((a, b) => {
var splits = b.split(':');
if (splits.length == 2) {
a[splits[0].toLowerCase()] = splits[1];
}
return a;
}, {}) : {};
axios.get('https://www.php.net/releases/?json').then(res => {
Object.values(res.data).forEach(v => {
v.supported_versions.forEach((/** @type {string} */ ver) => {
Expand Down Expand Up @@ -482,3 +493,19 @@ export function writeTo(path, content) {
encoding: 'utf-8'
});
}

export function detectCanShareSSL(subdomain) {
const subdomainParts = subdomain.split('.');
for (const domain of Object.keys(sslWildcardsMap)) {

// Split the domain strings into arrays of subdomains
const domainParts = domain.split('.');

// Check if the subdomain has exactly one more part than the domain
if (subdomainParts.length === domainParts.length + 1 &&
subdomain.endsWith(`.${domain}`)) {
return sslWildcardsMap[domain]
}
}
return null;
}
8 changes: 8 additions & 0 deletions sudoutil.js
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ switch (cli.args.shift()) {
arg = cli.args.shift();
exec(`${env.BASH_KILL} ${arg}`, { shell: '' }).code;
exit(0);
case 'SHELL_EXISTS':
arg = cli.args.shift();
for (const path of cli.args) {
if (!existsSync(path)) {
exit(1);
}
}
exit(0);
case 'SHELL_SUDO':
arg = cli.args.shift();
var sudo = spawn(env.BASH_SUDO, ['-u', arg, '-i', ...cli.args], {
Expand Down

0 comments on commit d18b04e

Please sign in to comment.