44 lines
1.3 KiB
JavaScript
44 lines
1.3 KiB
JavaScript
import { createHash, randomInt, timingSafeEqual } from 'node:crypto'
|
|
|
|
/**
|
|
* OTP용 이메일 정규화(소문자·trim)
|
|
* @param {string} email - 원본
|
|
* @returns {string}
|
|
*/
|
|
export const normalizeOtpEmail = (email) => String(email || '').trim().toLowerCase()
|
|
|
|
/**
|
|
* 6자리 숫자 인증 코드 생성
|
|
* @returns {string}
|
|
*/
|
|
export const generateSixDigitOtp = () => String(randomInt(0, 1_000_000)).padStart(6, '0')
|
|
|
|
/**
|
|
* OTP 코드 해시(hex)
|
|
* @param {{ pepper: string, email: string, purpose: string, code: string }} input - 입력
|
|
* @returns {string} sha256 hex
|
|
*/
|
|
export const hashOtpCode = (input) => {
|
|
const payload = `${String(input.pepper || '')}|${normalizeOtpEmail(input.email)}|${String(input.purpose || '')}|${String(input.code || '')}`
|
|
return createHash('sha256').update(payload, 'utf8').digest('hex')
|
|
}
|
|
|
|
/**
|
|
* 두 sha256 hex 문자열을 상수 시간으로 비교한다.
|
|
* @param {string} a - hex
|
|
* @param {string} b - hex
|
|
* @returns {boolean}
|
|
*/
|
|
export const timingSafeEqualHex = (a, b) => {
|
|
try {
|
|
const ba = Buffer.from(String(a || ''), 'hex')
|
|
const bb = Buffer.from(String(b || ''), 'hex')
|
|
if (ba.length !== bb.length || ba.length === 0) {
|
|
return false
|
|
}
|
|
return timingSafeEqual(ba, bb)
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|