Server: Support passphrase for SSL private key (#4488) * SSL: support passphrase for private key * Recommend CLI argument or environment variable for key passphrase * Fix SSL passphrase handling to ensure it is always a string

e871886b1358d385b2fee177e9db0e1f7c85d3d0

Cohee <18619528+Cohee1207@users.noreply.github.com>

Signed
3 files changed, +16 -0Showing whitespace changes
default/config.yaml+6 -0
@@ -40,9 +40,15 @@ browserLaunch:
4040port: 8000
4141# -- SSL options --
4242ssl:
43+ # Enable SSL/TLS encryption
4344 enabled: false
45+ # Path to certificate (relative to server root)
4446 certPath: "./certs/cert.pem"
47+ # Path to private key (relative to server root)
4548 keyPath: "./certs/privkey.pem"
49+ # Private key passphrase (leave empty if not needed)
50+ # For better security, use a CLI argument or an environment variable (SILLYTAVERN_SSL_KEYPASSPHRASE)
51+ keyPassphrase: ""
4652# -- SECURITY CONFIGURATION --
4753# Toggle whitelist mode
4854whitelistMode: true
src/command-line.js+8 -0
@@ -27,6 +27,7 @@ import { initConfig } from './config-init.js';
2727 * @property {boolean} ssl If enable SSL
2828 * @property {string} certPath Path to certificate
2929 * @property {string} keyPath Path to private key
30+ * @property {string} keyPassphrase SSL private key passphrase
3031 * @property {boolean} whitelistMode If enable whitelist mode
3132 * @property {boolean} basicAuthMode If enable basic authentication
3233 * @property {boolean} requestProxyEnabled If enable outgoing request proxy
@@ -70,6 +71,7 @@ export class CommandLineParser {
7071 ssl: false,
7172 certPath: 'certs/cert.pem',
7273 keyPath: 'certs/privkey.pem',
74+ keyPassphrase: '',
7375 whitelistMode: true,
7476 basicAuthMode: false,
7577 requestProxyEnabled: false,
@@ -193,6 +195,11 @@ export class CommandLineParser {
193195 default: null,
194196 describe: 'Path to SSL private key file',
195197 })
198+ .option('keyPassphrase', {
199+ type: 'string',
200+ default: null,
201+ describe: 'Passphrase for the SSL private key',
202+ })
196203 .option('whitelist', {
197204 type: 'boolean',
198205 default: null,
@@ -291,6 +298,7 @@ export class CommandLineParser {
291298 ssl: cliArguments.ssl ?? getConfigValue('ssl.enabled', defaultConfig.ssl, 'boolean'),
292299 certPath: cliArguments.certPath ?? getConfigValue('ssl.certPath', defaultConfig.certPath),
293300 keyPath: cliArguments.keyPath ?? getConfigValue('ssl.keyPath', defaultConfig.keyPath),
301+ keyPassphrase: cliArguments.keyPassphrase ?? getConfigValue('ssl.keyPassphrase', defaultConfig.keyPassphrase),
294302 whitelistMode: cliArguments.whitelist ?? getConfigValue('whitelistMode', defaultConfig.whitelistMode, 'boolean'),
295303 basicAuthMode: cliArguments.basicAuthMode ?? getConfigValue('basicAuthMode', defaultConfig.basicAuthMode, 'boolean'),
296304 requestProxyEnabled: cliArguments.requestProxyEnabled ?? getConfigValue('requestProxy.enabled', defaultConfig.requestProxyEnabled, 'boolean'),
src/server-startup.js+2 -0
@@ -233,9 +233,11 @@ export class ServerStartup {
233233 #createHttpsServer(url, ipVersion) {
234234 this.#verifySslOptions();
235235 return new Promise((resolve, reject) => {
236+ /** @type {import('https').ServerOptions} */
236237 const sslOptions = {
237238 cert: fs.readFileSync(this.cliArgs.certPath),
238239 key: fs.readFileSync(this.cliArgs.keyPath),
240+ passphrase: String(this.cliArgs.keyPassphrase ?? ''),
239241 };
240242 const server = https.createServer(sslOptions, this.app);
241243 server.on('error', reject);