import { aql, Database } from "arangojs"; import type { Document } from "arangojs/documents"; import { compare } from "bcrypt"; import type { IncomingMessage, ServerResponse } from "http"; import type { Session, User } from "../routes/api/_types"; import { checkPermissions } from "./permissions"; /** * Find a session in a database * @param db Arango database * @param token Session token * @returns The session data */ export async function findSession( db: Database, token: string ): Promise | null> { if (token) { const cursor = await db.query(aql` FOR session IN sessions RETURN session `); while (cursor.hasNext) { let doc = await cursor.next(); if (await compare(token, doc.token)) { return doc; } } } return null; } /** * Find authorizing user * @param db Arango database * @param token Session token * @returns The user data */ export async function findAuthorizer( db: Database, token?: string ): Promise<(Document & { _session?: Document }) | null> { const session = await findSession(db, token || ""); if (!session?.user) { const cursor = await db.query(aql` FOR user IN users FILTER user.username == "_guest" LIMIT 1 RETURN user `); if (cursor.hasNext) { return cursor.next(); } else { return null; } } else { const users = db.collection("users"); try { let user = await users.document(session?.user); user._session = session; return user; } catch (e) { throw new Error("Invalid user"); } } } type AuthorizationReturn = T extends true ? [null, T] : [Document & { _token?: string; _session?: Document }, T]; /** * Authorize a user * @param req Request * @param res Response * @param db Arango database * @param permissions The permissions to check against * @returns The user and whether to return */ export async function authorizeRequest( req: IncomingMessage, res: ServerResponse, db: Database, permissions: string[] ): Promise { const token = req.headers.authorization; let user: | (Document & { _token?: string; _session?: Document }) | null; try { user = await findAuthorizer(db, token); } catch (e) { res.writeHead(401); res.end( JSON.stringify({ message: "Invalid user" }) ); return [null, true]; } if (user === null) { res.writeHead(500); res.end( JSON.stringify({ message: "_guest user not found" }) ); return [null, true]; } if (!checkPermissions(permissions, user.permissions)) { res.writeHead(403); res.end( JSON.stringify({ message: "Missing permissions" }) ); return [null, true]; } user._token = token; return [user, false]; }