import Prisma from "@prisma/client"; const prisma = new Prisma.PrismaClient(); import { log } from "../logs.js"; async function isLoggedIn(req) { // If AUTH_PASSWORD env variable is not present don't require any login if (!process.env.AUTH_PASSWORD) { return true; } // If no session cookie is set and no token query // parameter is provided the user can't be logged in const token = req.query.token || req.cookies.session; if (!token) { return false; } // If there is a session cookie check it const session = await prisma.session.findUnique({ where: { token, }, }); // If no session is found (the session probably // exired) the user is not logged in if (!session) { return false; } // If no checks failed the user is logged in return session; } async function renewSession(session) { // Don't try to renew sessions if auth is disabled if (session === true) return; await prisma.session.update({ where: { token: session.token, }, data: { // 14 Days from now on validUntil: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14), }, }); } async function login(req, res) { // Check if the user is already logged in let session = await isLoggedIn(req); if (session) { renewSession(session); res.redirect("/"); return; } // Check password if (!req.body.password || req.body.password != process.env.AUTH_PASSWORD) { res.redirect("/login"); return; } // Create a new auth session session = await prisma.session.create({ data: { // Expires after 14 days of inactivity validUntil: new Date(Date.now() + 1000 * 60 * 60 * 24 * 14), }, }); res.cookie("session", session.token, { httpOnly: true, // Expire "never" expires: new Date(253402300000000), }); log("API / Auth", `New session: ${session.token}`); res.redirect("/"); } async function logout(req, res) { const session = await isLoggedIn(req); if (!session) { res.sendStatus(401); return; } await prisma.session.deleteMany({ where: { token: session.token, }, }); log("API / Auth", `Removed session: ${session.token}`); res.redirect("/"); } async function checkLogin(req, res, next) { // Allow requests to `/api/token` if (req.path == "/token") { next(); return; } const session = await isLoggedIn(req); if (!session) { // send 401 Unauthorized so the // app redirects to the login page res.sendStatus(401); return; } req.locals = { session: session.token, }; renewSession(session); next(); } async function token(req, res) { if (!req.query.password || req.query.password != process.env.AUTH_PASSWORD) { res.status(401).send({ success: false, error: "wrong_auth", message: "Wrong password", }); return; } // Create a new auth session const session = await prisma.session.create({ data: { // API token expires after 1 hour validUntil: new Date(Date.now() + 1000 * 60 * 60), }, }); log("API / Auth", `New token: ${session.token}`); res.send({ success: true, token: session.token, }); } export default { login, logout, checkLogin, token, }; // Clean up expired sessions every hour setInterval( async () => { const sessions = await prisma.session.findMany(); for (const session of sessions) { if (session.validUntil < new Date()) { log("API / Auth", `Removed expired session: ${session.token}`); await prisma.session.delete({ where: { token: session.token, }, }); } } }, 1000 * 60 * 60, );