From c7a9063a72071153723e668787548766c971f029 Mon Sep 17 00:00:00 2001 From: ZacharyZcR Date: Wed, 15 Jul 2026 14:30:28 +0800 Subject: [PATCH] Merge commit from fork --- .../database/routes/acme-ssl-routes.ts | 78 +++++++++++-------- 1 file changed, 46 insertions(+), 32 deletions(-) diff --git a/src/backend/database/routes/acme-ssl-routes.ts b/src/backend/database/routes/acme-ssl-routes.ts index 8d55f65e..878c0770 100644 --- a/src/backend/database/routes/acme-ssl-routes.ts +++ b/src/backend/database/routes/acme-ssl-routes.ts @@ -1,4 +1,4 @@ -import { execSync } from "child_process"; +import { execFileSync } from "child_process"; import { promises as fs } from "fs"; import path from "path"; import type { AuthenticatedRequest } from "../../../types/index.js"; @@ -39,7 +39,7 @@ function getCertInfo(): { } { const certFile = path.join(SSL_DIR, "termix.crt"); try { - execSync(`openssl x509 -in "${certFile}" -noout 2>/dev/null`, { + execFileSync("openssl", ["x509", "-in", certFile, "-noout"], { stdio: "pipe", }); } catch { @@ -47,8 +47,9 @@ function getCertInfo(): { } try { - const endDateRaw = execSync( - `openssl x509 -in "${certFile}" -noout -enddate`, + const endDateRaw = execFileSync( + "openssl", + ["x509", "-in", certFile, "-noout", "-enddate"], { stdio: "pipe" }, ) .toString() @@ -57,17 +58,25 @@ function getCertInfo(): { const expiresAt = new Date(endDateRaw).toISOString(); try { - execSync(`openssl x509 -in "${certFile}" -checkend 0 -noout`, { - stdio: "pipe", - }); + execFileSync( + "openssl", + ["x509", "-in", certFile, "-checkend", "0", "-noout"], + { + stdio: "pipe", + }, + ); } catch { return { status: "expired", expiresAt }; } try { - execSync(`openssl x509 -in "${certFile}" -checkend 2592000 -noout`, { - stdio: "pipe", - }); + execFileSync( + "openssl", + ["x509", "-in", certFile, "-checkend", "2592000", "-noout"], + { + stdio: "pipe", + }, + ); return { status: "valid", expiresAt }; } catch { return { status: "expiring", expiresAt }; @@ -265,7 +274,7 @@ export function registerAcmeSSLRoutes( } try { - execSync("certbot --version", { stdio: "pipe" }); + execFileSync("certbot", ["--version"], { stdio: "pipe" }); } catch { return res .status(500) @@ -278,13 +287,16 @@ export function registerAcmeSSLRoutes( await fs.mkdir(CERTBOT_WORK_DIR, { recursive: true }); await fs.mkdir(CERTBOT_LOGS_DIR, { recursive: true }); - const certbotDirFlags = [ - `--config-dir "${CERTBOT_CONFIG_DIR}"`, - `--work-dir "${CERTBOT_WORK_DIR}"`, - `--logs-dir "${CERTBOT_LOGS_DIR}"`, - ].join(" "); + const certbotDirArgs = [ + "--config-dir", + CERTBOT_CONFIG_DIR, + "--work-dir", + CERTBOT_WORK_DIR, + "--logs-dir", + CERTBOT_LOGS_DIR, + ]; - let certbotCmd: string; + let certbotArgs: string[]; if (challengeType === "dns-cloudflare") { if (!cloudflareToken) { @@ -302,40 +314,39 @@ export function registerAcmeSSLRoutes( { mode: 0o600 }, ); - certbotCmd = [ - "certbot", + certbotArgs = [ "certonly", "--non-interactive", "--agree-tos", "--dns-cloudflare", - `--dns-cloudflare-credentials "${CLOUDFLARE_CREDENTIALS_FILE}"`, + "--dns-cloudflare-credentials", + CLOUDFLARE_CREDENTIALS_FILE, "--dns-cloudflare-propagation-seconds", "30", "-d", - `"${domain}"`, + domain, "--email", - `"${email}"`, + email, "--cert-name", "termix", - certbotDirFlags, - ].join(" "); + ...certbotDirArgs, + ]; } else { - certbotCmd = [ - "certbot", + certbotArgs = [ "certonly", "--non-interactive", "--agree-tos", "--webroot", "-w", - `"${ACME_WEBROOT}"`, + ACME_WEBROOT, "-d", - `"${domain}"`, + domain, "--email", - `"${email}"`, + email, "--cert-name", "termix", - certbotDirFlags, - ].join(" "); + ...certbotDirArgs, + ]; } authLogger.info("Requesting Let's Encrypt certificate", { @@ -344,7 +355,10 @@ export function registerAcmeSSLRoutes( operation: "acme_cert_request", }); - execSync(certbotCmd, { stdio: "pipe", timeout: 120000 }); + execFileSync("certbot", certbotArgs, { + stdio: "pipe", + timeout: 120000, + }); const liveDir = path.join(CERTBOT_CONFIG_DIR, "live", "termix"); const fullchainSrc = path.join(liveDir, "fullchain.pem");