diff --git a/api/package.json b/api/package.json index fcfc1d4..3042fd7 100644 --- a/api/package.json +++ b/api/package.json @@ -21,6 +21,7 @@ "dependencies": { "bcrypt": "^5.1.1", "colors": "1.4.0", + "cookie-parser": "^1.4.6", "dotenv": "^16.4.5", "express": "^4.19.2", "fs-extra": "^10.0.0", @@ -37,6 +38,7 @@ "@biomejs/biome": "1.7.1", "@types/bcrypt": "^5.0.2", "@types/chai": "^4.2.22", + "@types/cookie-parser": "^1.4.7", "@types/express": "^4.17.21", "@types/fs-extra": "^9.0.13", "@types/inquirer": "^8.1.3", diff --git a/api/src/app.ts b/api/src/app.ts index f14a697..be72f3f 100644 --- a/api/src/app.ts +++ b/api/src/app.ts @@ -1,8 +1,8 @@ import express from "express"; import morgan from "morgan"; -//import path from 'path' +import path from 'path' //import cors from 'cors' -//import cookieParser from 'cookie-parser' +import cookieParser from 'cookie-parser' import { router as routes } from "./routes"; //import { router as middlewares } from './middlewares' //import env from './config/environment' @@ -35,8 +35,8 @@ export const app = express(); app.use(morgan("dev")); app.use(express.urlencoded({ extended: true })); app.use(express.json()); -//app.use(express.static(path.join(__dirname, 'public'))) -//app.use(cookieParser()) +app.use(express.static(path.join(__dirname, 'public'))) +app.use(cookieParser()) // Routes app.use(routes); diff --git a/api/src/middlewares/authMiddleware.ts b/api/src/middlewares/authMiddleware.ts new file mode 100644 index 0000000..475f177 --- /dev/null +++ b/api/src/middlewares/authMiddleware.ts @@ -0,0 +1,90 @@ +import { Request, Response, NextFunction } from 'express'; +import jwt from 'jsonwebtoken'; +import env from '../config/environment'; +import { Log } from 'nork'; +import User from '../models/User'; +import { isValidObjectId } from 'mongoose'; + +export function requireAuth(req: Request, res: Response, next: NextFunction) { + const token = req.cookies?.jwt; + + if (token) { + jwt.verify(token, env.JWT_SECRET, async (err: any, decodedToken: any) => { + if (err) { + // console.error(err.message) + res.status(401).send(Log.error(401, 'user is not authenticated')); + } + if (!err) { + const user = await User.findById(decodedToken.id); + if (user === null) { + res.status(401).send(Log.error(401, 'user is not authenticated')); + return; + } + res.locals.user = user; + Log.info(100, 'user is authenticated'); + next(); + } + }); + } + + if (!token) { + res.status(401).send(Log.error(401, 'user is not authenticated')); + } +} + +export function requireVerified(req: Request, res: Response, next: NextFunction) { + if (res.locals.user._id) { + if (res.locals.user.verified) { + Log.info(100, 'user is verified'); + next(); + return; + } + + res.status(403).json(Log.error(403, 'user is not verified')); + return; + } + + if (!res.locals.user._id) { + res.status(401).send(Log.error(401, 'user is not authenticated')); + return; + } +} + +export class requireRole { + static Admin(req: Request, res: Response, next: NextFunction) { + if (res.locals.user.admin) { + Log.info(100, 'user is admin'); + next(); + return; + } + res.status(403).json(Log.error(403, 'insufficient permissions')); + return; + } + static Owner(req: Request, res: Response, next: NextFunction) { + try { + if (!isValidObjectId(req.body.domain_id)) { + throw Log.error(400, 'neznámé domain_id'); + } + + const domain = res.locals.user.domains.filter((domain: any) => domain.domain_id == req.body.domain_id); + console.log(domain); + + if (domain.length < 1) { + throw Log.error(400, 'neznámé domain_id'); + } + + if (domain[0].role == 1) { + Log.info(100, 'user is owner'); + next(); + return; + } + + res.status(403).json(Log.error(403, 'insufficient permissions')); + return; + } catch (err: any) { + res.status(400).json(err); + } + } + static Editor(req: Request, res: Response, next: NextFunction) {} + static Guest(req: Request, res: Response, next: NextFunction) {} +} \ No newline at end of file diff --git a/api/src/routes/api_v1.ts b/api/src/routes/api_v1.ts index 8789666..c8a3855 100644 --- a/api/src/routes/api_v1.ts +++ b/api/src/routes/api_v1.ts @@ -3,7 +3,7 @@ import * as authController from "../controllers/authController"; import validate from '../middlewares/validateRequest' import * as AuthVal from '../validators/authValidator' //import handleValidation from "../middlewares/handleValidation"; -//import { requireAuth } from "../middlewares/authMiddleware"; +import { requireAuth } from "../middlewares/authMiddleware"; const router = Router(); @@ -11,6 +11,7 @@ const router = Router(); router.post("/auth/signup",validate(AuthVal.signup) , authController.signup_post); router.post("/auth/signin",validate(AuthVal.signin) , authController.signin_post); +router.post("/auth/logout", requireAuth, authController.logout_post); //router.post( // "/login", diff --git a/api/tests/auth.test.ts b/api/tests/auth.test.ts index acdd09c..95d8d82 100644 --- a/api/tests/auth.test.ts +++ b/api/tests/auth.test.ts @@ -190,9 +190,6 @@ describe('POST /api/v1/auth/signin', () => { }); }); -/** - * Throws errors idk - describe('POST /api/v1/auth/logout', () => { const url = '/api/v1/auth/logout'; test('should drop 401 error', async () => { @@ -202,18 +199,13 @@ describe('POST /api/v1/auth/logout', () => { test('should logout an user', async () => { const jwt = await login(); - const res = await request.post(url).set('Cookie', jwt).send({}); - - res.headers['set-cookie'].forEach((el: any) => { - if (el.split('=')[0] == 'jwt') { - expect(Number(el.split('=')[2][0])).toBe(0); - } - }); + const res = await request.post(url).set('Cookie', jwt).send(); expect(res.statusCode).toBe(200); + expect(res.header['set-cookie'][0]).toContain("jwt=; Max-Age=0") + expect(res.header['set-cookie'][1]).toContain("auth=false") }); }); - */ /* describe('GET /api/v1/auth/status', () => {