Harden auth, payments, and frontend against review findings.

Close exploitable gaps in booking/payment flows, enforce token versioning and account checks, gate sensitive payment data, and add middleware plus input validation across admin routes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Michilis
2026-06-24 19:59:02 +00:00
co-authored by Cursor
parent fc4af38e8a
commit a6840ea953
37 changed files with 1432 additions and 528 deletions
+4 -3
View File
@@ -314,10 +314,11 @@ export const paymentOptionsApi = {
body: JSON.stringify(data),
}),
// Event-specific options (merged with global)
getForEvent: (eventId: string) =>
// Event-specific options (merged with global). Pass ticketId after booking to
// retrieve bank/TPago credentials gated behind the booking capability token.
getForEvent: (eventId: string, ticketId?: string) =>
fetchApi<{ paymentOptions: PaymentOptionsConfig; hasOverrides: boolean }>(
`/api/payment-options/event/${eventId}`
`/api/payment-options/event/${eventId}${ticketId ? `?ticketId=${encodeURIComponent(ticketId)}` : ''}`
),
// Event overrides (admin only)
+31
View File
@@ -0,0 +1,31 @@
/**
* Returns a safe internal redirect path, or the provided fallback.
*
* Only same-origin relative paths are allowed (must start with a single "/" and not
* "//", which the browser treats as protocol-relative -> external). This prevents
* open-redirect attacks via a `?redirect=` parameter.
*/
export function safeInternalPath(value: string | null | undefined, fallback: string = '/'): string {
if (!value) return fallback;
// Must be a relative path rooted at "/", but not "//" or "/\" (protocol-relative).
if (!value.startsWith('/')) return fallback;
if (value.startsWith('//') || value.startsWith('/\\')) return fallback;
// Reject attempts to smuggle a scheme or control characters.
if (/[\x00-\x1f]/.test(value) || value.includes('\\')) return fallback;
return value;
}
/**
* Returns true if a URL is safe to use as an external navigation target:
* an absolute https:// URL, or a same-origin relative path.
*/
export function isSafeExternalUrl(value: string | null | undefined): boolean {
if (!value) return false;
if (value.startsWith('/') && !value.startsWith('//') && !value.startsWith('/\\')) return true;
try {
const url = new URL(value);
return url.protocol === 'https:';
} catch {
return false;
}
}