From 7af3597e8d66fad7bc2a1011ce60bdba7b5a521a Mon Sep 17 00:00:00 2001 From: Daniel McAssey Date: Thu, 4 Jan 2024 14:21:31 +0000 Subject: [PATCH] feat(app): add support for SSL certificate as part of the container --- Dockerfile | 2 ++ package-lock.json | 6 ++++-- server.js | 37 ++++++++++++++++++++++++++++--------- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/Dockerfile b/Dockerfile index ef61330..1111527 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,6 +40,8 @@ ENV GUACD_PORT=4822 ENV CRYPT_CYPHER='AES-256-CBC' ENV LOG_LEVEL='info' ENV USER_DRIVE_ROOT='/user-drives' +ENV SSL_CERT_PATH='/app/certificate.pem' +ENV SSL_KEY_PATH='/app/certificate-key.pem' EXPOSE 8080 RUN mkdir -p /user-drives && chown -R guacd:guacd /user-drives diff --git a/package-lock.json b/package-lock.json index 2c15131..3d8e846 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,11 +1,11 @@ { - "name": "@glokon/guacamole-lite", + "name": "@glokon/guacws", "version": "0.0.0-development", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "@glokon/guacamole-lite", + "name": "@glokon/guacws", "version": "0.0.0-development", "license": "Apache-2.0", "dependencies": { @@ -2149,6 +2149,7 @@ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, + "peer": true, "dependencies": { "string-width": "^4.2.0" }, @@ -10978,6 +10979,7 @@ "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", "dev": true, + "peer": true, "requires": { "@colors/colors": "1.5.0", "string-width": "^4.2.0" diff --git a/server.js b/server.js index 0f59b96..b2005a0 100644 --- a/server.js +++ b/server.js @@ -2,6 +2,8 @@ const packageFile = require('./package.json'); const GuacamoleLite = require('./lib/Server'); +const Https = require('https'); +const fs = require('fs'); const { createLogger, transports, format } = require('winston'); const { combine, splat, timestamp, printf } = format; @@ -11,6 +13,8 @@ const CRYPT_CYPHER = process.env.CRYPT_CYPHER || 'AES-256-CBC'; const GUACD_HOST = process.env.GUACD_HOST || '127.0.0.1'; const GUACD_PORT = process.env.GUACD_PORT || 4822; const USER_DRIVE_ROOT = process.env.USER_DRIVE_ROOT || '/tmp/drives' +const SSL_CERT_PATH = process.env.SSL_CERT_PATH; +const SSL_KEY_PATH = process.env.SSL_KEY_PATH; const loggerFormat = printf( ({ level, message, timestamp , ...metadata}) => { let msg = `${timestamp} [${level}] : ${message} ` @@ -33,18 +37,33 @@ const logger = createLogger({ ] }); -function start(cryptKey, cryptCypher , websocketPort , guacdHost, guacdPort) { +function start(cryptKey, cryptCypher, websocketPort , guacdHost, guacdPort) { logger.info('[GUACWS] Starting Server'); - logger.info('[GUACWS] Version ' + packageFile.version); + logger.info(`[GUACWS] Version ${packageFile.version}`); if (!cryptKey || cryptKey.length === 0) { logger.error('[GUACWS] No secret key specified, please specify a key with CRYPT_SECRET environment variable'); return; } - const websocketOptions = { - port: websocketPort - }; + let httpsServer = undefined; + if (SSL_CERT_PATH && SSL_KEY_PATH) { + try { + const hasCert = fs.existsSync(SSL_CERT_PATH); + const hasKey = fs.existsSync(SSL_KEY_PATH); + + if (hasCert && hasKey) { + httpsServer = Https.createServer({ + cert: fs.readFileSync(SSL_CERT_PATH), + key: fs.readFileSync(SSL_KEY_PATH), + }); + } + } catch (err) { + logger.error('[GUACWS] Could not load SSL certificate/key, please check the SSL certificate key and path exist and are valid'); + return; + } + } + const websocketOptions = httpsServer ? { server: httpsServer } : { port: websocketPort }; const guacdOptions = { host: guacdHost, @@ -61,21 +80,21 @@ function start(cryptKey, cryptCypher , websocketPort , guacdHost, guacdPort) { const callbacks = { processConnectionSettings: function (settings, callback) { if (settings.userFolder) { - settings.connection['drive-path'] = USER_DRIVE_ROOT + '/user_' + settings.userFolder; + settings.connection['drive-path'] = `${USER_DRIVE_ROOT}/user_${settings.userFolder}`; } callback(null, settings); } }; - logger.info('[GUACWS] WebSocket on ws://0.0.0.0:' + websocketPort); - logger.info('[GUACWS] GuacD host on ' + guacdHost + ':' + guacdPort); + logger.info(`[GUACWS] WebSocket on ${httpsServer ? 'wss' : 'ws'}://0.0.0.0:${websocketPort}`); + logger.info(`[GUACWS] GuacD host on ${guacdHost}:${guacdPort}`); return new GuacamoleLite(logger, websocketOptions, guacdOptions, clientOptions, callbacks); } const server = start(CRYPT_SECRET, CRYPT_CYPHER, PORT, GUACD_HOST, GUACD_PORT); if (server) { - logger.info('[GUACWS] WebSocket Tunnel running on ws://0.0.0.0:' + PORT); + logger.info('[GUACWS] WebSocket Tunnel running'); } else { logger.error('[GUACWS] Failed to start WebSocket Tunnel'); }