Datenbank bereinigt / Gitea-Integration gefixt

Dieser Commit ist enthalten in:
hendrik_gebhardt@gmx.de
2026-01-04 00:24:11 +00:00
committet von Server Deploy
Ursprung 395598c2b0
Commit c21be47428
37 geänderte Dateien mit 30993 neuen und 809 gelöschten Zeilen

Datei anzeigen

@ -5,15 +5,22 @@
*/
const jwt = require('jsonwebtoken');
const crypto = require('crypto');
const logger = require('../utils/logger');
const { getDb } = require('../database');
const JWT_SECRET = process.env.JWT_SECRET || 'UNSICHER_BITTE_AENDERN';
const JWT_SECRET = process.env.JWT_SECRET;
if (!JWT_SECRET || JWT_SECRET.length < 32) {
throw new Error('JWT_SECRET muss in .env gesetzt und mindestens 32 Zeichen lang sein!');
}
const ACCESS_TOKEN_EXPIRY = 15; // Minuten (kürzer für mehr Sicherheit)
const REFRESH_TOKEN_EXPIRY = 7 * 24 * 60; // 7 Tage in Minuten
const SESSION_TIMEOUT = parseInt(process.env.SESSION_TIMEOUT) || 30; // Minuten
/**
* JWT-Token generieren
* JWT Access-Token generieren (kurze Lebensdauer)
*/
function generateToken(user) {
function generateAccessToken(user) {
// Permissions parsen falls als String gespeichert
let permissions = user.permissions || [];
if (typeof permissions === 'string') {
@ -31,13 +38,38 @@ function generateToken(user) {
displayName: user.display_name,
color: user.color,
role: user.role || 'user',
permissions: permissions
permissions: permissions,
type: 'access'
},
JWT_SECRET,
{ expiresIn: `${SESSION_TIMEOUT}m` }
{ expiresIn: `${ACCESS_TOKEN_EXPIRY}m` }
);
}
/**
* Refresh-Token generieren (lange Lebensdauer)
*/
function generateRefreshToken(userId, ipAddress, userAgent) {
const db = getDb();
const token = crypto.randomBytes(32).toString('hex');
const expiresAt = new Date(Date.now() + REFRESH_TOKEN_EXPIRY * 60 * 1000);
// Token in Datenbank speichern
db.prepare(`
INSERT INTO refresh_tokens (user_id, token, expires_at, ip_address, user_agent)
VALUES (?, ?, ?, ?, ?)
`).run(userId, token, expiresAt.toISOString(), ipAddress, userAgent);
return token;
}
/**
* Legacy generateToken für Rückwärtskompatibilität
*/
function generateToken(user) {
return generateAccessToken(user);
}
/**
* JWT-Token verifizieren
*/
@ -179,8 +211,72 @@ function generateCsrfToken() {
return randomBytes(32).toString('hex');
}
/**
* Refresh-Token validieren und neuen Access-Token generieren
*/
async function refreshAccessToken(refreshToken, ipAddress, userAgent) {
const db = getDb();
// Token in Datenbank suchen
const tokenRecord = db.prepare(`
SELECT rt.*, u.* FROM refresh_tokens rt
JOIN users u ON rt.user_id = u.id
WHERE rt.token = ? AND rt.expires_at > datetime('now')
`).get(refreshToken);
if (!tokenRecord) {
throw new Error('Ungültiger oder abgelaufener Refresh-Token');
}
// Token als benutzt markieren
db.prepare(`
UPDATE refresh_tokens SET last_used = CURRENT_TIMESTAMP WHERE id = ?
`).run(tokenRecord.id);
// Neuen Access-Token generieren
const user = {
id: tokenRecord.user_id,
username: tokenRecord.username,
display_name: tokenRecord.display_name,
color: tokenRecord.color,
role: tokenRecord.role,
permissions: tokenRecord.permissions
};
return generateAccessToken(user);
}
/**
* Alle Refresh-Tokens eines Benutzers löschen (Logout auf allen Geräten)
*/
function revokeAllRefreshTokens(userId) {
const db = getDb();
db.prepare('DELETE FROM refresh_tokens WHERE user_id = ?').run(userId);
}
/**
* Abgelaufene Refresh-Tokens aufräumen
*/
function cleanupExpiredTokens() {
const db = getDb();
const result = db.prepare(`
DELETE FROM refresh_tokens WHERE expires_at < datetime('now')
`).run();
if (result.changes > 0) {
logger.info(`Bereinigt: ${result.changes} abgelaufene Refresh-Tokens`);
}
}
// Cleanup alle 6 Stunden
setInterval(cleanupExpiredTokens, 6 * 60 * 60 * 1000);
module.exports = {
generateToken,
generateAccessToken,
generateRefreshToken,
refreshAccessToken,
revokeAllRefreshTokens,
verifyToken,
authenticateToken,
authenticateSocket,