From 093e069ccce9b5c49d91b45fd507bd0efb1eaeb6 Mon Sep 17 00:00:00 2001 From: Maurice <61554723+mauriceboe@users.noreply.github.com> Date: Sat, 6 Jun 2026 16:37:03 +0200 Subject: [PATCH] Backend/frontend hardening & consistency cleanups (#1113) * refactor(auth): session token validation and password-change consistency * refactor(journey): entry field allow-list and public share-link consistency * refactor(mcp): align tool authorization with the REST permission checks * chore: input validation and sanitisation touch-ups (uploads, pdf, maps, backup, csp) --- .../src/components/Map/ReservationOverlay.tsx | 9 +- .../src/components/Map/reservationsMapbox.ts | 7 +- .../components/PDF/JourneyBookPDF.test.tsx | 16 ++++ client/src/components/PDF/JourneyBookPDF.tsx | 9 +- client/src/components/PDF/TripPDF.tsx | 4 +- server/src/mcp/tools/_shared.ts | 20 +++++ server/src/mcp/tools/assignments.ts | 8 +- server/src/mcp/tools/budget.ts | 10 ++- server/src/mcp/tools/collab.ts | 12 ++- server/src/mcp/tools/days.ts | 12 ++- server/src/mcp/tools/packing.ts | 15 +++- server/src/mcp/tools/places.ts | 8 +- server/src/mcp/tools/reservations.ts | 7 +- server/src/mcp/tools/todos.ts | 8 +- server/src/mcp/tools/transports.ts | 5 +- server/src/mcp/tools/trips.ts | 7 +- server/src/middleware/auth.ts | 6 +- server/src/middleware/globalMiddleware.ts | 3 + server/src/nest/auth/auth.controller.ts | 8 +- server/src/nest/budget/budget.controller.ts | 2 +- server/src/nest/budget/budget.service.ts | 4 +- .../nest/journey/journey-public.controller.ts | 8 +- server/src/nest/oidc/oidc.controller.ts | 16 ++++ server/src/services/authService.ts | 29 +++++-- server/src/services/backupService.ts | 13 ++- server/src/services/budgetService.ts | 6 +- server/src/services/journeyService.ts | 10 +++ server/src/services/journeyShareService.ts | 50 ++++++++--- server/src/services/oidcService.ts | 16 +++- server/src/services/tripService.ts | 10 ++- server/tests/integration/oidc.test.ts | 15 ++-- server/tests/unit/middleware/auth.test.ts | 17 ++++ .../unit/nest/journey.controller.test.ts | 25 ++++++ .../tests/unit/nest/oidc.controller.test.ts | 27 ++++-- .../tests/unit/services/authServiceDb.test.ts | 36 ++++++++ .../tests/unit/services/backupService.test.ts | 16 ++++ .../unit/services/budgetServiceDb.test.ts | 83 +++++++++++++++++++ .../unit/services/journeyService.test.ts | 26 ++++++ .../unit/services/journeyShareService.test.ts | 80 +++++++++++++++++- .../tests/unit/services/oidcService.test.ts | 23 ++++- .../tests/unit/services/tripService.test.ts | 41 ++++++++- 41 files changed, 653 insertions(+), 74 deletions(-) create mode 100644 server/tests/unit/services/budgetServiceDb.test.ts diff --git a/client/src/components/Map/ReservationOverlay.tsx b/client/src/components/Map/ReservationOverlay.tsx index cbdf57d9..8db225f8 100644 --- a/client/src/components/Map/ReservationOverlay.tsx +++ b/client/src/components/Map/ReservationOverlay.tsx @@ -3,6 +3,7 @@ import { renderToStaticMarkup } from 'react-dom/server' import { Marker, Polyline, Tooltip, useMap, useMapEvents } from 'react-leaflet' import L from 'leaflet' import { Plane, Train, Ship, Car, Bus, Sailboat, Bike, CarTaxiFront, Route } from 'lucide-react' +import { escapeHtml } from '@trek/shared' import { useSettingsStore } from '../../store/settingsStore' import type { Reservation, ReservationEndpoint } from '../../types' @@ -42,7 +43,7 @@ function useEndpointPane() { function endpointIcon(type: TransportType, label: string | null): L.DivIcon { const { icon: IconCmp, color } = TYPE_META[type] const svg = renderToStaticMarkup(createElement(IconCmp, { size: 13, color: 'white', strokeWidth: 2.5 })) - const labelHtml = label ? `${label}` : '' + const labelHtml = label ? `${escapeHtml(label)}` : '' const estWidth = label ? Math.max(40, label.length * 6 + 28) : 26 return L.divIcon({ className: 'trek-endpoint-marker', @@ -53,7 +54,7 @@ function endpointIcon(type: TransportType, label: string | null): L.DivIcon { border:1.5px solid #fff;color:#fff; font-family:var(--font-system);font-size:11px;font-weight:600;letter-spacing:0.3px;line-height:1; box-sizing:border-box;height:22px;white-space:nowrap; - ">${svg}${labelHtml ? `${label}` : ''}`, + ">${svg}${labelHtml ? `${escapeHtml(label)}` : ''}`, iconSize: [estWidth, 22], iconAnchor: [estWidth / 2, 11], popupAnchor: [0, -11], @@ -172,8 +173,8 @@ function buildStatsHtml(color: string, mainLabel: string | null, subLabel: strin ) + 22 const hasBoth = !!mainLabel && !!subLabel const height = hasBoth ? 36 : 22 - const main = mainLabel ? `${mainLabel}` : '' - const sub = subLabel ? `${subLabel}` : '' + const main = mainLabel ? `${escapeHtml(mainLabel)}` : '' + const sub = subLabel ? `${escapeHtml(subLabel)}` : '' const html = `