From 86888d9ed05ff0b6a756d988a9b48fb242dfd384 Mon Sep 17 00:00:00 2001 From: Karsten Hassel Date: Sat, 7 Feb 2026 23:59:24 +0100 Subject: [PATCH 1/3] allow environment variables in cors urls, optimize replace regex --- js/node_helper.js | 2 +- js/server_functions.js | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/js/node_helper.js b/js/node_helper.js index 952db968c6..02b55607f5 100644 --- a/js/node_helper.js +++ b/js/node_helper.js @@ -90,7 +90,7 @@ const NodeHelper = Class.extend({ socket.onAny((notification, payload) => { if (config.hideConfigSecrets && payload && typeof payload === "object") { try { - const payloadStr = JSON.stringify(payload).replaceAll(/\*\*(SECRET_.*)\*\*/g, (match, group) => { + const payloadStr = JSON.stringify(payload).replaceAll(/\*\*(SECRET_[^*]+)\*\*/g, (match, group) => { return process.env[group]; }); this.socketNotificationReceived(notification, JSON.parse(payloadStr)); diff --git a/js/server_functions.js b/js/server_functions.js index a2f0ea0557..4024c352d0 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -35,6 +35,11 @@ async function cors (req, res) { return res.status(400).send(url); } else { url = match[1]; + if (config.hideConfigSecrets) { + url = url.replaceAll(/\*\*(SECRET_[^*]+)\*\*/g, (match, group) => { + return process.env[group]; + }); + } const headersToSend = getHeadersToSend(req.url); const expectedReceivedHeaders = geExpectedReceivedHeaders(req.url); From b0bfe0a4728ca9489b3cba082a06474a2f4571d9 Mon Sep 17 00:00:00 2001 From: Karsten Hassel Date: Sun, 8 Feb 2026 00:24:23 +0100 Subject: [PATCH 2/3] remove copy/paste --- js/node_helper.js | 5 ++--- js/server_functions.js | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/js/node_helper.js b/js/node_helper.js index 02b55607f5..8910699930 100644 --- a/js/node_helper.js +++ b/js/node_helper.js @@ -1,6 +1,7 @@ const express = require("express"); const Log = require("logger"); const Class = require("./class"); +const { replaceSecretPlaceholder } = require("#server_functions"); const NodeHelper = Class.extend({ init () { @@ -90,9 +91,7 @@ const NodeHelper = Class.extend({ socket.onAny((notification, payload) => { if (config.hideConfigSecrets && payload && typeof payload === "object") { try { - const payloadStr = JSON.stringify(payload).replaceAll(/\*\*(SECRET_[^*]+)\*\*/g, (match, group) => { - return process.env[group]; - }); + const payloadStr = replaceSecretPlaceholder(JSON.stringify(payload)); this.socketNotificationReceived(notification, JSON.parse(payloadStr)); } catch (e) { Log.error("Error substituting variables in payload: ", e); diff --git a/js/server_functions.js b/js/server_functions.js index 4024c352d0..063e9cfe35 100644 --- a/js/server_functions.js +++ b/js/server_functions.js @@ -13,6 +13,17 @@ function getStartup (req, res) { res.send(startUp); } +/** + * A method that replaces the secret placeholders `**SECRET_ABC**` with the environment variable SECRET_ABC + * @param {string} input - the input string + * @returns {string} the input with real variable content + */ +function replaceSecretPlaceholder (input) { + return input.replaceAll(/\*\*(SECRET_[^*]+)\*\*/g, (match, group) => { + return process.env[group]; + }); +} + /** * A method that forwards HTTP Get-methods to the internet to avoid CORS-errors. * @@ -35,10 +46,10 @@ async function cors (req, res) { return res.status(400).send(url); } else { url = match[1]; - if (config.hideConfigSecrets) { - url = url.replaceAll(/\*\*(SECRET_[^*]+)\*\*/g, (match, group) => { - return process.env[group]; - }); + if (typeof config !== "undefined") { + if (config.hideConfigSecrets) { + url = replaceSecretPlaceholder(url); + } } const headersToSend = getHeadersToSend(req.url); @@ -191,4 +202,4 @@ function getConfigFilePath () { return path.resolve(global.configuration_file || `${global.root_path}/config/config.js`); } -module.exports = { cors, getHtml, getVersion, getStartup, getEnvVars, getEnvVarsAsObj, getUserAgent, getConfigFilePath }; +module.exports = { cors, getHtml, getVersion, getStartup, getEnvVars, getEnvVarsAsObj, getUserAgent, getConfigFilePath, replaceSecretPlaceholder }; From d927b463ae8d3301c37d2bc638b3106ae90cbe95 Mon Sep 17 00:00:00 2001 From: Karsten Hassel Date: Sun, 8 Feb 2026 15:10:56 +0100 Subject: [PATCH 3/3] add unit tests --- tests/unit/functions/server_functions_spec.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/tests/unit/functions/server_functions_spec.js b/tests/unit/functions/server_functions_spec.js index 7596577309..c0953d4877 100644 --- a/tests/unit/functions/server_functions_spec.js +++ b/tests/unit/functions/server_functions_spec.js @@ -1,6 +1,23 @@ -const { cors, getUserAgent } = require("#server_functions"); +const { cors, getUserAgent, replaceSecretPlaceholder } = require("#server_functions"); describe("server_functions tests", () => { + describe("The replaceSecretPlaceholder method", () => { + it("Calls string without secret placeholder", () => { + const teststring = "test string without secret placeholder"; + const result = replaceSecretPlaceholder(teststring); + expect(result).toBe(teststring); + }); + + it("Calls string with 2 secret placeholders", () => { + const teststring = "test string with secret1=**SECRET_ONE** and secret2=**SECRET_TWO**"; + process.env.SECRET_ONE = "secret1"; + process.env.SECRET_TWO = "secret2"; + const resultstring = `test string with secret1=${process.env.SECRET_ONE} and secret2=${process.env.SECRET_TWO}`; + const result = replaceSecretPlaceholder(teststring); + expect(result).toBe(resultstring); + }); + }); + describe("The cors method", () => { let fetchResponse; let fetchResponseHeadersGet;