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:
@@ -3,6 +3,7 @@
|
||||
import { useEffect, useRef, useState, useCallback } from 'react';
|
||||
import { useAuth } from '@/context/AuthContext';
|
||||
import { useLanguage } from '@/context/LanguageContext';
|
||||
import { safeInternalPath } from '@/lib/safeRedirect';
|
||||
import toast from 'react-hot-toast';
|
||||
|
||||
declare global {
|
||||
@@ -82,10 +83,9 @@ export default function GoogleSignInButton({
|
||||
toast.success(locale === 'es' ? 'Bienvenido!' : 'Welcome!');
|
||||
onSuccess?.();
|
||||
|
||||
// Use window.location for navigation to ensure clean state
|
||||
if (redirectTo) {
|
||||
window.location.href = redirectTo;
|
||||
}
|
||||
// Use window.location for navigation to ensure clean state.
|
||||
// Constrain to a same-origin path to avoid open redirects.
|
||||
window.location.href = safeInternalPath(redirectTo, '/dashboard');
|
||||
} catch (error: unknown) {
|
||||
const errorMessage = error instanceof Error ? error.message : 'Google login failed';
|
||||
const displayError = locale === 'es' ? 'Error al iniciar sesion con Google' : errorMessage;
|
||||
|
||||
@@ -21,6 +21,17 @@ function extractLastUpdated(contentMarkdown: string, updatedAt?: string): string
|
||||
return match ? match[1].trim() : updatedAt;
|
||||
}
|
||||
|
||||
// Only permit safe link schemes. Anything else (javascript:, data:, etc.) is dropped
|
||||
// so a malicious markdown link can't execute script when clicked.
|
||||
function sanitizeHref(href?: string): string | undefined {
|
||||
if (!href) return undefined;
|
||||
const trimmed = href.trim();
|
||||
// Allow relative/anchor/protocol-relative-safe links
|
||||
if (trimmed.startsWith('/') || trimmed.startsWith('#')) return trimmed;
|
||||
if (/^(https?:|mailto:|tel:)/i.test(trimmed)) return trimmed;
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export default function LegalPageLayout({
|
||||
slug,
|
||||
initialLocale,
|
||||
@@ -141,17 +152,20 @@ export default function LegalPageLayout({
|
||||
{children}
|
||||
</li>
|
||||
),
|
||||
// Style links
|
||||
a: ({ href, children }) => (
|
||||
<a
|
||||
href={href}
|
||||
className="text-primary-dark underline hover:text-primary-yellow transition-colors"
|
||||
target={href?.startsWith('http') ? '_blank' : undefined}
|
||||
rel={href?.startsWith('http') ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
// Style links (with scheme allowlist to block javascript:/data: URLs)
|
||||
a: ({ href, children }) => {
|
||||
const safeHref = sanitizeHref(href);
|
||||
return (
|
||||
<a
|
||||
href={safeHref}
|
||||
className="text-primary-dark underline hover:text-primary-yellow transition-colors"
|
||||
target={safeHref?.startsWith('http') ? '_blank' : undefined}
|
||||
rel={safeHref?.startsWith('http') ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
},
|
||||
// Style horizontal rules
|
||||
hr: () => (
|
||||
<hr className="my-8 border-gray-200" />
|
||||
|
||||
@@ -14,11 +14,18 @@ interface RichTextEditorProps {
|
||||
editable?: boolean;
|
||||
}
|
||||
|
||||
// Escape HTML-significant characters so any raw HTML embedded in the markdown source
|
||||
// is neutralised before we layer our own generated tags on top (defense-in-depth;
|
||||
// the public renderer escapes too, and TipTap sanitizes via its schema).
|
||||
function escapeRawHtml(s: string): string {
|
||||
return s.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
||||
}
|
||||
|
||||
// Convert markdown to HTML for TipTap
|
||||
function markdownToHtml(markdown: string): string {
|
||||
if (!markdown) return '<p></p>';
|
||||
|
||||
let html = markdown;
|
||||
let html = escapeRawHtml(markdown);
|
||||
|
||||
// Convert horizontal rules first (before other processing)
|
||||
html = html.replace(/^---+$/gm, '<hr>');
|
||||
|
||||
Reference in New Issue
Block a user