From 1fb999d73be66006b49ad845369c83d8c870c31a Mon Sep 17 00:00:00 2001 From: Michelle Date: Sat, 28 Feb 2026 20:02:15 +0100 Subject: [PATCH] Refactor theme validation to dynamically import themes from the source directory --- server/routes/auth.js | 7 ++----- server/routes/branding.js | 8 ++------ 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/server/routes/auth.js b/server/routes/auth.js index 117f0a9..8c5137c 100644 --- a/server/routes/auth.js +++ b/server/routes/auth.js @@ -11,6 +11,7 @@ import { getDb } from '../config/database.js'; import redis from '../config/redis.js'; import { authenticateToken, generateToken } from '../middleware/auth.js'; import { isMailerConfigured, sendVerificationEmail } from '../config/mailer.js'; +import { themes } from '../../src/themes/index.js'; if (!process.env.JWT_SECRET) { console.error('FATAL: JWT_SECRET environment variable is not set.'); @@ -33,11 +34,7 @@ function makeRedisStore(prefix) { // ── Validation helpers ───────────────────────────────────────────────────── const EMAIL_RE = /^[^\s@]{1,64}@[^\s@]{1,253}\.[^\s@]{2,}$/; -const VALID_THEMES = new Set([ - 'light', 'dark', 'dracula', 'mocha', 'latte', 'nord', 'tokyo-night', - 'gruvbox-dark', 'gruvbox-light', 'rose-pine', 'rose-pine-dawn', - 'solarized-dark', 'solarized-light', 'one-dark', 'github-dark', 'scrunkly-cat', -]); +const VALID_THEMES = new Set(themes.map(t => t.id)); const VALID_LANGUAGES = new Set(['en', 'de']); // Allowlist for CSS color values – only permits hsl(), hex (#rgb/#rrggbb) and plain names diff --git a/server/routes/branding.js b/server/routes/branding.js index 0349633..19fb580 100644 --- a/server/routes/branding.js +++ b/server/routes/branding.js @@ -5,18 +5,14 @@ import fs from 'fs'; import { fileURLToPath } from 'url'; import { getDb } from '../config/database.js'; import { authenticateToken, requireAdmin } from '../middleware/auth.js'; +import { themes } from '../../src/themes/index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); const router = Router(); -// Allowlist of valid theme IDs (keep in sync with src/themes/index.js) -const VALID_THEMES = new Set([ - 'light', 'dark', 'dracula', 'mocha', 'latte', 'nord', 'tokyo-night', - 'gruvbox-dark', 'gruvbox-light', 'rose-pine', 'rose-pine-dawn', - 'solarized-dark', 'solarized-light', 'one-dark', 'github-dark', 'scrunkly-cat', -]); +const VALID_THEMES = new Set(themes.map(t => t.id)); // Ensure uploads/branding directory exists const brandingDir = path.join(__dirname, '..', '..', 'uploads', 'branding');