83 lines
2.7 KiB
TypeScript
83 lines
2.7 KiB
TypeScript
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');
|
|
}
|