aktueller stand

This commit is contained in:
2026-01-07 22:50:35 +01:00
parent b81c2042e9
commit 9675e73406
6 changed files with 146 additions and 14 deletions

View File

@@ -376,6 +376,47 @@ function isSecureRequest(req) {
}
const authSessions = new Map();
const AUTH_SESSION_TABLE = 'auth_sessions';
function persistAuthSession(token, username, expiresAt) {
if (!AUTH_ENABLED) {
return;
}
db.prepare(`
INSERT INTO ${AUTH_SESSION_TABLE} (token, username, expires_at)
VALUES (?, ?, ?)
ON CONFLICT(token) DO UPDATE SET
username = excluded.username,
expires_at = excluded.expires_at
`).run(token, username, expiresAt);
}
function deletePersistedAuthSession(token) {
if (!AUTH_ENABLED) {
return;
}
db.prepare(`DELETE FROM ${AUTH_SESSION_TABLE} WHERE token = ?`).run(token);
}
function hydrateAuthSessions() {
if (!AUTH_ENABLED) {
return;
}
const now = Date.now();
db.prepare(`DELETE FROM ${AUTH_SESSION_TABLE} WHERE expires_at <= ?`).run(now);
const rows = db.prepare(`
SELECT token, username, expires_at
FROM ${AUTH_SESSION_TABLE}
WHERE expires_at > ?
`).all(now);
rows.forEach(row => {
authSessions.set(row.token, {
username: row.username,
expiresAt: row.expires_at
});
});
}
function buildAuthCookieValue(token, req) {
const secure = isSecureRequest(req);
@@ -425,6 +466,7 @@ function createSession(username) {
const token = crypto.randomBytes(32).toString('hex');
const expiresAt = Date.now() + AUTH_SESSION_MAX_AGE * 1000;
authSessions.set(token, { username, expiresAt });
persistAuthSession(token, username, expiresAt);
return { token, expiresAt };
}
@@ -437,17 +479,39 @@ function getSessionFromRequest(req) {
const session = authSessions.get(token);
if (!session) {
if (AUTH_ENABLED) {
const row = db.prepare(`
SELECT username, expires_at
FROM ${AUTH_SESSION_TABLE}
WHERE token = ?
`).get(token);
if (!row) {
return null;
}
if (row.expires_at <= Date.now()) {
deletePersistedAuthSession(token);
return null;
}
const hydrated = { username: row.username, expiresAt: row.expires_at };
authSessions.set(token, hydrated);
return { token, ...hydrated };
}
return null;
}
if (session.expiresAt <= Date.now()) {
authSessions.delete(token);
deletePersistedAuthSession(token);
return null;
}
// Sliding expiration
session.expiresAt = Date.now() + AUTH_SESSION_MAX_AGE * 1000;
authSessions.set(token, session);
persistAuthSession(token, session.username, session.expiresAt);
return { token, ...session };
}
@@ -552,6 +616,7 @@ app.post('/api/logout', (req, res) => {
const session = getSessionFromRequest(req);
if (session) {
authSessions.delete(session.token);
deletePersistedAuthSession(session.token);
}
clearAuthCookie(res, req);
res.json({ success: true });
@@ -1384,6 +1449,15 @@ db.exec(`
);
`);
db.exec(`
CREATE TABLE IF NOT EXISTS auth_sessions (
token TEXT PRIMARY KEY,
username TEXT NOT NULL,
expires_at INTEGER NOT NULL
);
`);
hydrateAuthSessions();
db.exec(`
CREATE TABLE IF NOT EXISTS ai_settings (
id INTEGER PRIMARY KEY CHECK (id = 1),