62 lines
1.9 KiB
TypeScript
62 lines
1.9 KiB
TypeScript
import crypto from 'crypto'
|
|
|
|
export function sanitizeHtml(input: string): string {
|
|
return input
|
|
.replace(/[<>'"&]/g, (char) => {
|
|
switch (char) {
|
|
case '<': return '<'
|
|
case '>': return '>'
|
|
case '"': return '"'
|
|
case "'": return '''
|
|
case '&': return '&'
|
|
default: return char
|
|
}
|
|
})
|
|
}
|
|
|
|
export function validateDomain(domain: string): boolean {
|
|
const domainRegex = /^[a-zA-Z0-9][a-zA-Z0-9-]{0,61}[a-zA-Z0-9]?\.[a-zA-Z]{2,}$/
|
|
return domainRegex.test(domain) && domain.length <= 253
|
|
}
|
|
|
|
export function isValidIPAddress(ip: string): boolean {
|
|
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/
|
|
const ipv6Regex = /^([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$/
|
|
|
|
if (ipv4Regex.test(ip)) {
|
|
return ip.split('.').every(part => {
|
|
const num = parseInt(part, 10)
|
|
return num >= 0 && num <= 255
|
|
})
|
|
}
|
|
|
|
return ipv6Regex.test(ip)
|
|
}
|
|
|
|
export function hashPassword(password: string, salt?: string): { hash: string, salt: string } {
|
|
const finalSalt = salt || crypto.randomBytes(32).toString('hex')
|
|
const hash = crypto.pbkdf2Sync(password, finalSalt, 100000, 64, 'sha256').toString('hex')
|
|
return { hash, salt: finalSalt }
|
|
}
|
|
|
|
export function verifyPassword(password: string, hash: string, salt: string): boolean {
|
|
const { hash: computedHash } = hashPassword(password, salt)
|
|
return crypto.timingSafeEqual(Buffer.from(hash, 'hex'), Buffer.from(computedHash, 'hex'))
|
|
}
|
|
|
|
export function generateSecureToken(length = 32): string {
|
|
return crypto.randomBytes(length).toString('hex')
|
|
}
|
|
|
|
export function rateLimitKey(req: any): string {
|
|
const forwarded = req.headers['x-forwarded-for']
|
|
const ip = forwarded ? forwarded.split(',')[0] : req.connection?.remoteAddress
|
|
return `rate_limit:${ip || 'unknown'}`
|
|
}
|
|
|
|
export class SecurityError extends Error {
|
|
constructor(message: string, public code: string) {
|
|
super(message)
|
|
this.name = 'SecurityError'
|
|
}
|
|
} |