fix: recover when sessions table is missing
This commit is contained in:
parent
c3c0c33339
commit
c1259f0bf5
@ -2,27 +2,10 @@ const crypto = require("crypto");
|
||||
const pool = require("../db/pool");
|
||||
const { SESSION_TTL_DAYS } = require("../utils/session-cookie");
|
||||
|
||||
function generateSessionId() {
|
||||
if (typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID().replace(/-/g, "") + crypto.randomBytes(8).toString("hex");
|
||||
}
|
||||
return crypto.randomBytes(32).toString("hex");
|
||||
}
|
||||
|
||||
exports.createSession = async (userId, userAgent = null) => {
|
||||
const id = generateSessionId();
|
||||
const result = await pool.query(
|
||||
`INSERT INTO sessions (id, user_id, expires_at, user_agent)
|
||||
const INSERT_SESSION_SQL = `INSERT INTO sessions (id, user_id, expires_at, user_agent)
|
||||
VALUES ($1, $2, NOW() + ($3 || ' days')::interval, $4)
|
||||
RETURNING id, user_id, created_at, expires_at`,
|
||||
[id, userId, String(SESSION_TTL_DAYS), userAgent]
|
||||
);
|
||||
return result.rows[0];
|
||||
};
|
||||
|
||||
exports.getActiveSessionWithUser = async (sessionId) => {
|
||||
const result = await pool.query(
|
||||
`SELECT
|
||||
RETURNING id, user_id, created_at, expires_at`;
|
||||
const SELECT_ACTIVE_SESSION_SQL = `SELECT
|
||||
s.id,
|
||||
s.user_id,
|
||||
s.expires_at,
|
||||
@ -31,26 +14,110 @@ exports.getActiveSessionWithUser = async (sessionId) => {
|
||||
FROM sessions s
|
||||
JOIN users u ON u.id = s.user_id
|
||||
WHERE s.id = $1
|
||||
AND s.expires_at > NOW()`,
|
||||
[sessionId]
|
||||
);
|
||||
AND s.expires_at > NOW()`;
|
||||
|
||||
let ensureSessionsTablePromise = null;
|
||||
|
||||
function generateSessionId() {
|
||||
if (typeof crypto.randomUUID === "function") {
|
||||
return crypto.randomUUID().replace(/-/g, "") + crypto.randomBytes(8).toString("hex");
|
||||
}
|
||||
return crypto.randomBytes(32).toString("hex");
|
||||
}
|
||||
|
||||
function isUndefinedTableError(error) {
|
||||
return error && error.code === "42P01";
|
||||
}
|
||||
|
||||
async function ensureSessionsTable() {
|
||||
if (!ensureSessionsTablePromise) {
|
||||
ensureSessionsTablePromise = (async () => {
|
||||
await pool.query(`CREATE TABLE IF NOT EXISTS sessions (
|
||||
id VARCHAR(128) PRIMARY KEY,
|
||||
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
expires_at TIMESTAMPTZ NOT NULL,
|
||||
last_seen_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
user_agent TEXT
|
||||
);`);
|
||||
await pool.query(
|
||||
"CREATE INDEX IF NOT EXISTS idx_sessions_user_id ON sessions(user_id);"
|
||||
);
|
||||
await pool.query(
|
||||
"CREATE INDEX IF NOT EXISTS idx_sessions_expires_at ON sessions(expires_at);"
|
||||
);
|
||||
})().catch((error) => {
|
||||
ensureSessionsTablePromise = null;
|
||||
throw error;
|
||||
});
|
||||
}
|
||||
|
||||
await ensureSessionsTablePromise;
|
||||
}
|
||||
|
||||
async function insertSession(id, userId, userAgent) {
|
||||
const result = await pool.query(INSERT_SESSION_SQL, [
|
||||
id,
|
||||
userId,
|
||||
String(SESSION_TTL_DAYS),
|
||||
userAgent,
|
||||
]);
|
||||
return result.rows[0];
|
||||
}
|
||||
|
||||
exports.createSession = async (userId, userAgent = null) => {
|
||||
const id = generateSessionId();
|
||||
try {
|
||||
return await insertSession(id, userId, userAgent);
|
||||
} catch (error) {
|
||||
if (!isUndefinedTableError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
await ensureSessionsTable();
|
||||
return insertSession(id, userId, userAgent);
|
||||
}
|
||||
};
|
||||
|
||||
exports.getActiveSessionWithUser = async (sessionId) => {
|
||||
let result;
|
||||
try {
|
||||
result = await pool.query(SELECT_ACTIVE_SESSION_SQL, [sessionId]);
|
||||
} catch (error) {
|
||||
if (isUndefinedTableError(error)) {
|
||||
return null;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
|
||||
const session = result.rows[0] || null;
|
||||
if (!session) return null;
|
||||
|
||||
await pool.query(
|
||||
`UPDATE sessions
|
||||
try {
|
||||
await pool.query(
|
||||
`UPDATE sessions
|
||||
SET last_seen_at = NOW()
|
||||
WHERE id = $1`,
|
||||
[sessionId]
|
||||
);
|
||||
[sessionId]
|
||||
);
|
||||
} catch (error) {
|
||||
if (!isUndefinedTableError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return session;
|
||||
};
|
||||
|
||||
exports.deleteSession = async (sessionId) => {
|
||||
await pool.query(
|
||||
`DELETE FROM sessions WHERE id = $1`,
|
||||
[sessionId]
|
||||
);
|
||||
try {
|
||||
await pool.query(
|
||||
`DELETE FROM sessions WHERE id = $1`,
|
||||
[sessionId]
|
||||
);
|
||||
} catch (error) {
|
||||
if (!isUndefinedTableError(error)) {
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
Reference in New Issue
Block a user