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 { ServerOptions, SessionToken } from "./libs/types.js";
|
||||||
import { route as create } from "./routes/user/create.js";
|
import { route as create } from "./routes/user/create.js";
|
||||||
|
import { route as login } from "./routes/user/login.js";
|
||||||
|
|
||||||
const prisma = new PrismaClient();
|
const prisma = new PrismaClient();
|
||||||
|
|
||||||
|
@ -31,6 +32,7 @@ const fastify = Fastify({
|
||||||
});
|
});
|
||||||
|
|
||||||
create(fastify, prisma, sessionTokens, serverOptions);
|
create(fastify, prisma, sessionTokens, serverOptions);
|
||||||
|
login(fastify, prisma, sessionTokens, serverOptions);
|
||||||
|
|
||||||
// Run the server!
|
// Run the server!
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import type { PrismaClient } from "@prisma/client";
|
import type { PrismaClient } from "@prisma/client";
|
||||||
|
import type { SessionToken } from "./types.js";
|
||||||
|
|
||||||
export const permissionListDisabled: Record<string, boolean> = {
|
export const permissionListDisabled: Record<string, boolean> = {
|
||||||
"routes.add": false,
|
"routes.add": false,
|
||||||
|
@ -29,7 +30,8 @@ for (const index of Object.keys(permissionListEnabled)) {
|
||||||
permissionListEnabled[index] = true;
|
permissionListEnabled[index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function hasPermission(permission: string, uid: number, prisma: PrismaClient): Promise<boolean> {
|
export async function hasPermission(permissionList: string[], uid: number, prisma: PrismaClient): Promise<boolean> {
|
||||||
|
for (const permission of permissionList) {
|
||||||
const permissionNode = await prisma.permission.findFirst({
|
const permissionNode = await prisma.permission.findFirst({
|
||||||
where: {
|
where: {
|
||||||
userID: uid,
|
userID: uid,
|
||||||
|
@ -37,6 +39,35 @@ export async function hasPermission(permission: string, uid: number, prisma: Pri
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!permissionNode) return false;
|
if (!permissionNode || !permissionNode.has) return false;
|
||||||
return permissionNode.has;
|
}
|
||||||
|
|
||||||
|
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";
|
import { generateToken } from "../../libs/generateToken.js";
|
||||||
|
|
||||||
export function route(fastify: FastifyInstance, prisma: PrismaClient, tokens: Record<number, SessionToken[]>, options: ServerOptions) {
|
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.
|
* 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,
|
permission: string,
|
||||||
has: boolean
|
has: boolean
|
||||||
}[]
|
}[]
|
||||||
},
|
}
|
||||||
|
|
||||||
rootToken: null
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: There's probably a faster way to pull this off, but I'm lazy
|
// 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) {
|
if (options.allowUnsafeGlobalTokens) {
|
||||||
|
// @ts-ignore
|
||||||
userData.rootToken = generateToken() as unknown as null;
|
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