/**
 * Sanitizes a `?redirect=` / `?next=` URL parameter to prevent open-redirect attacks.
 *
 * Accepts only same-origin absolute paths. Uses URL parsing to reliably detect
 * protocol-relative URLs, external origins, and percent-encoded bypasses like
 * `/%2F%2Fevil.com` which would otherwise escape a simple string-prefix check.
 *
 * @param raw - Raw value from URL search params (may be null).
 * @returns A safe redirect path, defaulting to `'/'`.
 */
export function sanitizeRedirect(raw: string | null): string {
  if (!raw) return '/';
  try {
    // Decode percent-encoding first to catch bypasses like /%2F%2Fevil.com → //evil.com.
    // Double-decode to catch double-encoded variants (e.g. %252F → %2F → /).
    let decoded: string;
    try {
      const once = decodeURIComponent(raw);
      decoded = decodeURIComponent(once);
    } catch (err) {
      captureCaught(err, {
        scope: 'lib.sanitize-redirect.decode',
        severity: 'info',
      });
      decoded = raw;
    }
    // Parse against a dummy origin. If the resolved URL has a different origin,
    // the input was absolute/external (or percent-encoded to appear relative).
    const parsed = new URL(decoded, 'http://x');
    if (parsed.origin !== 'http://x') return '/';
    // Return only the path + search + hash — never the origin portion.
    const safe = parsed.pathname + parsed.search + parsed.hash;
    return safe || '/';
  } catch (err) {
    captureCaught(err, {
      scope: 'lib.sanitize-redirect.parse',
      severity: 'info',
    });
    // Malformed URL — fall back to safe default.
    return '/';
  }
}
import { captureCaught } from '@/lib/observability';
