From e6ef7865d8de41104b4b6c0963241a2a9daaac19 Mon Sep 17 00:00:00 2001 From: Wildan M Date: Thu, 9 May 2024 10:58:26 +0700 Subject: [PATCH] Implement SSL force linking --- .env.test | 2 + package-lock.json | 4 +- package.json | 2 +- src/executor/runnersub.js | 20 ++- src/executor/virtualmin.js | 41 +++++- src/util.js | 2 +- sudoutil.js | 13 ++ test/virtual-server.d/16183677691482684 | 175 ++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 12 deletions(-) create mode 100644 test/virtual-server.d/16183677691482684 diff --git a/.env.test b/.env.test index e0e87a1..04ec32c 100644 --- a/.env.test +++ b/.env.test @@ -1,4 +1,6 @@ NODE_ENV=development +VIRTUAL_SERVER_PATH=./test/virtual-server.d/$ +VIRTUAL_SERVER_OUT=./test/virtual-server.d/$ NGINX_PATH=./test/nginx.d/$.conf NGINX_OUT=./test/nginx.out/$.conf NGINX_BIN=echo nginx diff --git a/package-lock.json b/package-lock.json index 80b1de8..33cdd54 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "domcloud-bridge", - "version": "0.45.0", + "version": "0.46.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "domcloud-bridge", - "version": "0.45.0", + "version": "0.46.0", "license": "MIT", "dependencies": { "axios": "^1.6.8", diff --git a/package.json b/package.json index aeaeb3d..19bde6b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "domcloud-bridge", - "version": "0.45.0", + "version": "0.46.0", "description": "Deployment runner for DOM Cloud", "main": "app.js", "engines": { diff --git a/src/executor/runnersub.js b/src/executor/runnersub.js index 2e8ea03..f03b698 100644 --- a/src/executor/runnersub.js +++ b/src/executor/runnersub.js @@ -110,10 +110,7 @@ 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; - // } + // ssl also fix any misconfigurations let regenerateSsl = false; let selfSignSsl = false; let expectedSslMode = null; @@ -182,10 +179,19 @@ export async function runConfigSubdomain(config, domaindata, subdomain, sshExec, }); } else if (!changed) { await writeLog("$> SSL config seems OK, nothing changed"); + break; } - if (changed) { - await writeLog("$> Applying nginx ssl config on " + subdomain); - await writeLog(await nginxExec.setDirect(subdomain, nginxInfos)); + await writeLog("$> Applying nginx ssl config on " + subdomain); + await writeLog(await nginxExec.setDirect(subdomain, nginxInfos)); + if (sharedSSL && sharedSSL.match(/\/(\d{10,})\//)) { + await writeLog("$> Applying SSL links with global domain"); + let id = sharedSSL.match(/\/(\d{10,})\//)[1]; + await writeLog(await virtualminExec.pushVirtualServerConfig(subdomaindata['ID'], { + 'ssl_same': id, + 'ssl_key': path.join(sharedSSL, 'ssl.key'), + 'ssl_cert': path.join(sharedSSL, 'ssl.cert'), + 'ssl_chain': path.join(sharedSSL, 'ssl.ca'), + })); } break; case 'root': diff --git a/src/executor/virtualmin.js b/src/executor/virtualmin.js index 31184a6..f30f868 100644 --- a/src/executor/virtualmin.js +++ b/src/executor/virtualmin.js @@ -1,10 +1,14 @@ import { cat, escapeShell, + executeLock, spawnSudoUtil, spawnSudoUtilAsync, - splitLimit + splitLimit, + writeTo } from "../util.js"; +import path from 'path'; +const tmpFile = path.join(process.cwd(), '/.tmp/virtual-server') class VirtualminExecutor { /** @@ -155,6 +159,41 @@ class VirtualminExecutor { execAsync(...command) { return spawnSudoUtilAsync('VIRTUALMIN', command); } + + /** + * @param {string} id + * @param {{ [s: string]: string; }} props + */ + async pushVirtualServerConfig(id, props) { + return await executeLock('virtual-server', () => { + return new Promise((resolve, reject) => { + spawnSudoUtil('VIRTUAL_SERVER_GET', [id]).then(() => { + const fileConf = cat(tmpFile); + const config = cat(tmpFile).trimEnd().split("\n"); + for (const [key, value] of Object.entries(props)) { + let i = config.findIndex(x => x.startsWith(key + '=')); + if (i >= 0) { + config[i] = key + '=' + value; + } else { + config.push(key + '=' + value) + } + } + config.push(''); + const outConf = config.join("\n"); + if (outConf != fileConf) { + writeTo(tmpFile, outConf); + spawnSudoUtil('VIRTUAL_SERVER_SET', [id]).then(() => { + resolve("Done updated\n"); + }).catch((err) => { + reject(err); + }) + } else { + resolve("Nothing changed\n"); + } + }).catch(reject); + }); + }) + } } export const virtualminExec = new VirtualminExecutor(); \ No newline at end of file diff --git a/src/util.js b/src/util.js index 8deb8eb..63a3b81 100644 --- a/src/util.js +++ b/src/util.js @@ -31,7 +31,7 @@ export const initUtils = () => { revision = rev.indexOf(':') === -1 ? rev : cat('.git/' + rev.substring(5)).trim(); revision = revision.substring(0, 7); sslWildcardsMap = (process.env.SSL_WILDCARDS || '').split(',').reduce((a, b) => { - var splits = b.split(':'); + var splits = b.split(':', 2); if (splits.length == 2) { a[splits[0].toLowerCase()] = splits[1]; } diff --git a/sudoutil.js b/sudoutil.js index a2d71af..4c4dcb2 100755 --- a/sudoutil.js +++ b/sudoutil.js @@ -39,6 +39,9 @@ const env = Object.assign({}, { BASH_SU: 'su', BASH_SUDO: 'sudo', BASH_KILL: 'kill', + VIRTUAL_SERVER_PATH: '/etc/webmin/virtual-server/domains/$', + VIRTUAL_SERVER_OUT: '/etc/webmin/virtual-server/domains/$', + VIRTUAL_SERVER_TMP: path.join(__dirname, '.tmp/virtual-server'), NGINX_PATH: '/etc/nginx/conf.d/$.conf', NGINX_OUT: '/etc/nginx/conf.d/$.conf', NGINX_BIN: 'nginx', @@ -106,6 +109,16 @@ switch (cli.args.shift()) { rm(DEST + '.bak'); exec(`${env.NGINX_BIN} -s reload`); exit(0); + case 'VIRTUAL_SERVER_GET': + arg = cli.args.shift(); + cat(env.VIRTUAL_SERVER_PATH.replace('$', arg)).to(env.VIRTUAL_SERVER_TMP); + fixOwner(env.VIRTUAL_SERVER_TMP); + exit(0); + case 'VIRTUAL_SERVER_SET': + arg = cli.args.shift(); + DEST = env.VIRTUAL_SERVER_OUT.replace('$', arg); + cat(env.VIRTUAL_SERVER_TMP).to(DEST); + exit(0); case 'NGINX_START': exec(env.NGINX_START); exit(0); diff --git a/test/virtual-server.d/16183677691482684 b/test/virtual-server.d/16183677691482684 new file mode 100644 index 0000000..2af3778 --- /dev/null +++ b/test/virtual-server.d/16183677691482684 @@ -0,0 +1,175 @@ +auto_letsencrypt=0 +migrate=0 +email=hello@example.com +mongrelslimit= +bw_limit=3221225472 +edit_phpmode=1 +defip=1 +virtualmin-nginx-ssl=1 +edit_backup=1 +netmask= +lastsave=1715217551 +edit_records=1 +home=/home/example/domains/suba.example.com +ip=68.183.191.223 +limit_webalizer=0 +proxy_pass= +creator=root +plan=159145679461879 +limit_dns=1 +virus=0 +dir=1 +uquota=1048576 +ipfollow= +ftp=0 +virtalready= +name6=1 +edit_ip=0 +alias= +proxy_pass_mode=0 +nocreationmail= +edit_passwd=1 +ssl_cert=/home/example/domains/suba.example.com/ssl.cert +ssl_key=/home/example/domains/suba.example.com/ssl.key +mysql_module=mysql +virtualmin-nginx=1 +edit_disable=1 +quota=1048576 +ssl=0 +webmin=1 +emailto_addr=hello@example.com +limit_postgres=1 +template=0 +limit_ftp=0 +owner=suba.example.com +edit_aliases=1 +limit_mysql=1 +limit_logrotate=0 +domslimit=1 +edit_delete=1 +ip6=2400:6180:0:d1::770:4001 +parent= +edit_domain=1 +db_mysql=example_suba +limit_virus=0 +logrotate=0 +virt=0 +forceunder=1 +edit_allowedhosts=1 +name=1 +edit_admins=0 +edit_dnsip=0 +prefix=suba +aliasdomslimit=1 +group=suba +web_port=80 +limit_virt=0 +edit_mail=0 +mysql=1 +edit_catchall=0 +php_fpm_port=8048 +edit_restore=1 +edit_forward=0 +noslaves= +allowedscripts= +edit_dbs=1 +limit_dir=1 +uid=1218 +db=example_suba +edit_sharedips=0 +pass=abcdefgh +emailto_src=hello@example.com +limit_virtualmin-nginx-ssl=1 +mail=0 +realdomslimit=1 +gid=1218 +aliasmail= +virt6already= +edit_phpver=0 +aliaslimit=0 +nodbname=0 +subprefix= +mailboxlimit=1 +edit_redirect=1 +postgres=0 +unix=1 +norename=1 +web_ssl_samechain=1 +reseller= +limit_unix=1 +id=16161777331856567 +spam=0 +limit_mail=0 +db_postgres= +limit_webmin=1 +edit_spf=0 +ssl_combined=/home/example/domains/suba.example.com/ssl.combined +edit_users=0 +jail=0 +netmask6= +ugid=1218 +limit_web=0 +dbslimit=2 +created=1616177751 +source=create-domain.pl +virt6=0 +subdom= +web=0 +limit_spam=0 +nosecondaries= +ugroup=suba +php_fpm_version=8.0 +limit_ssl=0 +emailto=hello@example.com +hashpass=0 +webalizer=0 +ssl_everything=/home/example/domains/suba.example.com/ssl.everything +edit_spam=0 +web_sslport=443 +edit_ssl=1 +edit_sched=1 +dns_ip= +dns=1 +dom=perumdaseger.com +edit_scripts=0 +safeunder=0 +user=suba +limit_virtualmin-nginx=1 +file=/etc/webmin/virtual-server/domains/16161777331856567 +dns_slave=portal.domcloud.id +mysql_user=suba +letsencrypt_last_success=1710649364 +letsencrypt_dname= +letsencrypt_last=1710649364 +ssl_pass= +ssl_chain=/home/example/domains/suba.example.com/ssl.ca +letsencrypt_renew=1 +whois_err=Missing the whois command +whois_last=1715217551 +whois_next=1715832639 +whois_expiry=0 +domain_spf_enabled=0 +domain_dmarc_enabled=0 +bw_usage=328478251 +bw_start=19844 +bw_usage_only=328478251 +ssl_cert_expiry=1718421738 +ssl_cert_expiry_cache=1710649360 +php_mode=fpm +lastsave_user= +lastsave_webmincron=virtual-server::run_cron_script +lastsave_type=cron +lastsave_script=/webmincron/webmincron.pl +letsencrypt_last_failure=1695104403 +php_error_log= +letsencrypt_size=2048 +letsencrypt_ctype= +lastsave_pid=155764 +backup_web_type=virtualmin-nginx +backup_mail_folders=Maildir +backup_web_default=0 +backup_encpass=$6$encryptedpass +backup_ssl_type=virtualmin-nginx-ssl +bw_notify=1711843208 +bw_usage_only_web=328478251 +bw_usage_web=328478251