64 lines
2.6 KiB
JavaScript
64 lines
2.6 KiB
JavaScript
'use strict'
|
|
const jwt = require('jsonwebtoken')
|
|
const bcrypt = require('bcryptjs')
|
|
const { loadUsers, saveUsers } = require('./config')
|
|
|
|
const SECRET = process.env.JWT_SECRET || 'dev-secret-change-in-prod'
|
|
|
|
// ─── Ensure default admin exists on first run ─────────────────────────────────
|
|
function ensureDefaultAdmin() {
|
|
const users = loadUsers()
|
|
if (Object.keys(users).length === 0) {
|
|
const adminUser = process.env.ADMIN_USER || 'admin'
|
|
const adminPass = process.env.ADMIN_PASS || 'changeme'
|
|
users[adminUser] = {
|
|
passwordHash: bcrypt.hashSync(adminPass, 10),
|
|
role: 'admin',
|
|
createdAt: new Date().toISOString()
|
|
}
|
|
saveUsers(users)
|
|
console.log(`[Auth] Created default admin: ${adminUser} / ${adminPass}`)
|
|
console.log('[Auth] ⚠️ Change the password after first login!')
|
|
}
|
|
}
|
|
|
|
// ─── Verify login ─────────────────────────────────────────────────────────────
|
|
function login(username, password) {
|
|
const users = loadUsers()
|
|
const user = users[username]
|
|
if (!user) return null
|
|
if (!bcrypt.compareSync(password, user.passwordHash)) return null
|
|
const token = jwt.sign({ username, role: user.role }, SECRET, { expiresIn: '7d' })
|
|
return token
|
|
}
|
|
|
|
// ─── Change password ──────────────────────────────────────────────────────────
|
|
function changePassword(username, newPassword) {
|
|
const users = loadUsers()
|
|
if (!users[username]) return false
|
|
users[username].passwordHash = bcrypt.hashSync(newPassword, 10)
|
|
saveUsers(users)
|
|
return true
|
|
}
|
|
|
|
// ─── Middleware: verify JWT from Authorization header ─────────────────────────
|
|
function requireAuth(req, res, next) {
|
|
const header = req.headers.authorization || ''
|
|
const token = header.startsWith('Bearer ') ? header.slice(7) : null
|
|
if (!token) return res.status(401).json({ error: 'Unauthorized' })
|
|
try {
|
|
req.user = jwt.verify(token, SECRET)
|
|
next()
|
|
} catch {
|
|
res.status(401).json({ error: 'Invalid token' })
|
|
}
|
|
}
|
|
|
|
// ─── Verify JWT for WebSocket connections ────────────────────────────────────
|
|
function verifyJwt(token) {
|
|
try { return jwt.verify(token, SECRET) }
|
|
catch { return null }
|
|
}
|
|
|
|
module.exports = { ensureDefaultAdmin, login, changePassword, requireAuth, verifyJwt }
|