From 12591556a01f3803cf326a1c251a9309d6e13734 Mon Sep 17 00:00:00 2001 From: Luca <102960244+Luca-Timo@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:34:38 +0200 Subject: [PATCH] fix(branding): accept SVG favicons The favicon upload allowed only PNG/ICO, so an SVG favicon was rejected. Accept image/svg+xml (.svg) too - DynamicFavicon already emits the right MIME type and served SVGs are CSP-locked (render-only) by secureStatic. Update the EN/DE help text accordingly. --- backend/src/routes/adminSettings.js | 15 ++++++++++----- frontend/src/i18n/locales/de.json | 2 +- frontend/src/i18n/locales/en.json | 2 +- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/backend/src/routes/adminSettings.js b/backend/src/routes/adminSettings.js index b921f4e1..66898e16 100644 --- a/backend/src/routes/adminSettings.js +++ b/backend/src/routes/adminSettings.js @@ -76,7 +76,8 @@ const faviconUpload = multer({ limits: { fileSize: 2 * 1024 * 1024 }, // 2MB — roomy enough for a 512×512+ square PNG fileFilter: (req, file, cb) => { const allowedMimeTypes = ['image/png', 'image/x-icon', 'image/vnd.microsoft.icon']; - + const name = file.originalname.toLowerCase(); + // For ICO files, we can't use the standard validateFileType if (file.mimetype === 'image/png') { if (validateFileType(file.originalname, file.mimetype, ['image/png'])) { @@ -84,12 +85,16 @@ const faviconUpload = multer({ } else { cb(new Error('Invalid PNG file')); } - } else if (allowedMimeTypes.includes(file.mimetype) && - (file.originalname.toLowerCase().endsWith('.ico') || - file.originalname.toLowerCase().endsWith('.png'))) { + } else if (file.mimetype === 'image/svg+xml' && name.endsWith('.svg')) { + // SVG favicons are supported by modern browsers and are crisp at any + // size. Served SVGs are CSP-locked (no script execution) by the + // secureStatic middleware, so an admin-uploaded SVG is render-only. + cb(null, true); + } else if (allowedMimeTypes.includes(file.mimetype) && + (name.endsWith('.ico') || name.endsWith('.png'))) { cb(null, true); } else { - cb(new Error('Favicon must be PNG or ICO format')); + cb(new Error('Favicon must be PNG, ICO, or SVG format')); } } }); diff --git a/frontend/src/i18n/locales/de.json b/frontend/src/i18n/locales/de.json index 951bfb84..f2763516 100644 --- a/frontend/src/i18n/locales/de.json +++ b/frontend/src/i18n/locales/de.json @@ -1708,7 +1708,7 @@ "currentFavicon": "Aktuelles Favicon", "uploadFavicon": "Favicon hochladen", "removeFavicon": "Favicon entfernen", - "faviconHelp": "PNG- oder ICO-Format. Bitte ein quadratisches Bild verwenden – empfohlen sind 512×512px für eine scharfe Darstellung auf hochauflösenden Bildschirmen; kleinere Größen funktionieren ebenfalls.", + "faviconHelp": "PNG-, ICO- oder SVG-Format. Bitte ein quadratisches Bild verwenden – ein SVG (oder ein 512×512px-PNG) liefert die schärfste Darstellung auf hochauflösenden Bildschirmen; kleinere Größen funktionieren ebenfalls.", "watermarkSettings": "Wasserzeichen-Einstellungen", "enableWatermarks": "Wasserzeichen aktivieren", "watermarkHelp": "Fügen Sie Ihren Firmennamen als Wasserzeichen auf heruntergeladenen Fotos hinzu", diff --git a/frontend/src/i18n/locales/en.json b/frontend/src/i18n/locales/en.json index 97ad94d0..16fdbe80 100644 --- a/frontend/src/i18n/locales/en.json +++ b/frontend/src/i18n/locales/en.json @@ -1297,7 +1297,7 @@ "currentFavicon": "Current favicon", "uploadFavicon": "Upload Favicon", "removeFavicon": "Remove Favicon", - "faviconHelp": "PNG or ICO format. Use a square image — 512×512px is recommended for crisp display on high-resolution screens; smaller sizes work too.", + "faviconHelp": "PNG, ICO, or SVG format. Use a square image — an SVG (or a 512×512px PNG) gives the crispest display on high-resolution screens; smaller sizes work too.", "watermarkSettings": "Watermark Settings", "enableWatermarks": "Enable Watermarks", "watermarkHelp": "Add your company name as a watermark on downloaded photos",