import { z } from 'zod'; export function escapeHtml(unsafe: string): string { if (typeof unsafe !== 'string') return ''; return unsafe .replace(/&/g, '&') .replace(//g, '>') .replace(/"/g, '"') .replace(/'/g, '''); } const rateLimitMap = new Map(); const MAX_REQUESTS = 5; const WINDOW_MS = 10 * 60 * 1000; export function rateLimit(ip: string | undefined | null): boolean { if (!ip) return true; const now = Date.now(); const entry = rateLimitMap.get(ip); if (!entry || entry.expiresAt < now) { rateLimitMap.set(ip, { count: 1, expiresAt: now + WINDOW_MS }); return true; } if (entry.count >= MAX_REQUESTS) { return false; } entry.count++; return true; } export async function verifyRecaptcha(token: string): Promise { const secretKey = process.env.RECAPTCHA_SECRET_KEY; if (!secretKey) return false; try { const res = await fetch(`https://www.google.com/recaptcha/api/siteverify`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', }, body: `secret=${secretKey}&response=${token}`, }); const data = await res.json(); return data.success; } catch (err) { return false; } } export const baseContactSchema = z.object({ name: z.string().min(2, "Imię musi mieć co najmniej 2 znaki").max(100, "Imię jest zbyt długie"), phone: z.string().regex(/^[+\d\s-]{9,20}$/, "Niepoprawny format telefonu"), email: z.string().email("Niepoprawny adres e-mail").max(150, "E-mail jest zbyt długi"), consent: z.string().refine(val => val === "on" || val === "true", "Wymagana zgoda"), });