sbdatatracker/src/lib/butil.ts
2021-07-07 19:47:00 +01:00

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];
}