V0.1
This commit is contained in:
92
server/routes/auth.js
Normal file
92
server/routes/auth.js
Normal file
@@ -0,0 +1,92 @@
|
||||
import { randomUUID } from 'crypto';
|
||||
import { Router } from 'express';
|
||||
import db from '../db.js';
|
||||
import { badRequest } from '../lib/http.js';
|
||||
import { hashPassword, verifyPassword } from '../password.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get('/status', (req, res) => {
|
||||
const count = db.prepare('SELECT COUNT(*) AS c FROM users').get().c;
|
||||
const needsBootstrap = count === 0;
|
||||
if (needsBootstrap) {
|
||||
return res.json({ needsBootstrap: true, loggedIn: false, user: null });
|
||||
}
|
||||
if (!req.session?.userId) {
|
||||
return res.json({ needsBootstrap: false, loggedIn: false, user: null });
|
||||
}
|
||||
const u = db
|
||||
.prepare('SELECT id, username, role, active FROM users WHERE id = ?')
|
||||
.get(req.session.userId);
|
||||
if (!u || !u.active) {
|
||||
req.session.destroy(() => {});
|
||||
return res.json({ needsBootstrap: false, loggedIn: false, user: null });
|
||||
}
|
||||
res.json({
|
||||
needsBootstrap: false,
|
||||
loggedIn: true,
|
||||
user: { id: u.id, username: u.username, role: u.role },
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/bootstrap', async (req, res) => {
|
||||
const count = db.prepare('SELECT COUNT(*) AS c FROM users').get().c;
|
||||
if (count > 0) {
|
||||
return res.status(403).json({ message: 'Initialisierung nicht mehr möglich.' });
|
||||
}
|
||||
const { username, password } = req.body || {};
|
||||
const un = String(username || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!un || !password || password.length < 8) {
|
||||
return badRequest(res, 'Benutzername und Passwort (min. 8 Zeichen) erforderlich.');
|
||||
}
|
||||
const id = randomUUID();
|
||||
const ph = await hashPassword(password);
|
||||
db.prepare(
|
||||
`INSERT INTO users (id, username, password_hash, role, source, active, updated_at)
|
||||
VALUES (?, ?, ?, 'admin', 'local', 1, datetime('now'))`,
|
||||
).run(id, un, ph);
|
||||
req.session.userId = id;
|
||||
req.session.role = 'admin';
|
||||
req.session.username = un;
|
||||
res.status(201).json({
|
||||
user: { id, username: un, role: 'admin' },
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/login', async (req, res) => {
|
||||
const { username, password } = req.body || {};
|
||||
const un = String(username || '')
|
||||
.trim()
|
||||
.toLowerCase();
|
||||
if (!un || !password) {
|
||||
return badRequest(res, 'Benutzername und Passwort erforderlich.');
|
||||
}
|
||||
const u = db.prepare('SELECT * FROM users WHERE username = ?').get(un);
|
||||
if (!u || !u.active) {
|
||||
return res.status(401).json({ message: 'Ungültige Zugangsdaten.' });
|
||||
}
|
||||
if (!u.password_hash) {
|
||||
return res.status(401).json({
|
||||
message: 'Kein lokales Passwort (LDAP). Anmeldung folgt mit Verzeichnis-Sync.',
|
||||
});
|
||||
}
|
||||
const ok = await verifyPassword(password, u.password_hash);
|
||||
if (!ok) return res.status(401).json({ message: 'Ungültige Zugangsdaten.' });
|
||||
req.session.userId = u.id;
|
||||
req.session.role = u.role;
|
||||
req.session.username = u.username;
|
||||
res.json({
|
||||
user: { id: u.id, username: u.username, role: u.role },
|
||||
});
|
||||
});
|
||||
|
||||
router.post('/logout', (req, res) => {
|
||||
req.session.destroy((err) => {
|
||||
if (err) return res.status(500).json({ message: 'Abmelden fehlgeschlagen.' });
|
||||
res.json({ ok: true });
|
||||
});
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user