Add E.164 input validation for phone numbers (FRE-4506)
- Extract phone validation to reusable utility (src/utils/phone-validation.ts) - Use libphonenumber-js for strict E.164 format validation - Normalize accepted numbers to canonical E.164 format - Add 22 comprehensive validation tests covering valid/invalid formats - Update existing tests to use valid E.164 test numbers - All 56 tests passing Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -2,6 +2,7 @@ import { PrismaClient, SpamFeedback, SpamRule, SpamAuditLog } from '@prisma/clie
|
||||
import { FieldEncryptionService } from '@shieldai/db';
|
||||
import { spamConfig, spamFeatureFlags } from '../config/spamshield.config';
|
||||
import { CircuitBreaker, CircuitBreakerError, CircuitState, CircuitBreakerMetrics } from '../circuit-breaker';
|
||||
import { validatePhoneNumber as validateE164 } from '../utils/phone-validation';
|
||||
|
||||
const prisma = new PrismaClient() as PrismaClient & {
|
||||
spamFeedback: {
|
||||
@@ -269,11 +270,7 @@ export class SpamShieldService {
|
||||
}
|
||||
|
||||
private validatePhoneNumber(phoneNumber: string): string {
|
||||
if (phoneNumber.length < spamConfig.minPhoneNumberLength ||
|
||||
phoneNumber.length > spamConfig.maxPhoneNumberLength) {
|
||||
throw new Error(`Invalid phone number format: ${phoneNumber}`);
|
||||
}
|
||||
return phoneNumber;
|
||||
return validateE164(phoneNumber);
|
||||
}
|
||||
|
||||
private async getActiveRules(): Promise<Array<{ id: string; pattern: string }>> {
|
||||
|
||||
25
services/spamshield/src/utils/phone-validation.ts
Normal file
25
services/spamshield/src/utils/phone-validation.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
import { isValidPhoneNumber, parsePhoneNumber } from 'libphonenumber-js';
|
||||
|
||||
export class PhoneNumberValidationError extends Error {
|
||||
constructor(public readonly originalInput: string) {
|
||||
super(
|
||||
`Invalid E.164 phone number format: ${originalInput}. Expected format: +[country code][number] (e.g., +14155552671)`
|
||||
);
|
||||
this.name = 'PhoneNumberValidationError';
|
||||
}
|
||||
}
|
||||
|
||||
export function validatePhoneNumber(phoneNumber: string): string {
|
||||
const trimmed = phoneNumber.trim();
|
||||
|
||||
if (!isValidPhoneNumber(trimmed)) {
|
||||
throw new PhoneNumberValidationError(phoneNumber);
|
||||
}
|
||||
|
||||
const parsed = parsePhoneNumber(trimmed);
|
||||
if (!parsed || !parsed.number) {
|
||||
throw new PhoneNumberValidationError(phoneNumber);
|
||||
}
|
||||
|
||||
return parsed.number;
|
||||
}
|
||||
Reference in New Issue
Block a user