码桶

发现社区成员的开源项目

奶狗 /

ng-webot

公开
main
ng-webot/lib/auth.js
auth.js3.3 KB
const db = require('./db')
const bcrypt = require('bcryptjs')

// 开源单用户版:固定唯一管理员账号
const DEFAULT_ADMIN = 'admin'
const DEFAULT_PW = 'admin123'

class Auth {
  constructor() {}

  /** 当前登录用户(开源单用户版:始终为本地管理员,供 bot 等无会话场景使用) */
  static async currentUser(req) {
    try {
      const id = await Auth.ensureAdmin()
      return await db.row(
        'SELECT id, username, email, is_admin, user_code, ai_persona, created_at FROM users WHERE id=?',
        [id]
      )
    } catch (e) {
      console.error('[auth] currentUser 失败:', e.message)
      return null
    }
  }

  static async requireLogin(req) { return await Auth.currentUser(req) }
  static async requireAdmin(req) { return await Auth.currentUser(req) }

  /** 后台登录:校验账号密码 */
  static async login(username, password) {
    const u = await db.row(
      'SELECT id, username, password_hash, is_admin FROM users WHERE username=? AND is_admin=1',
      [username]
    )
    if (!u) return { ok: false, msg: '用户名或密码错误' }
    const valid = await bcrypt.compare(password, u.password_hash || '')
    if (!valid) return { ok: false, msg: '用户名或密码错误' }
    delete u.password_hash
    return { ok: true, user: u }
  }

  /** 修改管理员密码 */
  static async changePassword(oldPw, newPw) {
    const id = await Auth.ensureAdmin()
    const u = await db.row('SELECT password_hash FROM users WHERE id=?', [id])
    if (!u) return { ok: false, msg: '用户不存在' }
    if (oldPw && !(await bcrypt.compare(oldPw, u.password_hash || ''))) {
      return { ok: false, msg: '原密码错误' }
    }
    if (!newPw || newPw.length < 6) return { ok: false, msg: '新密码至少 6 位' }
    await db.exec('UPDATE users SET password_hash=? WHERE id=?', [await bcrypt.hash(newPw, 10), id])
    return { ok: true, msg: '密码已修改' }
  }

  /** 确保本地管理员存在;非 bcrypt 密码(占位/旧值)重置为默认 admin123 */
  static async ensureAdmin() {
    if (cachedAdminId) {
      const u = await db.row('SELECT id FROM users WHERE id=?', [cachedAdminId])
      if (u) return cachedAdminId
      cachedAdminId = null
    }
    let u = await db.row('SELECT id, password_hash FROM users WHERE is_admin=1 ORDER BY id LIMIT 1')
    if (!u) {
      const hash = await bcrypt.hash(DEFAULT_PW, 10)
      await db.exec(
        'INSERT INTO users (username,password_hash,email,email_verified,is_admin,user_code,created_at) VALUES (?,?,?,?,?,?,?)',
        [DEFAULT_ADMIN, hash, '', 0, 1, '000001', Math.floor(Date.now() / 1000)]
      )
      u = { id: await db.lastInsertId(), password_hash: hash }
      console.log('[auth] 已创建默认管理员 ' + DEFAULT_ADMIN + ' / ' + DEFAULT_PW)
    } else if (!/^\$2[aby]\$/.test(u.password_hash || '')) {
      // 非 bcrypt 哈希(占位密码或旧值)→ 重置为默认 admin123
      const hash = await bcrypt.hash(DEFAULT_PW, 10)
      await db.exec('UPDATE users SET password_hash=? WHERE id=?', [hash, u.id])
      console.log('[auth] 已将管理员密码重置为默认 ' + DEFAULT_PW)
    }
    cachedAdminId = u.id
    return cachedAdminId
  }
}

let cachedAdminId = null
module.exports = Auth