freealberta/influence/app/utils/validators.js

138 lines
3.9 KiB
JavaScript

// Validate Canadian postal code format
function validatePostalCode(postalCode) {
const regex = /^[A-Za-z]\d[A-Za-z]\s?\d[A-Za-z]\d$/;
return regex.test(postalCode);
}
// Validate Alberta postal code (starts with T)
function validateAlbertaPostalCode(postalCode) {
const formatted = postalCode.replace(/\s/g, '').toUpperCase();
return formatted.startsWith('T') && validatePostalCode(postalCode);
}
// Validate email format
function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// Format postal code to standard format (A1A 1A1)
function formatPostalCode(postalCode) {
const cleaned = postalCode.replace(/\s/g, '').toUpperCase();
if (cleaned.length === 6) {
return `${cleaned.slice(0, 3)} ${cleaned.slice(3)}`;
}
return cleaned;
}
// Sanitize string input to prevent XSS
function sanitizeString(str) {
if (typeof str !== 'string') return str;
return str
.replace(/[<>]/g, '') // Remove angle brackets
.trim()
.substring(0, 1000); // Limit length
}
// Validate required fields in request body
function validateRequiredFields(body, requiredFields) {
const errors = [];
requiredFields.forEach(field => {
if (!body[field] || (typeof body[field] === 'string' && body[field].trim() === '')) {
errors.push(`${field} is required`);
}
});
return errors;
}
// Check if string contains potentially harmful content
function containsSuspiciousContent(str) {
const suspiciousPatterns = [
/<script/i,
/javascript:/i,
/on\w+\s*=/i,
/<iframe/i,
/<object/i,
/<embed/i
];
return suspiciousPatterns.some(pattern => pattern.test(str));
}
// Generate URL-friendly slug from text
function generateSlug(text) {
return text
.toLowerCase()
.trim()
.replace(/[^\w\s-]/g, '') // Remove special characters
.replace(/[\s_-]+/g, '-') // Replace spaces and underscores with hyphens
.replace(/^-+|-+$/g, ''); // Remove leading/trailing hyphens
}
// Validate slug format
function validateSlug(slug) {
const slugPattern = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
return slugPattern.test(slug) && slug.length >= 3 && slug.length <= 100;
}
// Validate response submission
function validateResponse(data) {
const { representative_name, representative_level, response_type, response_text } = data;
// Check required fields
if (!representative_name || representative_name.trim() === '') {
return { valid: false, error: 'Representative name is required' };
}
if (!representative_level || representative_level.trim() === '') {
return { valid: false, error: 'Representative level is required' };
}
// Validate representative level
const validLevels = ['Federal', 'Provincial', 'Municipal', 'School Board'];
if (!validLevels.includes(representative_level)) {
return { valid: false, error: 'Invalid representative level' };
}
if (!response_type || response_type.trim() === '') {
return { valid: false, error: 'Response type is required' };
}
// Validate response type
const validTypes = ['Email', 'Letter', 'Phone Call', 'Meeting', 'Social Media', 'Other'];
if (!validTypes.includes(response_type)) {
return { valid: false, error: 'Invalid response type' };
}
if (!response_text || response_text.trim() === '') {
return { valid: false, error: 'Response text is required' };
}
// Check for suspicious content
if (containsSuspiciousContent(response_text)) {
return { valid: false, error: 'Response contains invalid content' };
}
// Validate email if provided
if (data.submitted_by_email && !validateEmail(data.submitted_by_email)) {
return { valid: false, error: 'Invalid email address' };
}
return { valid: true };
}
module.exports = {
validatePostalCode,
validateAlbertaPostalCode,
validateEmail,
formatPostalCode,
sanitizeString,
validateRequiredFields,
containsSuspiciousContent,
generateSlug,
validateSlug,
validateResponse
};