import { createHash } from 'node:crypto'; import { IdentifierType } from './types'; import { normalizeEmail, normalizePhone, normalizeLegalName, normalizeCardNumber, normalizePaymentAppId, normalizeCanvasFp, normalizeWebglFp, normalizeAudioFp, normalizeWebrtcLocalIp, normalizeScreenGeometry, normalizeTimezoneLocale, normalizeFontSet, normalizeHardwareProfile, normalizeTypingCadence, normalizeMouseDynamics, } from './normalizers'; /** * Normalize an identifier value according to its type before hashing. * * Dispatches to the appropriate type-specific normalizer, ensuring * consistent matching regardless of input formatting. */ export function normalizeIdentifier(type: IdentifierType, value: string): string { switch (type) { case IdentifierType.EMAIL: return normalizeEmail(value); case IdentifierType.PHONE: return normalizePhone(value); case IdentifierType.LEGAL_NAME: return normalizeLegalName(value); case IdentifierType.CARD_HASH: return normalizeCardNumber(value); case IdentifierType.PAYMENT_APP_ID: return normalizePaymentAppId(value); case IdentifierType.DEVICE_FP: case IdentifierType.IP_ADDRESS: case IdentifierType.USERNAME: return value.trim().toLowerCase(); case IdentifierType.CANVAS_FP: return normalizeCanvasFp(value); case IdentifierType.WEBGL_FP: return normalizeWebglFp(value); case IdentifierType.AUDIO_FP: return normalizeAudioFp(value); case IdentifierType.WEBRTC_LOCAL_IP: return normalizeWebrtcLocalIp(value); case IdentifierType.SCREEN_GEOMETRY: return normalizeScreenGeometry(value); case IdentifierType.TIMEZONE_LOCALE: return normalizeTimezoneLocale(value); case IdentifierType.FONT_SET: return normalizeFontSet(value); case IdentifierType.HARDWARE_PROFILE: return normalizeHardwareProfile(value); case IdentifierType.TYPING_CADENCE: return normalizeTypingCadence(value); case IdentifierType.MOUSE_DYNAMICS: return normalizeMouseDynamics(value); } } /** * Hash an identifier value using SHA-256 after normalization. * * The pepper MUST be provided as a parameter — this function has * no dependency on environment variables or NestJS config. * * @param type - The identifier type (determines normalization strategy) * @param value - The raw identifier value * @param pepper - Secret pepper value for hash salting * @returns Hex-encoded SHA-256 hash of the normalized value + pepper */ export function hashIdentifier(type: IdentifierType, value: string, pepper: string): string { const normalized = normalizeIdentifier(type, value); return createHash('sha256') .update(normalized + pepper) .digest('hex'); }