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:
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user