Files
playbull/server/auth.js
Mike 94b6cc3be9 Initial PlayBull release with Trilogy Hub integration.
Includes homelab deploy tooling, image position/zoom manifest persistence, and full trading/casino stack.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-02 08:31:36 +02:00

71 lines
2.2 KiB
JavaScript

import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { config } from './config.js';
import { Users } from './db.js';
const COOKIE = 'pb_token';
export function signToken(user) {
return jwt.sign({ id: user.id, username: user.username }, config.JWT_SECRET, { expiresIn: '30d' });
}
export function setAuthCookie(res, token) {
res.cookie(COOKIE, token, {
httpOnly: true,
sameSite: 'lax',
maxAge: 30 * 24 * 60 * 60 * 1000,
});
}
export function clearAuthCookie(res) {
res.clearCookie(COOKIE);
}
function readToken(req) {
const c = req.cookies?.[COOKIE];
if (c) return c;
const h = req.headers.authorization;
if (h && h.startsWith('Bearer ')) return h.slice(7);
return null;
}
// Haengt req.user an, wenn eingeloggt (sonst null). Blockiert nicht.
export function optionalAuth(req, _res, next) {
req.user = null;
const token = readToken(req);
if (token) {
try {
const decoded = jwt.verify(token, config.JWT_SECRET);
const u = Users.byId(decoded.id);
if (u) req.user = u;
} catch { /* ungueltig -> Gast */ }
}
next();
}
// Erzwingt Login (fuer Gamble & Trades).
export function requireAuth(req, res, next) {
if (!req.user) return res.status(401).json({ error: 'Login erforderlich' });
next();
}
export async function registerUser(username, password) {
username = String(username || '').trim();
if (username.length < 3 || username.length > 20) throw new Error('Username: 3-20 Zeichen');
if (!/^[a-zA-Z0-9_]+$/.test(username)) throw new Error('Nur Buchstaben, Zahlen, _');
if (String(password || '').length < 4) throw new Error('Passwort: min. 4 Zeichen');
if (Users.byName(username)) throw new Error('Username bereits vergeben');
const hash = await bcrypt.hash(password, 10);
return Users.create(username, hash, config.START_BALANCE);
}
export async function loginUser(username, password) {
const u = Users.byName(String(username || '').trim());
if (!u) throw new Error('Falscher Username oder Passwort');
const ok = await bcrypt.compare(String(password || ''), u.password_hash);
if (!ok) throw new Error('Falscher Username oder Passwort');
return u;
}
export { COOKIE };