更新完善页面

This commit is contained in:
董海洋
2026-06-03 14:15:55 +08:00
parent 4b7ae9c933
commit 1675662537
57 changed files with 7625 additions and 883 deletions
+107
View File
@@ -0,0 +1,107 @@
/**
* 密码加密和验证工具函数
* @module services/utils/password
*/
const crypto = require('crypto')
const N = 16384
const r = 8
const p = 1
const KEYLEN = 64
const SALT_LEN = 16
const MD5_LEN = 32
/**
* 计算 MD5 哈希
* @param {string} str - 输入字符串
* @returns {string} MD5 哈希值(十六进制)
*/
function md5(str) {
return crypto.createHash('md5').update(str).digest('hex')
}
/**
* 使用 scrypt 计算哈希
* @param {string} password - 密码
* @param {Buffer} [saltBuf] - 可选的 salt
* @returns {Object} { salt, hash }
*/
function scryptHash(password, saltBuf) {
const salt = saltBuf || crypto.randomBytes(SALT_LEN)
const derived = crypto.scryptSync(String(password), salt, KEYLEN, { N, r, p, maxmem: 64 * 1024 * 1024 })
return { salt, hash: derived }
}
/**
* 哈希密码(使用 scrypt
* @param {string} password - 密码
* @returns {string} 编码后的密码哈希
*/
function hashPassword(password) {
const { salt, hash } = scryptHash(password)
const saltB64 = salt.toString('base64').replace(/=+$/, '')
const hashB64 = hash.toString('base64').replace(/=+$/, '')
return `scrypt$${N}$${r}$${p}$${saltB64}$${hashB64}`
}
/**
* 验证 scrypt 密码
* @param {string} password - 密码
* @param {string} encoded - 编码后的密码哈希
* @returns {boolean} 是否验证通过
*/
function verifyScrypt(password, encoded) {
try {
const parts = encoded.split('$')
if (parts.length !== 6 || parts[0] !== 'scrypt') return false
const saltB64 = parts[4]
const expectedB64 = parts[5]
const salt = Buffer.from(saltB64, 'base64')
const expected = Buffer.from(expectedB64, 'base64')
const { hash } = scryptHash(password, salt)
if (hash.length !== expected.length) return false
return crypto.timingSafeEqual(hash, expected)
} catch {
return false
}
}
/**
* 验证密码(支持 scrypt 和旧版 MD5
* @param {string} password - 密码
* @param {string} stored - 存储的密码哈希
* @returns {boolean} 是否验证通过
*/
function verifyPassword(password, stored) {
if (!stored) return false
if (stored.startsWith('scrypt$')) return verifyScrypt(password, stored)
if (/^[a-f0-9]{32}$/i.test(stored)) return md5(password).toLowerCase() === stored.toLowerCase()
return false
}
/**
* 检查是否是旧版 MD5 哈希
* @param {string} stored - 存储的密码哈希
* @returns {boolean} 是否是旧版哈希
*/
function isLegacyHash(stored) {
return stored && /^[a-f0-9]{32}$/i.test(stored)
}
/**
* 检查是否需要重新哈希密码
* @param {string} stored - 存储的密码哈希
* @returns {boolean} 是否需要重新哈希
*/
function needsRehash(stored) {
return !stored || !stored.startsWith('scrypt$')
}
module.exports = {
hashPassword,
verifyPassword,
isLegacyHash,
needsRehash,
md5
}