feature: Adds logging in support, and fixes permissions.
This commit is contained in:
parent
0c279b459f
commit
a7fd48d732
6 changed files with 136 additions and 14 deletions
18
routes/NextNet API/Log In User.bru
Normal file
18
routes/NextNet API/Log In User.bru
Normal file
|
@ -0,0 +1,18 @@
|
|||
meta {
|
||||
name: Create User
|
||||
type: http
|
||||
seq: 1
|
||||
}
|
||||
|
||||
post {
|
||||
url: http://127.0.0.1:3000/api/v1/users/login
|
||||
body: json
|
||||
auth: none
|
||||
}
|
||||
|
||||
body:json {
|
||||
{
|
||||
"email": "me@greysoh.dev",
|
||||
"password": "password"
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import Fastify from "fastify";
|
|||
|
||||
import { ServerOptions, SessionToken } from "./libs/types.js";
|
||||
import { route as create } from "./routes/user/create.js";
|
||||
import { route as login } from "./routes/user/login.js";
|
||||
|
||||
const prisma = new PrismaClient();
|
||||
|
||||
|
@ -31,6 +32,7 @@ const fastify = Fastify({
|
|||
});
|
||||
|
||||
create(fastify, prisma, sessionTokens, serverOptions);
|
||||
login(fastify, prisma, sessionTokens, serverOptions);
|
||||
|
||||
// Run the server!
|
||||
try {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { SessionToken } from "./types.js";
|
||||
|
||||
export const permissionListDisabled: Record<string, boolean> = {
|
||||
"routes.add": false,
|
||||
|
@ -29,14 +30,44 @@ 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
|
||||
}
|
||||
});
|
||||
export async function hasPermission(permissionList: string[], uid: number, prisma: PrismaClient): Promise<boolean> {
|
||||
for (const permission of permissionList) {
|
||||
const permissionNode = await prisma.permission.findFirst({
|
||||
where: {
|
||||
userID: uid,
|
||||
permission
|
||||
}
|
||||
});
|
||||
|
||||
if (!permissionNode) return false;
|
||||
return permissionNode.has;
|
||||
if (!permissionNode || !permissionNode.has) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
export async function hasPermissionByToken(permissionList: string[], token: string, tokens: Record<number, SessionToken[]>, prisma: PrismaClient): Promise<boolean> {
|
||||
let userID = -1;
|
||||
|
||||
for (const otherTokenKey of Object.keys(tokens)) {
|
||||
const otherTokenList = tokens[parseInt(otherTokenKey)];
|
||||
|
||||
for (const otherTokenIndex in otherTokenList) {
|
||||
const otherToken = otherTokenList[otherTokenIndex];
|
||||
|
||||
if (otherToken.token == token) {
|
||||
if (otherToken.expiresAt < otherToken.createdAt + (otherToken.createdAt - Date.now())) {
|
||||
otherTokenList.splice(parseInt(otherTokenIndex), 1);
|
||||
continue;
|
||||
} else {
|
||||
userID = parseInt(otherTokenKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fine, we'll look up for global tokens...
|
||||
|
||||
if (userID == -1) return false;
|
||||
|
||||
return true;
|
||||
}
|
12
src/routes/ROUTE_PLAN.md
Normal file
12
src/routes/ROUTE_PLAN.md
Normal file
|
@ -0,0 +1,12 @@
|
|||
# Route Plan
|
||||
- /api/v1/users/create
|
||||
- /api/v1/users/disable
|
||||
- /api/v1/users/remove
|
||||
- /api/v1/backends/create
|
||||
- /api/v1/backends/remove
|
||||
- /api/v1/backends/modify
|
||||
- /api/v1/backends/search
|
||||
- /api/v1/routes/create
|
||||
- /api/v1/routes/remove
|
||||
- /api/v1/routes/modify
|
||||
- /api/v1/routes/search
|
|
@ -7,8 +7,6 @@ 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.
|
||||
*/
|
||||
|
@ -63,9 +61,7 @@ export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Re
|
|||
permission: string,
|
||||
has: boolean
|
||||
}[]
|
||||
},
|
||||
|
||||
rootToken: null
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: There's probably a faster way to pull this off, but I'm lazy
|
||||
|
@ -79,6 +75,7 @@ export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Re
|
|||
};
|
||||
|
||||
if (options.allowUnsafeGlobalTokens) {
|
||||
// @ts-ignore
|
||||
userData.rootToken = generateToken() as unknown as null;
|
||||
}
|
||||
|
||||
|
|
62
src/routes/user/login.ts
Normal file
62
src/routes/user/login.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import type { PrismaClient } from "@prisma/client";
|
||||
import type { FastifyInstance } from "fastify";
|
||||
import { compare } from "bcrypt";
|
||||
|
||||
import { ServerOptions, SessionToken } from "../../libs/types.js";
|
||||
import { generateToken } from "../../libs/generateToken.js";
|
||||
|
||||
export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Record<number, SessionToken[]>, options: ServerOptions) {
|
||||
/**
|
||||
* Logs in to a user account.
|
||||
*/
|
||||
fastify.post("/api/v1/users/login", {
|
||||
schema: {
|
||||
body: {
|
||||
type: "object",
|
||||
required: ["email", "password"],
|
||||
|
||||
properties: {
|
||||
email: { type: "string" },
|
||||
password: { type: "string" }
|
||||
}
|
||||
}
|
||||
}
|
||||
}, async(req, res) => {
|
||||
// @ts-ignore
|
||||
const body: {
|
||||
email: string,
|
||||
password: string
|
||||
} = req.body;
|
||||
|
||||
const userSearch = await prisma.user.findFirst({
|
||||
where: {
|
||||
email: body.email
|
||||
}
|
||||
});
|
||||
|
||||
if (!userSearch) return res.status(403).send({
|
||||
error: "Email or password is incorrect"
|
||||
});
|
||||
|
||||
const passwordIsValid = compare(userSearch.password, body.password);
|
||||
|
||||
if (!passwordIsValid) return res.status(403).send({
|
||||
error: "Email or password is incorrect"
|
||||
});
|
||||
|
||||
const token = generateToken();
|
||||
if (!tokens[userSearch.id]) tokens[userSearch.id] = [];
|
||||
|
||||
tokens[userSearch.id].push({
|
||||
createdAt: Date.now(),
|
||||
expiresAt: Date.now() + (30 * 60_000),
|
||||
|
||||
token
|
||||
});
|
||||
|
||||
return {
|
||||
success: true,
|
||||
token
|
||||
}
|
||||
});
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue