diff --git a/src/utils/config/config.js b/src/utils/config/config.js index 65b8866f1..92e8fb460 100644 --- a/src/utils/config/config.js +++ b/src/utils/config/config.js @@ -69,11 +69,11 @@ export function substituteEnvironmentVars(str) { const cachedVars = getCachedEnvironmentVars(); cachedVars.forEach(([key, value]) => { if (key.startsWith(homepageVarPrefix)) { - result = result.replaceAll(`{{${key}}}`, value); + result = result.replaceAll(`{{${key}}}`, () => value); } else if (key.startsWith(homepageFilePrefix)) { const filename = value; const fileContents = readFileSync(filename, "utf8"); - result = result.replaceAll(`{{${key}}}`, fileContents); + result = result.replaceAll(`{{${key}}}`, () => fileContents); } }); } diff --git a/src/utils/config/config.test.js b/src/utils/config/config.test.js index e2936b68c..8d4678e05 100644 --- a/src/utils/config/config.test.js +++ b/src/utils/config/config.test.js @@ -1,4 +1,4 @@ -import { mkdtempSync, writeFileSync } from "node:fs"; +import { mkdtempSync, rmdirSync, unlinkSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import path from "node:path"; @@ -37,6 +37,39 @@ describe("utils/config/config", () => { expect(mod.substituteEnvironmentVars("token={{HOMEPAGE_FILE_SECRET}}")).toBe("token=secret"); }); + it.each(["pa$$word", "pa$&word", "pa$`word", "pa$'word", "pa$1word"])( + "substituteEnvironmentVars preserves literal environment value %j in every occurrence", + async (secret) => { + process.env.HOMEPAGE_VAR_SECRET = secret; + + const mod = await import("./config"); + expect( + mod.substituteEnvironmentVars("before {{HOMEPAGE_VAR_SECRET}} between {{HOMEPAGE_VAR_SECRET}} after"), + ).toBe(`before ${secret} between ${secret} after`); + }, + ); + + it.each(["pa$$word", "pa$&word", "pa$`word", "pa$'word", "pa$1word"])( + "substituteEnvironmentVars preserves literal secret file contents %j in every occurrence", + async (secret) => { + const dir = mkdtempSync(path.join(tmpdir(), "homepage-config-test-")); + const secretPath = path.join(dir, "secret.txt"); + writeFileSync(secretPath, secret, "utf8"); + + try { + process.env.HOMEPAGE_FILE_SECRET = secretPath; + + const mod = await import("./config"); + expect( + mod.substituteEnvironmentVars("before {{HOMEPAGE_FILE_SECRET}} between {{HOMEPAGE_FILE_SECRET}} after"), + ).toBe(`before ${secret} between ${secret} after`); + } finally { + unlinkSync(secretPath); + rmdirSync(dir); + } + }, + ); + it("getSettings reads from HOMEPAGE_CONFIG_DIR and converts layout list to an object", async () => { const dir = mkdtempSync(path.join(tmpdir(), "homepage-settings-test-")); process.env.HOMEPAGE_CONFIG_DIR = dir;