From 82d356ef5e4b7b9d9a97b7d00a6015cf96cb7a27 Mon Sep 17 00:00:00 2001 From: Yanis Rigaudeau Date: Sun, 30 Oct 2022 19:35:35 +0100 Subject: [PATCH] better errors + better tools --- api/src/framework/express/middleware.ts | 13 ++++--- api/src/framework/express/user.ts | 34 +++++++++++------- api/src/framework/mongo/user.ts | 46 +++++++++++++++++-------- api/src/functions/logger.ts | 13 +++---- api/src/functions/user.ts | 12 +++---- scripts/tools.py | 26 ++++++++++---- www/package.json | 2 +- 7 files changed, 93 insertions(+), 53 deletions(-) diff --git a/api/src/framework/express/middleware.ts b/api/src/framework/express/middleware.ts index 86b24f6..4846a20 100644 --- a/api/src/framework/express/middleware.ts +++ b/api/src/framework/express/middleware.ts @@ -9,7 +9,7 @@ declare module 'express-session' { } } -export function getId(req: Request): string { +export function getRequestId(req: Request): string { return req.header('request-id') || 'unknown'; } @@ -22,8 +22,9 @@ export function RequestId(): RequestHandler { export function CheckPermissions(): RequestHandler { function getResourceId(req: Request): string | null { - if (req.params.uuid) return req.params.uuid; - if (req.body.uuid) return req.body.uuid; + if (req.method === 'GET' && req.params.uuid) return req.params.uuid; + if ((req.method === 'POST' || req.method === 'PUT') && req.body.uuid) + return req.body.uuid; return null; } @@ -48,6 +49,7 @@ export function CheckPermissions(): RequestHandler { next({ status: 403, messsage: 'Forbidden' }); return; } + if (canAccessRessource(req.session.user, ressourceId)) { next(); return; @@ -56,7 +58,8 @@ export function CheckPermissions(): RequestHandler { return; } - next({ status: 401, messsage: 'Unauthorized' }); + // Should be unreachable + next({ status: 403, messsage: 'Forbidden' }); }; } @@ -76,6 +79,6 @@ export function ErrorHandler(): ErrorRequestHandler { return (error, req, res, next) => { error.status ? res.status(error.status).send(error) - : res.status(500).send(error); + : res.status(500).send({ status: 500, message: error.message }); }; } diff --git a/api/src/framework/express/user.ts b/api/src/framework/express/user.ts index d3e9c55..3258ea2 100644 --- a/api/src/framework/express/user.ts +++ b/api/src/framework/express/user.ts @@ -7,17 +7,19 @@ import { ReadUserSchema, LogoutUserSchema, } from './schema/user'; -import { CheckPermissions, getId, SchemaValidator } from './middleware'; +import { CheckPermissions, getRequestId, SchemaValidator } from './middleware'; function LoginHandler(services: Services): RequestHandler { const login = LoginUser(services); return async (req, res, next) => { - const user = await login(getId(req), req.body); - user ? (req.session.user = user) : (req.session.user = null); - user - ? res.status(200).send(user) - : next({ status: 401, message: 'wrong username or password' }); + try { + const user = await login(getRequestId(req), req.body); + user ? (req.session.user = user) : (req.session.user = null); + res.status(200).send(user); + } catch (error) { + next({ status: 401, message: 'wrong username or password' }); + } }; } @@ -27,7 +29,7 @@ function LogoutHandler(services: Services): RequestHandler { req.session.user = null; res.status(204).send(); } else { - next({ status: 401, message: 'not logged in' }); + next({ status: 401, message: 'Not Logged In' }); } }; } @@ -36,8 +38,12 @@ function CreateHandler(services: Services): RequestHandler { const createUser = CreateUser(services); return async (req, res, next) => { - const user = await createUser(getId(req), req.body); - user ? res.status(201).send(user) : next(); + try { + const user = await createUser(getRequestId(req), req.body); + res.status(201).send(user); + } catch (error) { + next({ status: 409, message: 'User Already Exists' }); + } }; } @@ -45,10 +51,12 @@ function ReadHandler(services: Services): RequestHandler { const readUser = ReadUser(services); return async (req, res, next) => { - const user = await readUser(getId(req), req.params.uuid); - user - ? res.status(200).send(user) - : next({ status: 404, message: 'user not found' }); + try { + const user = await readUser(getRequestId(req), req.params.uuid); + res.status(200).send(user); + } catch (error) { + next({ status: 404, message: 'User Not Found' }); + } }; } diff --git a/api/src/framework/mongo/user.ts b/api/src/framework/mongo/user.ts index 7109aad..2c24d5d 100644 --- a/api/src/framework/mongo/user.ts +++ b/api/src/framework/mongo/user.ts @@ -1,5 +1,5 @@ import { Collection, Db } from 'mongodb'; -import { LoginUserBody } from '../../../../core/src/user'; +import { LoginUserBody, UserInfo } from '@core'; import { User, UserWithPassword } from '../../entities/user'; import log from '../../functions/logger'; import { generateHash } from '../../functions/password'; @@ -11,42 +11,58 @@ class UserModel { this.collection = db.collection('users'); } - public async login(tracker: string, data: LoginUserBody) { + public async login(tracker: string, data: LoginUserBody): Promise { const checkUser = await this.collection.findOne({ username: data.username, }); - if (checkUser === null) { + if (!checkUser) { log(tracker, 'User Not Found'); - return null; + throw new Error(); } - const user = await this.collection.findOne({ + const userDocument = await this.collection.findOne({ uuid: checkUser.uuid, password: generateHash(checkUser.uuid, data.password), }); - if (user === null) { + if (!userDocument) { log(tracker, 'Wrong Password'); - return null; + throw new Error(); } + const user = new User(userDocument); log(tracker, 'LOG IN', user); return new User(user); } - public async create(tracker: string, user: UserWithPassword) { - await this.collection.insertOne(user); + public async create( + tracker: string, + userInfo: UserWithPassword, + ): Promise { + const checkUser = await this.collection.findOne({ + username: userInfo.username, + }); + if (checkUser) { + log(tracker, 'User Already Exists'); + throw new Error(); + } + + await this.collection.insertOne(userInfo); + + const user = await this.read(tracker, userInfo.uuid); log(tracker, 'CREATE USER', user); - return this.read(tracker, user.uuid); + return user; } - public async read(tracker: string, uuid: string) { - const user = await this.collection.findOne({ uuid }); - if (user === null) { + public async read(tracker: string, uuid: string): Promise { + const userDocument = await this.collection.findOne({ uuid }); + if (!userDocument) { log(tracker, 'User Not Found'); - return null; + throw new Error(); } + + const user = new User(userDocument); log(tracker, 'READ USER', user); - return new User(user); + return user; } } diff --git a/api/src/functions/logger.ts b/api/src/functions/logger.ts index 26faa55..ccba982 100644 --- a/api/src/functions/logger.ts +++ b/api/src/functions/logger.ts @@ -1,11 +1,12 @@ export function log(tracker: string, ...message: unknown[]) { - message.forEach((obj, index) => { - try { - message[index] = JSON.stringify(obj); - } catch {} - }); + if (message) + message.forEach((obj, index) => { + try { + message[index] = JSON.stringify(obj); + } catch {} + }); - tracker ? console.log(`[${tracker}]`, ...message) : console.log(...message); + message ? console.log(`[${tracker}]`, ...message) : console.log(...tracker); } export default log; diff --git a/api/src/functions/user.ts b/api/src/functions/user.ts index e47c9b7..3026970 100644 --- a/api/src/functions/user.ts +++ b/api/src/functions/user.ts @@ -4,33 +4,33 @@ import { UserWithPassword } from '../entities/user'; export function LoginUser( services: Services, -): (tracker: string, raw: LoginUserBody) => Promise { +): (tracker: string, raw: LoginUserBody) => Promise { const { userModel } = services; return async (tracker, raw) => { const user = await userModel.login(tracker, raw); - return user ? user.Info() : null; + return user.Info(); }; } export function CreateUser( services: Services, -): (tracker: string, raw: CreateUserBody) => Promise { +): (tracker: string, raw: CreateUserBody) => Promise { const { userModel } = services; return async (tracker, raw) => { const user = await userModel.create(tracker, new UserWithPassword(raw)); - return user ? user.Info() : null; + return user.Info(); }; } export function ReadUser( services: Services, -): (tracker: string, uuid: string) => Promise { +): (tracker: string, uuid: string) => Promise { const { userModel } = services; return async (tracker, uuid) => { const user = await userModel.read(tracker, uuid); - return user ? user.Info() : null; + return user.Info(); }; } diff --git a/scripts/tools.py b/scripts/tools.py index 0915d93..f3ad1e0 100644 --- a/scripts/tools.py +++ b/scripts/tools.py @@ -1,6 +1,8 @@ #!/usr/bin/python -import os -import sys +from os import chdir, system, path +from sys import argv +from subprocess import run, PIPE +from multiprocessing import Process apps = ['core', 'api', 'www'] commands = { @@ -14,19 +16,29 @@ def print_commands(): print('Available commands:', [c for c in commands]) +def run_command_in_app(app: str, command: str): + chdir(app) + result = run(command.split(' '), stdout=PIPE, stderr=PIPE, text=True) + + status = 'DONE' if result.returncode == 0 else 'ERROR' + print('%s:\t%s' % (app, status)) + if status == 'ERROR': + print(result.stdout, result.stderr) + + if __name__ == '__main__': - if len(sys.argv) < 2: + if len(argv) < 2: print_commands() exit() - cmd = sys.argv[1] + cmd = argv[1] if cmd not in commands: print('Command \'%s\' not available' % cmd) print_commands() exit() + chdir(path.join(path.dirname(path.realpath(__file__)), '..')) + print('Running \'%s\' on %d apps: %s' % (commands[cmd], len(apps), apps)) for app in apps: - os.chdir(app) - os.system(commands[cmd]) - os.chdir('..') + Process(target=run_command_in_app, args=(app, commands[cmd])).start() diff --git a/www/package.json b/www/package.json index 6c87cf6..27f1374 100644 --- a/www/package.json +++ b/www/package.json @@ -5,7 +5,7 @@ "author": "Yanis Rigaudeau - Axel Barault", "private": true, "scripts": { - "build": "rollup -c", + "build": "rollup -c --failAfterWarnings", "dev": "rollup -c -w", "start": "sirv public --no-clear --host --single", "check": "svelte-check --tsconfig ./tsconfig.json",