asset_browser/auth/sessionStore.js
setonc a558804026 Initial commit — asset browser web app
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-27 09:06:25 -04:00

65 lines
2 KiB
JavaScript
Executable file

'use strict';
// Custom session store backed by the same better-sqlite3 instance.
// Avoids pulling in a second SQLite driver (connect-sqlite3 / sqlite3).
const session = require('express-session');
const TTL_SECONDS = 8 * 60 * 60; // 8 hours — matches cookie maxAge
function createSessionStore(db) {
class SQLiteStore extends session.Store {
constructor() {
super();
// Purge expired sessions every 15 minutes
setInterval(() => {
db.prepare('DELETE FROM sessions WHERE expired < ?').run(Math.floor(Date.now() / 1000));
}, 15 * 60 * 1000).unref();
}
get(sid, cb) {
try {
const row = db.prepare('SELECT sess, expired FROM sessions WHERE sid = ?').get(sid);
if (!row) return cb(null, null);
if (row.expired < Math.floor(Date.now() / 1000)) {
db.prepare('DELETE FROM sessions WHERE sid = ?').run(sid);
return cb(null, null);
}
cb(null, JSON.parse(row.sess));
} catch (e) { cb(e); }
}
set(sid, sessionData, cb) {
try {
const ttl = sessionData.cookie?.maxAge
? Math.floor(sessionData.cookie.maxAge / 1000)
: TTL_SECONDS;
const expired = Math.floor(Date.now() / 1000) + ttl;
db.prepare('INSERT OR REPLACE INTO sessions (sid, sess, expired) VALUES (?, ?, ?)')
.run(sid, JSON.stringify(sessionData), expired);
cb(null);
} catch (e) { cb(e); }
}
destroy(sid, cb) {
try {
db.prepare('DELETE FROM sessions WHERE sid = ?').run(sid);
cb(null);
} catch (e) { cb(e); }
}
touch(sid, sessionData, cb) {
try {
const ttl = sessionData.cookie?.maxAge
? Math.floor(sessionData.cookie.maxAge / 1000)
: TTL_SECONDS;
const expired = Math.floor(Date.now() / 1000) + ttl;
db.prepare('UPDATE sessions SET expired = ? WHERE sid = ?').run(expired, sid);
cb(null);
} catch (e) { cb(e); }
}
}
return new SQLiteStore();
}
module.exports = { createSessionStore };