api Controller & token

This commit is contained in:
Julian Krauser 2025-01-21 13:54:52 +01:00
parent 36ecccd0dc
commit 4568bef10e
8 changed files with 115 additions and 5 deletions

View file

@ -18,5 +18,5 @@ MAIL_HOST = mail_hoststring
MAIL_PORT = mail_portnumber
MAIL_SECURE (true|false) // true for port 465, fals for other ports
CLUB_NAME = clubname
CLUB_NAME = clubname #default FF Admin
CLUB_WEBSITE = https://my-club-website-url

View file

@ -40,7 +40,7 @@ services:
- MAIL_HOST=<url>
- MAIL_PORT=<port> # default ist auf 578 gesetzt
- MAIL_SECURE=<boolean> # default ist auf false gesetzt
- CLUB_NAME=<tobemodified>
- CLUB_NAME=<tobemodified> # default ist auf FF Admin gesetzt
- CLUB_WEBSITE=<tobemodified>
volumes:
- <volume|local path>:/app/files

View file

@ -7,6 +7,9 @@ import { CreateApiCommand, DeleteApiCommand, UpdateApiCommand } from "../../../c
import ApiCommandHandler from "../../../command/user/api/apiCommandHandler";
import { UpdateApiPermissionsCommand } from "../../../command/user/api/apiPermissionCommand";
import ApiPermissionCommandHandler from "../../../command/user/api/apiPermissionCommandHandler";
import { JWTHelper } from "../../../helpers/jwtHelper";
import { CLUB_NAME } from "../../../env.defaults";
import { StringHelper } from "../../../helpers/stringHelper";
/**
* @description get All apis
@ -69,10 +72,15 @@ export async function createApi(req: Request, res: Response): Promise<any> {
let title = req.body.title;
let expiry = req.body.expiry;
// TODO: create jwt as token to prevent random string tests
let token = await JWTHelper.create({
iss: CLUB_NAME,
sub: "api_token_retrieve",
iat: new Date().toISOString(),
aud: StringHelper.random(32),
});
let createApi: CreateApiCommand = {
token: "",
token: token,
title: title,
expiry: expiry,
};

View file

@ -0,0 +1,34 @@
import { Request, Response } from "express";
import { JWTHelper } from "../helpers/jwtHelper";
import { JWTToken } from "../type/jwtTypes";
import InternalException from "../exceptions/internalException";
import RefreshCommandHandler from "../command/refreshCommandHandler";
import { CreateRefreshCommand, DeleteRefreshCommand } from "../command/refreshCommand";
import UserService from "../service/user/userService";
import speakeasy from "speakeasy";
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
import RefreshService from "../service/refreshService";
import ApiService from "../service/user/apiService";
import ForbiddenRequestException from "../exceptions/forbiddenRequestException";
/**
* @description Check authentication status by token
* @param req {Request} Express req object
* @param res {Response} Express res object
* @returns {Promise<*>}
*/
export async function getAccess(req: Request, res: Response): Promise<any> {
const bearer = req.headers.authorization?.split(" ")?.[1] ?? undefined;
let { expiry } = await ApiService.getByToken(bearer);
if (new Date() > new Date(expiry)) {
throw new ForbiddenRequestException("api token expired");
}
let accessToken = await JWTHelper.buildApiToken(bearer);
res.json({
accessToken,
});
}

View file

@ -21,7 +21,7 @@ export const MAIL_HOST = process.env.MAIL_HOST ?? "";
export const MAIL_PORT = Number(process.env.MAIL_PORT ?? "587");
export const MAIL_SECURE = process.env.MAIL_SECURE ?? "false";
export const CLUB_NAME = process.env.CLUB_NAME ?? "";
export const CLUB_NAME = process.env.CLUB_NAME ?? "FF Admin";
export const CLUB_WEBSITE = process.env.CLUB_WEBSITE ?? "";
export function configCheck() {

View file

@ -6,6 +6,8 @@ import RolePermissionService from "../service/user/rolePermissionService";
import UserPermissionService from "../service/user/userPermissionService";
import UserService from "../service/user/userService";
import PermissionHelper from "./permissionHelper";
import ApiService from "../service/user/apiService";
import ApiPermissionService from "../service/user/apiPermissionService";
export abstract class JWTHelper {
static validate(token: string): Promise<string | jwt.JwtPayload> {
@ -72,4 +74,29 @@ export abstract class JWTHelper {
throw new InternalException("Failed accessToken creation", err);
});
}
static async buildApiToken(token: string): Promise<string> {
let { id, title } = await ApiService.getByToken(token);
let apiPermissions = await ApiPermissionService.getByApi(id);
let apiPermissionStrings = apiPermissions.map((e) => e.permission);
let permissionObject = PermissionHelper.convertToObject(apiPermissionStrings);
let jwtData: JWTToken = {
userId: id,
mail: "",
username: title,
firstname: "",
lastname: "",
isOwner: false,
permissions: permissionObject,
};
return await JWTHelper.create(jwtData)
.then((result) => {
return result;
})
.catch((err) => {
throw new InternalException("Failed accessToken creation", err);
});
}
}

View file

@ -29,6 +29,10 @@ export default async function authenticate(req: Request, res: Response, next: Fu
throw new InternalException("process failed");
}
if (decoded?.sub == "api_token_retrieve") {
throw new BadRequestException("This token is only authorized to get temporary access tokens via GET /api/webapi");
}
req.userId = decoded.userId;
req.username = decoded.username;
req.isOwner = decoded.isOwner;

View file

@ -0,0 +1,37 @@
import { Request, Response } from "express";
import jwt from "jsonwebtoken";
import BadRequestException from "../exceptions/badRequestException";
import UnauthorizedRequestException from "../exceptions/unauthorizedRequestException";
import InternalException from "../exceptions/internalException";
import { JWTHelper } from "../helpers/jwtHelper";
export default async function authenticateAPI(req: Request, res: Response, next: Function) {
const bearer = req.headers.authorization?.split(" ")?.[1] ?? undefined;
if (!bearer) {
throw new BadRequestException("Provide valid Authorization Header");
}
let decoded: string | jwt.JwtPayload;
await JWTHelper.validate(bearer)
.then((result) => {
decoded = result;
})
.catch((err) => {
if (err == "jwt expired") {
throw new UnauthorizedRequestException("Token expired", err);
} else {
throw new BadRequestException("Failed Authorization Header decoding", err);
}
});
if (typeof decoded == "string" || !decoded) {
throw new InternalException("process failed");
}
if (decoded?.sub != "api_token_retrieve") {
throw new BadRequestException("This route can only be accessed via a api token");
}
next();
}