From 2503eb92afd99e116d3d13813c96c0abb5e43f58 Mon Sep 17 00:00:00 2001 From: "Torsten Schulz (local)" Date: Wed, 20 May 2026 11:07:56 +0200 Subject: [PATCH] =?UTF-8?q?Aktualisiere=20die=20Version=20auf=201.4.2=20un?= =?UTF-8?q?d=20f=C3=BCge=20Funktionen=20zur=20Fehlerprotokollierung=20und?= =?UTF-8?q?=20Validierung=20von=20Saison-Slugs=20hinzu?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- server/utils/spielplan-data.js | 30 ++++++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index cd411b7..9958cfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "harheimertc-website", - "version": "1.4.1", + "version": "1.4.2", "description": "Moderne Webseite für den Harheimer Tischtennis Club", "private": true, "type": "module", diff --git a/server/utils/spielplan-data.js b/server/utils/spielplan-data.js index 72bb1ed..42ec826 100644 --- a/server/utils/spielplan-data.js +++ b/server/utils/spielplan-data.js @@ -75,6 +75,26 @@ function seasonSlugToLabel(slug) { return `20${match[1]}/${match[2]}` } +function logReadError(message, filePath, error) { + console.error(message, { filePath, error }) +} + +function requireSeasonSlug(seasonSlug) { + const value = String(seasonSlug || '') + if (!SEASON_SLUG_PATTERN.test(value)) { + throw new Error(`Ungueltiger Spielplan-Saison-Slug: ${value}`) + } + return value +} + +function normalizeSpielplanCsvPath(csvPath) { + const value = String(csvPath || '') + if (value.includes('\0') || path.basename(value) !== 'spielplan.csv') { + throw new Error('Ungueltiger Spielplan-CSV-Pfad') + } + return path.normalize(value) +} + export function getCurrentSeasonSlug(date = new Date()) { const year = date.getFullYear() const month = date.getMonth() @@ -353,7 +373,7 @@ async function readFirstExistingJson(paths) { } } catch (error) { if (error.code !== 'ENOENT') { - console.error(`Fehler beim Lesen der Spielplan-JSON ${filePath}:`, error) + logReadError('Fehler beim Lesen der Spielplan-JSON', filePath, error) } } } @@ -374,7 +394,7 @@ async function readFirstExistingCsv(paths) { } } catch (error) { if (error.code !== 'ENOENT') { - console.error(`Fehler beim Lesen der Spielplan-CSV ${filePath}:`, error) + logReadError('Fehler beim Lesen der Spielplan-CSV', filePath, error) } } } @@ -419,7 +439,7 @@ export async function listSpielplanSeasons() { entries = await fs.readdir(directory) } catch (error) { if (error.code !== 'ENOENT') { - console.error(`Fehler beim Lesen des Spielplan-Saisonverzeichnisses ${directory}:`, error) + logReadError('Fehler beim Lesen des Spielplan-Saisonverzeichnisses', directory, error) } continue } @@ -468,5 +488,7 @@ export async function readSpielplanData(options = {}) { } export function getSpielplanSeasonJsonPathForCsvPath(csvPath, seasonSlug) { - return path.join(path.dirname(csvPath), 'spielplaene', `spielplan-${seasonSlug}.json`) + const safeCsvPath = normalizeSpielplanCsvPath(csvPath) + const safeSeasonSlug = requireSeasonSlug(seasonSlug) + return `${path.dirname(safeCsvPath)}/spielplaene/spielplan-${safeSeasonSlug}.json` }