diff --git a/utils/helpers.ts b/utils/helpers.ts index 73cb261..65b342d 100644 --- a/utils/helpers.ts +++ b/utils/helpers.ts @@ -133,7 +133,10 @@ export const capitalize = (str: string): string => { // Validation Helpers export const isValidEmail = (email: string): boolean => { - const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + // Limit input length to prevent ReDoS attacks + if (!email || email.length > 254) return false; + // Simple and safe email regex (non-backtracking) + const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/; return emailRegex.test(email); }; @@ -157,9 +160,15 @@ export const deepClone = (obj: T): T => { return JSON.parse(JSON.stringify(obj)); }; -// Generate Random ID +// Generate Random ID (cryptographically secure) export const generateId = (): string => { - return Math.random().toString(36).substring(2) + Date.now().toString(36); + if (typeof window !== 'undefined' && window.crypto) { + const array = new Uint32Array(2); + window.crypto.getRandomValues(array); + return array[0].toString(36) + array[1].toString(36) + Date.now().toString(36); + } + // Fallback for SSR (non-sensitive context) + return Date.now().toString(36) + Math.random().toString(36).substring(2); }; // Debounce Function