🛂 Add key-based permission system
This commit is contained in:
@ -101,6 +101,9 @@ async function checkLogin(req, res, next) {
|
||||
res.sendStatus(401);
|
||||
return;
|
||||
}
|
||||
req.locals = {
|
||||
session: session.token,
|
||||
};
|
||||
renewSession(session);
|
||||
next();
|
||||
}
|
||||
|
@ -1,6 +1,60 @@
|
||||
import Prisma from "@prisma/client";
|
||||
const prisma = new Prisma.PrismaClient();
|
||||
|
||||
import {
|
||||
applyKey,
|
||||
hasPermission,
|
||||
listPermissions,
|
||||
revokeKey,
|
||||
} from "./permission.js";
|
||||
|
||||
// Get info API endpoint (/api/info)
|
||||
// Returns information about the requesting session
|
||||
export async function getInfo(req, res) {
|
||||
const session = await prisma.session.findUnique({
|
||||
where: {
|
||||
token: req.locals.session,
|
||||
},
|
||||
include: {
|
||||
appliedKeys: {
|
||||
select: {
|
||||
key: true,
|
||||
permissions: true,
|
||||
validUntil: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
res.send({
|
||||
authenticated: true,
|
||||
appliedKeys: session.appliedKeys,
|
||||
permissions: await listPermissions(session.token),
|
||||
});
|
||||
}
|
||||
|
||||
// Put and Delete key API endpoints (/api/key)
|
||||
// Applies or revokes a key from the requesting user's session
|
||||
export async function putKey(req, res) {
|
||||
if (await applyKey(req.locals.session, req.query.key)) {
|
||||
res.status(200).send();
|
||||
} else {
|
||||
res.status(400).send({
|
||||
success: false,
|
||||
error: "invalid_key",
|
||||
message: "This key does not exist",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function deleteKey(req, res) {
|
||||
if (await revokeKey(req.locals.session, req.query.key)) {
|
||||
res.status(200).send();
|
||||
} else {
|
||||
res.status(400).send();
|
||||
}
|
||||
}
|
||||
|
||||
// Get timetable API endpoint (/api/timetable)
|
||||
// Returns timetable data for requested class if available
|
||||
export async function getTimetable(req, res) {
|
||||
|
95
server/api/permission.js
Normal file
95
server/api/permission.js
Normal file
@ -0,0 +1,95 @@
|
||||
import Prisma from "@prisma/client";
|
||||
import { log } from "../logs.js";
|
||||
const prisma = new Prisma.PrismaClient();
|
||||
|
||||
export async function listPermissions(sessionToken) {
|
||||
const session = await prisma.session.findUnique({
|
||||
where: {
|
||||
token: sessionToken,
|
||||
},
|
||||
include: {
|
||||
appliedKeys: "true",
|
||||
},
|
||||
});
|
||||
if (!session) return [];
|
||||
|
||||
const perms = [];
|
||||
for (const key of session.appliedKeys) {
|
||||
if (key.validUntil && new Date() > key.validUntil) continue;
|
||||
for (const perm of key.permissions) {
|
||||
perms.push(perm);
|
||||
}
|
||||
}
|
||||
return perms;
|
||||
}
|
||||
|
||||
export async function hasPermission(sessionToken, permission, forValue) {
|
||||
let hasPermission = false;
|
||||
for (const perm of await listPermissions(sessionToken)) {
|
||||
if (perm == permission) hasPermission = true;
|
||||
else if (perm == permission + ":" + forValue) hasPermission = true;
|
||||
}
|
||||
return hasPermission;
|
||||
}
|
||||
|
||||
export async function applyKey(sessionToken, key) {
|
||||
if (!key) return false;
|
||||
const foundKey = await prisma.key.findUnique({
|
||||
where: {
|
||||
key,
|
||||
},
|
||||
});
|
||||
if (!foundKey) return false;
|
||||
|
||||
await prisma.session.update({
|
||||
where: {
|
||||
token: sessionToken,
|
||||
},
|
||||
data: {
|
||||
appliedKeys: {
|
||||
connect: {
|
||||
key: foundKey.key,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function revokeKey(sessionToken, key) {
|
||||
if (!key) return false;
|
||||
|
||||
await prisma.session.update({
|
||||
where: {
|
||||
token: sessionToken,
|
||||
},
|
||||
data: {
|
||||
appliedKeys: {
|
||||
disconnect: {
|
||||
key: key,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clean up expired keys every hour
|
||||
setInterval(async () => {
|
||||
const keys = await prisma.key.findMany();
|
||||
for (const key of keys) {
|
||||
if (key.validUntil && key.validUntil < new Date()) {
|
||||
log(
|
||||
"API / Permissions",
|
||||
`Removed expired key: ${key.key}; Permissions: ${key.permissions.join(
|
||||
", "
|
||||
)}`
|
||||
);
|
||||
await prisma.key.delete({
|
||||
where: {
|
||||
key: key.key,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
}, 1000 * 60 * 60);
|
Reference in New Issue
Block a user