feature: Adds permission system.

This commit is contained in:
Tera << 8 2024-04-19 12:48:40 +00:00
parent be91aafb58
commit 0c279b459f
6 changed files with 122 additions and 8 deletions

View file

@ -0,0 +1,20 @@
/*
Warnings:
- You are about to drop the column `permissionID` on the `Permission` table. All the data in the column will be lost.
- Added the required column `permission` to the `Permission` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Permission" (
"permission" TEXT NOT NULL,
"has" BOOLEAN NOT NULL,
"userID" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
CONSTRAINT "Permission_userID_fkey" FOREIGN KEY ("userID") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Permission" ("has", "userID") SELECT "has", "userID" FROM "Permission";
DROP TABLE "Permission";
ALTER TABLE "new_Permission" RENAME TO "Permission";
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

View file

@ -0,0 +1,21 @@
/*
Warnings:
- The primary key for the `Permission` table will be changed. If it partially fails, the table could be left without primary key constraint.
- Added the required column `id` to the `Permission` table without a default value. This is not possible if the table is not empty.
*/
-- RedefineTables
PRAGMA foreign_keys=OFF;
CREATE TABLE "new_Permission" (
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
"permission" TEXT NOT NULL,
"has" BOOLEAN NOT NULL,
"userID" INTEGER NOT NULL,
CONSTRAINT "Permission_userID_fkey" FOREIGN KEY ("userID") REFERENCES "User" ("id") ON DELETE RESTRICT ON UPDATE CASCADE
);
INSERT INTO "new_Permission" ("has", "permission", "userID") SELECT "has", "permission", "userID" FROM "Permission";
DROP TABLE "Permission";
ALTER TABLE "new_Permission" RENAME TO "Permission";
PRAGMA foreign_key_check;
PRAGMA foreign_keys=ON;

View file

@ -37,11 +37,13 @@ model ForwardRule {
}
model Permission {
permissionID String @unique
id Int @id @default(autoincrement())
permission String
has Boolean
user User @relation(fields: [userID], references: [id])
userID Int @id @default(autoincrement())
userID Int
}
model User {

View file

@ -6,6 +6,14 @@ meta {
post {
url: http://127.0.0.1:3000/api/v1/users/create
body: none
body: json
auth: none
}
body:json {
{
"name": "Greyson Hofer",
"email": "me@greysoh.dev",
"password": "password"
}
}

42
src/libs/permissions.ts Normal file
View file

@ -0,0 +1,42 @@
import type { PrismaClient } from "@prisma/client";
export const permissionListDisabled: Record<string, boolean> = {
"routes.add": false,
"routes.remove": false,
"routes.start": false,
"routes.stop": false,
"routes.edit": false,
"routes.visible": false,
"backends.add": false,
"backends.remove": false,
"backends.start": false,
"backends.stop": false,
"backends.edit": false,
"backends.visible": false,
"backends.secretVis": false,
"permissions.see": false,
"users.add": false,
"users.remove": false
};
// FIXME: This solution fucking sucks.
export let permissionListEnabled: Record<string, boolean> = JSON.parse(JSON.stringify(permissionListDisabled));
for (const index of Object.keys(permissionListEnabled)) {
permissionListEnabled[index] = true;
}
export async function hasPermission(permission: string, uid: number, prisma: PrismaClient): Promise<boolean> {
const permissionNode = await prisma.permission.findFirst({
where: {
userID: uid,
permission
}
});
if (!permissionNode) return false;
return permissionNode.has;
}

View file

@ -1,14 +1,17 @@
import type { PrismaClient } from "@prisma/client";
import type { FastifyInstance } from "fastify";
import { hash } from "bcrypt";
import { ServerOptions, SessionToken } from "../../libs/types.js";
import { permissionListEnabled } from "../../libs/permissions.js";
import { generateToken } from "../../libs/generateToken.js";
export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Record<number, SessionToken[]>, options: ServerOptions) {
// TODO: Permissions
/**
* Creates a new user account to use, only if it is enabled.
*/
fastify.post("/api/v1/users/create", {
schema: {
body: {
@ -16,8 +19,8 @@ export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Re
required: ["name", "email", "password"],
properties: {
name: { type: "string" },
email: { type: "string" },
name: { type: "string" },
email: { type: "string" },
password: { type: "string" }
}
}
@ -31,7 +34,7 @@ export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Re
} = req.body;
if (!options.isSignupEnabled) {
return res.status(400).send({
return res.status(403).send({
error: "Signing up is not enabled at this time."
});
};
@ -50,13 +53,31 @@ export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Re
const saltedPassword: string = await hash(body.password, 15);
let userData = {
const userData = {
name: body.name,
email: body.email,
password: saltedPassword,
permissions: {
create: [] as {
permission: string,
has: boolean
}[]
},
rootToken: null
};
// TODO: There's probably a faster way to pull this off, but I'm lazy
for (const permissionKey of Object.keys(permissionListEnabled)) {
if (options.isSignupAsAdminEnabled || (permissionKey.startsWith("routes") || permissionKey == "permissions.see")) {
userData.permissions.create.push({
permission: permissionKey,
has: permissionListEnabled[permissionKey]
});
}
};
if (options.allowUnsafeGlobalTokens) {
userData.rootToken = generateToken() as unknown as null;
}