feat(validation): Implement form validation and error handling utilities

- Add validation rules for form fields with XSS protection
- Create API error handler to parse and manage server validation errors
- Integrate validation rules into contact and inquiries forms
- Enhance error handling with user feedback for form submissions
- Introduce unit tests for validation and error handling functionalities
This commit is contained in:
AmirReza Jamali
2026-02-08 13:35:07 +03:30
parent 5fc6469752
commit 7b6cd4d965
9 changed files with 4834 additions and 108 deletions
+154
View File
@@ -0,0 +1,154 @@
/**
* Validation utilities for form fields
* Detects potentially harmful content (XSS patterns) and provides validation rules
*/
// Patterns that indicate potentially malicious content
const DANGEROUS_PATTERNS = [
/<script[\s\S]*?>/i,
/<\/script>/i,
/javascript:/i,
/vbscript:/i,
/on\w+\s*=/i, // onclick=, onerror=, onload=, etc.
/<iframe[\s\S]*?>/i,
/<object[\s\S]*?>/i,
/<embed[\s\S]*?>/i,
/<link[\s\S]*?>/i,
/<meta[\s\S]*?>/i,
/data:\s*text\/html/i,
/expression\s*\(/i, // CSS expression
/url\s*\(\s*["']?\s*javascript:/i,
];
/**
* Checks if text contains potentially dangerous patterns (XSS)
* @param text - The text to check
* @returns true if dangerous patterns are found
*/
export function containsDangerousContent(text: string): boolean {
if (!text) return false;
return DANGEROUS_PATTERNS.some((pattern) => pattern.test(text));
}
/**
* Validation function for react-hook-form that checks for XSS patterns
* @param fieldName - The human-readable name of the field for error messages
* @returns Validation function for react-hook-form
*/
export function createXSSValidator(fieldName: string) {
return (value: string) => {
if (containsDangerousContent(value)) {
return `${fieldName} contains invalid characters or content. Please remove any special HTML tags or scripts.`;
}
return true;
};
}
/**
* Standard validation rules with XSS protection for common field types
*/
export const validationRules = {
fullName: {
required: {
value: true,
message: "Full name is required",
},
minLength: {
value: 2,
message: "Full name must be at least 2 characters",
},
maxLength: {
value: 100,
message: "Full name must not exceed 100 characters",
},
validate: {
noXSS: createXSSValidator("Full name"),
},
},
email: {
required: {
value: true,
message: "Email is required",
},
pattern: {
value: /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
message: "Please enter a valid email address",
},
validate: {
noXSS: createXSSValidator("Email"),
},
},
phone: {
required: {
value: true,
message: "Phone number is required",
},
minLength: {
value: 10,
message: "Phone number must be at least 10 characters",
},
maxLength: {
value: 20,
message: "Phone number must not exceed 20 characters",
},
pattern: {
value: /^[+\d\s()-]+$/,
message: "Please enter a valid phone number (digits, +, spaces, parentheses, and dashes only)",
},
},
message: {
required: {
value: true,
message: "Message is required",
},
minLength: {
value: 10,
message: "Message must be at least 10 characters",
},
maxLength: {
value: 1000,
message: "Message must not exceed 1000 characters",
},
validate: {
noXSS: createXSSValidator("Message"),
},
},
companyName: {
maxLength: {
value: 200,
message: "Company name must not exceed 200 characters",
},
validate: {
noXSS: createXSSValidator("Company name"),
},
},
};
/**
* Creates validation rules for a field with optional XSS check
* @param fieldName - Human-readable field name
* @param isRequired - Whether the field is required
* @param additionalRules - Additional validation rules to merge
*/
export function createFieldValidation(
fieldName: string,
isRequired: boolean = false,
additionalRules: Record<string, unknown> = {}
) {
const rules: Record<string, unknown> = {
validate: {
noXSS: createXSSValidator(fieldName),
},
...additionalRules,
};
if (isRequired) {
rules.required = `${fieldName} is required`;
}
return rules;
}