mirror of
https://gitlab.com/cyclane/sbdatatracker.git
synced 2025-04-19 12:25:05 +00:00
123 lines
2.7 KiB
TypeScript
123 lines
2.7 KiB
TypeScript
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<Document<Session> | 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<User> & { _session?: Document<Session> }) | 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 | false = boolean> = T extends true
|
|
? [null, T]
|
|
: [Document<User> & { _token?: string; _session?: Document<Session> }, 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<AuthorizationReturn> {
|
|
const token = req.headers.authorization;
|
|
let user:
|
|
| (Document<User> & { _token?: string; _session?: Document<Session> })
|
|
| 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];
|
|
}
|