import crypto from 'crypto'; import bcrypt from 'bcrypt'; export interface HashResult { plaintext: string; md5: string; sha1: string; sha256: string; sha512: string; bcrypt: string; } /** * Generate all common hashes for a given plaintext */ export async function generateHashes(plaintext: string): Promise { const bcryptHash = await bcrypt.hash(plaintext, 10); return { plaintext, md5: crypto.createHash('md5').update(plaintext).digest('hex'), sha1: crypto.createHash('sha1').update(plaintext).digest('hex'), sha256: crypto.createHash('sha256').update(plaintext).digest('hex'), sha512: crypto.createHash('sha512').update(plaintext).digest('hex'), bcrypt: bcryptHash, }; } /** * Detect hash type based on length and format */ export function detectHashType(hash: string): string | null { const cleanHash = hash.trim().toLowerCase(); // MD5: 32 hex characters if (/^[a-f0-9]{32}$/i.test(cleanHash)) { return 'md5'; } // SHA1: 40 hex characters if (/^[a-f0-9]{40}$/i.test(cleanHash)) { return 'sha1'; } // SHA256: 64 hex characters if (/^[a-f0-9]{64}$/i.test(cleanHash)) { return 'sha256'; } // SHA512: 128 hex characters if (/^[a-f0-9]{128}$/i.test(cleanHash)) { return 'sha512'; } // BCrypt: starts with $2a$, $2b$, $2x$, or $2y$ if (/^\$2[abxy]\$/.test(cleanHash)) { return 'bcrypt'; } return null; } /** * Check if a string is a valid hash */ export function isHash(input: string): boolean { return detectHashType(input) !== null; } /** * Verify a plaintext against a bcrypt hash */ export async function verifyBcrypt(plaintext: string, hash: string): Promise { try { return await bcrypt.compare(plaintext, hash); } catch (_error) { return false; } }