← back to Wine Finder Next
lib/inputValidation.ts
93 lines
// Input Validation and Sanitization
export function validateBottleId(id: string): boolean {
return /^bottle_\d+_[a-z0-9]{9}$/.test(id);
}
export function validateVoteId(id: string): boolean {
return /^vote_\d+_[a-z0-9]{9}$/.test(id);
}
export function validateMembershipUnitId(id: string): boolean {
return /^unit_\d+_[a-z0-9]{9}$/.test(id);
}
export function validateUserId(id: string): boolean {
return /^user_\d+$/.test(id) || /^[a-z0-9]{40,}$/.test(id);
}
export function validateVoteChoice(choice: string): choice is 'for' | 'against' | 'abstain' {
return ['for', 'against', 'abstain'].includes(choice);
}
export function validateEmail(email: string): boolean {
const emailRegex = /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/;
return emailRegex.test(email) && email.length <= 254;
}
export function validatePrice(price: number): boolean {
return typeof price === 'number' && price > 0 && price < 1000000 && Number.isFinite(price);
}
export function validateQuantity(quantity: number): boolean {
return Number.isInteger(quantity) && quantity > 0 && quantity <= 10000;
}
export function sanitizeString(input: string, maxLength: number = 1000): string {
return input
.replace(/[<>]/g, '')
.replace(/javascript:/gi, '')
.replace(/on\w+=/gi, '')
.slice(0, maxLength)
.trim();
}
export function validateShippingAddress(address: any): boolean {
if (!address || typeof address !== 'object') return false;
const required = ['name', 'addressLine1', 'city', 'state', 'zipCode', 'country', 'phone'];
for (const field of required) {
if (!address[field] || typeof address[field] !== 'string' || address[field].trim() === '') {
return false;
}
}
// Validate ZIP code (basic US format)
if (!/^\d{5}(-\d{4})?$/.test(address.zipCode)) {
return false;
}
// Validate phone (basic format)
if (!/^\+?[\d\s\-()]{10,}$/.test(address.phone)) {
return false;
}
return true;
}
export class ValidationError extends Error {
constructor(message: string) {
super(message);
this.name = 'ValidationError';
}
}
export function validateRequest<T>(
data: any,
schema: Record<string, (value: any) => boolean>
): T {
const errors: string[] = [];
for (const [key, validator] of Object.entries(schema)) {
if (!validator(data[key])) {
errors.push(`Invalid ${key}`);
}
}
if (errors.length > 0) {
throw new ValidationError(errors.join(', '));
}
return data as T;
}