7b6cd4d965
- 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
155 lines
3.7 KiB
TypeScript
155 lines
3.7 KiB
TypeScript
/**
|
|
* 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;
|
|
}
|