From 8ce824356ce4f99fd906dcfbcd7234c6a50c5e5d Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 15:25:27 +0200 Subject: [PATCH 01/25] OV-8: + empty auth jwt plugin --- .../common/plugins/auth/auth-jwt.plugin.ts | 20 +++++++++++++++++++ backend/src/common/plugins/plugins.ts | 1 + 2 files changed, 21 insertions(+) create mode 100644 backend/src/common/plugins/auth/auth-jwt.plugin.ts create mode 100644 backend/src/common/plugins/plugins.ts diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts new file mode 100644 index 000000000..cb29f74e1 --- /dev/null +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -0,0 +1,20 @@ +import fp from 'fastify-plugin'; + +type Options = { + routesWhiteList: string[]; +}; + +const authenticateJWT = fp((fastify, options, done) => { + // todo + fastify.addHook('preHandler', (request, reply, done) => { + if (options.routesWhiteList.includes(request.url)) { + return done(); + } + + done(); + }); + + done(); +}); + +export { authenticateJWT }; diff --git a/backend/src/common/plugins/plugins.ts b/backend/src/common/plugins/plugins.ts new file mode 100644 index 000000000..edaf41ada --- /dev/null +++ b/backend/src/common/plugins/plugins.ts @@ -0,0 +1 @@ +export { authenticateJWT } from './auth/auth-jwt.plugin.js'; From 44b25328ee71e5208e0cb0ce8df7788f5b4643ae Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 15:31:16 +0200 Subject: [PATCH 02/25] OV-8: + register plugins --- backend/src/common/server-application/base-server-app.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/backend/src/common/server-application/base-server-app.ts b/backend/src/common/server-application/base-server-app.ts index 25cef068b..d6a39d8ba 100644 --- a/backend/src/common/server-application/base-server-app.ts +++ b/backend/src/common/server-application/base-server-app.ts @@ -22,6 +22,7 @@ import { type ValidationSchema, } from '~/common/types/types.js'; +import { authenticateJWT } from '../plugins/plugins.js'; import { type ServerApp, type ServerAppApi, @@ -122,6 +123,12 @@ class BaseServerApp implements ServerApp { ); } + private registerPlugins(): void { + this.app.register(authenticateJWT, { + routesWhiteList: ['/api/v1/users/'], + }); + } + private initValidationCompiler(): void { this.app.setValidatorCompiler( ({ schema }: { schema: ValidationSchema }) => { @@ -200,6 +207,8 @@ class BaseServerApp implements ServerApp { await this.initMiddlewares(); + this.registerPlugins(); + this.initValidationCompiler(); this.initErrorHandler(); From da1397e4c2556665da7e17962ee8d9c7a42a7880 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 16:15:08 +0200 Subject: [PATCH 03/25] OV-8: + dependencies --- package-lock.json | 12 ++++++++++++ package.json | 4 ++++ 2 files changed, 16 insertions(+) diff --git a/package-lock.json b/package-lock.json index 711edfde0..a0a8c132c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,10 @@ "backend", "frontend" ], + "dependencies": { + "fastify-plugin": "4.5.1", + "jose": "5.7.0" + }, "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", @@ -8447,6 +8451,14 @@ "jiti": "bin/jiti.js" } }, + "node_modules/jose": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/jose/-/jose-5.7.0.tgz", + "integrity": "sha512-3P9qfTYDVnNn642LCAqIKbTGb9a1TBxZ9ti5zEVEr48aDdflgRjhspWFb6WM4PzAfFbGMJYC4+803v8riCRAKw==", + "funding": { + "url": "https://github.com/sponsors/panva" + } + }, "node_modules/joycon": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", diff --git a/package.json b/package.json index 8bf4426ea..fdb0aec4f 100644 --- a/package.json +++ b/package.json @@ -48,5 +48,9 @@ "simple-git-hooks": { "pre-commit": "npx lint-staged", "commit-msg": "npx commitlint --edit $1" + }, + "dependencies": { + "fastify-plugin": "4.5.1", + "jose": "5.7.0" } } From 9721153433cbe9a41ad3880ed1ccd5614d5284cd Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 18:25:37 +0200 Subject: [PATCH 04/25] OV-8: + findById method to Repository type --- backend/src/common/types/repository.type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/common/types/repository.type.ts b/backend/src/common/types/repository.type.ts index d69be849b..cec93d641 100644 --- a/backend/src/common/types/repository.type.ts +++ b/backend/src/common/types/repository.type.ts @@ -4,6 +4,7 @@ type Repository = { create(payload: unknown): Promise; update(): Promise; delete(): Promise; + findById(userId: string): Promise; }; export { type Repository }; From 89ec60b612b4d1ac9181d7aaa9dcec7800e4e358 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 18:27:21 +0200 Subject: [PATCH 05/25] OV-8: + findById method to Service type --- backend/src/common/types/service.type.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/common/types/service.type.ts b/backend/src/common/types/service.type.ts index 7b1a64ebb..3fa38468b 100644 --- a/backend/src/common/types/service.type.ts +++ b/backend/src/common/types/service.type.ts @@ -3,6 +3,7 @@ type Service = { findAll(): Promise<{ items: T[]; }>; + findById(userId: string): Promise; create(payload: unknown): Promise; update(): Promise; delete(): Promise; From b707dc38d37372f8ee9c9fce2c3643c7d4ca9257 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 18:29:02 +0200 Subject: [PATCH 06/25] OV-8: + findById method to user service and repository --- backend/src/bundles/users/user.repository.ts | 6 ++++++ backend/src/bundles/users/user.service.ts | 4 ++++ 2 files changed, 10 insertions(+) diff --git a/backend/src/bundles/users/user.repository.ts b/backend/src/bundles/users/user.repository.ts index f6b5873aa..b37c89e3d 100644 --- a/backend/src/bundles/users/user.repository.ts +++ b/backend/src/bundles/users/user.repository.ts @@ -20,6 +20,12 @@ class UserRepository implements Repository { return user ? UserEntity.initialize(user) : null; } + public async findById(userId: string): Promise { + const user = await this.userModel.query().findById(userId).execute(); + + return user ? UserEntity.initialize(user) : null; + } + public async findAll(): Promise { const users = await this.userModel.query().execute(); diff --git a/backend/src/bundles/users/user.service.ts b/backend/src/bundles/users/user.service.ts index a99f1f93f..222e4b72a 100644 --- a/backend/src/bundles/users/user.service.ts +++ b/backend/src/bundles/users/user.service.ts @@ -24,6 +24,10 @@ class UserService implements Service { return await this.userRepository.findByEmail(email); } + public async findById(userId: string): Promise { + return await this.userRepository.findById(userId); + } + public async findAll(): Promise { const items = await this.userRepository.findAll(); From 5e4644484d910deb342b9a6ff5902c20ac0a0b5f Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 18:40:53 +0200 Subject: [PATCH 07/25] OV-8: * userId to number --- backend/src/bundles/users/user.repository.ts | 2 +- backend/src/bundles/users/user.service.ts | 2 +- backend/src/common/types/repository.type.ts | 2 +- backend/src/common/types/service.type.ts | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/bundles/users/user.repository.ts b/backend/src/bundles/users/user.repository.ts index b37c89e3d..914108bd1 100644 --- a/backend/src/bundles/users/user.repository.ts +++ b/backend/src/bundles/users/user.repository.ts @@ -20,7 +20,7 @@ class UserRepository implements Repository { return user ? UserEntity.initialize(user) : null; } - public async findById(userId: string): Promise { + public async findById(userId: number): Promise { const user = await this.userModel.query().findById(userId).execute(); return user ? UserEntity.initialize(user) : null; diff --git a/backend/src/bundles/users/user.service.ts b/backend/src/bundles/users/user.service.ts index 222e4b72a..171c8ab4a 100644 --- a/backend/src/bundles/users/user.service.ts +++ b/backend/src/bundles/users/user.service.ts @@ -24,7 +24,7 @@ class UserService implements Service { return await this.userRepository.findByEmail(email); } - public async findById(userId: string): Promise { + public async findById(userId: number): Promise { return await this.userRepository.findById(userId); } diff --git a/backend/src/common/types/repository.type.ts b/backend/src/common/types/repository.type.ts index cec93d641..780e27a0a 100644 --- a/backend/src/common/types/repository.type.ts +++ b/backend/src/common/types/repository.type.ts @@ -4,7 +4,7 @@ type Repository = { create(payload: unknown): Promise; update(): Promise; delete(): Promise; - findById(userId: string): Promise; + findById(userId: number): Promise; }; export { type Repository }; diff --git a/backend/src/common/types/service.type.ts b/backend/src/common/types/service.type.ts index 3fa38468b..a1a961cc1 100644 --- a/backend/src/common/types/service.type.ts +++ b/backend/src/common/types/service.type.ts @@ -3,7 +3,7 @@ type Service = { findAll(): Promise<{ items: T[]; }>; - findById(userId: string): Promise; + findById(userId: number): Promise; create(payload: unknown): Promise; update(): Promise; delete(): Promise; From 50245d6cbef1615f32330bbff3b47cb85f836cc7 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 19:06:59 +0200 Subject: [PATCH 08/25] OV-8: + http codes to http code enum --- shared/src/framework/http/enums/http-code.enum.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shared/src/framework/http/enums/http-code.enum.ts b/shared/src/framework/http/enums/http-code.enum.ts index 6d2ad89ba..4f64e0c55 100644 --- a/shared/src/framework/http/enums/http-code.enum.ts +++ b/shared/src/framework/http/enums/http-code.enum.ts @@ -4,6 +4,8 @@ const HttpCode = { BAD_REQUEST: 400, UNPROCESSED_ENTITY: 422, INTERNAL_SERVER_ERROR: 500, + UNAUTHORIZED: 401, + FORBIDDEN: 403, } as const; export { HttpCode }; From ee3a4e536db291a76c8791baf2fac6f9a50c7829 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 19:10:52 +0200 Subject: [PATCH 09/25] OV-8: + hook and error messages enums for auth plugin --- backend/src/common/plugins/auth/enums/enums.ts | 2 ++ backend/src/common/plugins/auth/enums/error-message.enum.ts | 5 +++++ backend/src/common/plugins/auth/enums/hook.enum.ts | 5 +++++ 3 files changed, 12 insertions(+) create mode 100644 backend/src/common/plugins/auth/enums/enums.ts create mode 100644 backend/src/common/plugins/auth/enums/error-message.enum.ts create mode 100644 backend/src/common/plugins/auth/enums/hook.enum.ts diff --git a/backend/src/common/plugins/auth/enums/enums.ts b/backend/src/common/plugins/auth/enums/enums.ts new file mode 100644 index 000000000..ab66478a4 --- /dev/null +++ b/backend/src/common/plugins/auth/enums/enums.ts @@ -0,0 +1,2 @@ +export { ErrorMessage } from './error-message.enum.js'; +export { Hook } from './hook.enum.js'; diff --git a/backend/src/common/plugins/auth/enums/error-message.enum.ts b/backend/src/common/plugins/auth/enums/error-message.enum.ts new file mode 100644 index 000000000..eae69fec2 --- /dev/null +++ b/backend/src/common/plugins/auth/enums/error-message.enum.ts @@ -0,0 +1,5 @@ +const ErrorMessage = { + MISSING_TOKEN: 'You are not logged in', +} as const; + +export { ErrorMessage }; diff --git a/backend/src/common/plugins/auth/enums/hook.enum.ts b/backend/src/common/plugins/auth/enums/hook.enum.ts new file mode 100644 index 000000000..5588cd61c --- /dev/null +++ b/backend/src/common/plugins/auth/enums/hook.enum.ts @@ -0,0 +1,5 @@ +const Hook = { + PRE_HANDLER: 'preHandler', +} as const; + +export { Hook }; From 8eb1aae88d78bba16696a9bdb4470ac2d0bd5ac8 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 19:36:07 +0200 Subject: [PATCH 10/25] OV-8: * export user entity --- backend/src/bundles/users/users.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/src/bundles/users/users.ts b/backend/src/bundles/users/users.ts index 73f640e85..3c7531b73 100644 --- a/backend/src/bundles/users/users.ts +++ b/backend/src/bundles/users/users.ts @@ -16,6 +16,7 @@ export { type UserSignUpRequestDto, type UserSignUpResponseDto, } from './types/types.js'; +export { type UserEntity } from './user.entity.js'; export { UserModel } from './user.model.js'; export { userSignInValidationSchema, From 356145127adcb2488173cd596ba6ae744fb94541 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 19:37:44 +0200 Subject: [PATCH 11/25] OV-8: * implement auth jwt plugin --- .../common/plugins/auth/auth-jwt.plugin.ts | 50 +++++++++++++++++-- .../plugins/auth/enums/error-message.enum.ts | 2 + 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index cb29f74e1..025e26995 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -1,17 +1,59 @@ import fp from 'fastify-plugin'; +import { HttpCode, HttpError, HttpHeader } from 'shared'; + +import { type UserEntity, userService } from '~/bundles/users/users.js'; +import { tokenService } from '~/common/services/services.js'; + +import { ErrorMessage, Hook } from './enums/enums.js'; type Options = { routesWhiteList: string[]; }; +declare module 'fastify' { + interface FastifyRequest { + user: UserEntity; + } +} + const authenticateJWT = fp((fastify, options, done) => { - // todo - fastify.addHook('preHandler', (request, reply, done) => { + fastify.decorateRequest('user', null); + + fastify.addHook(Hook.PRE_HANDLER, async (request) => { if (options.routesWhiteList.includes(request.url)) { - return done(); + return; + } + + const authHeader = request.headers[HttpHeader.AUTHORIZATION]; + + if (!authHeader) { + throw new HttpError({ + message: ErrorMessage.MISSING_TOKEN, + status: HttpCode.UNAUTHORIZED, + }); + } + + const [, token] = authHeader.split(' '); + + const userId = await tokenService.getUserIdFromToken(token as string); + + if (!userId) { + throw new HttpError({ + message: ErrorMessage.INVALID_TOKEN, + status: HttpCode.UNAUTHORIZED, + }); + } + + const user = await userService.findById(userId); + + if (!user) { + throw new HttpError({ + message: ErrorMessage.MISSING_USER, + status: HttpCode.BAD_REQUEST, + }); } - done(); + request.user = user; }); done(); diff --git a/backend/src/common/plugins/auth/enums/error-message.enum.ts b/backend/src/common/plugins/auth/enums/error-message.enum.ts index eae69fec2..58e565b33 100644 --- a/backend/src/common/plugins/auth/enums/error-message.enum.ts +++ b/backend/src/common/plugins/auth/enums/error-message.enum.ts @@ -1,5 +1,7 @@ const ErrorMessage = { MISSING_TOKEN: 'You are not logged in', + INVALID_TOKEN: 'Token is no longer valid. Please log in again.', + MISSING_USER: 'User with this id does not exist.', } as const; export { ErrorMessage }; From f034695d15c0ba09ab854263bd38fa333881fa3d Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 20:05:01 +0200 Subject: [PATCH 12/25] OV-8: + white routes constant --- backend/src/common/constants/constants.ts | 1 + backend/src/common/constants/white-routes.constants.ts | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 backend/src/common/constants/white-routes.constants.ts diff --git a/backend/src/common/constants/constants.ts b/backend/src/common/constants/constants.ts index 172cdf50f..1a5d15784 100644 --- a/backend/src/common/constants/constants.ts +++ b/backend/src/common/constants/constants.ts @@ -1 +1,2 @@ export { USER_PASSWORD_SALT_ROUNDS } from './user.constants.js'; +export { WHITE_ROUTES } from './white-routes.constants.js'; diff --git a/backend/src/common/constants/white-routes.constants.ts b/backend/src/common/constants/white-routes.constants.ts new file mode 100644 index 000000000..b2837860d --- /dev/null +++ b/backend/src/common/constants/white-routes.constants.ts @@ -0,0 +1,8 @@ +import { ApiPath, AuthApiPath } from 'shared'; + +const WHITE_ROUTES = [ + `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_IN}`, + `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_UP}`, +]; + +export { WHITE_ROUTES }; From 36a220ef8da5a0e400a9ed4aa9ace93b254f8692 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 20:06:20 +0200 Subject: [PATCH 13/25] OV-8: * refactor checking for white route --- backend/src/common/plugins/auth/auth-jwt.plugin.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index 025e26995..a4d9b3723 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -20,7 +20,11 @@ const authenticateJWT = fp((fastify, options, done) => { fastify.decorateRequest('user', null); fastify.addHook(Hook.PRE_HANDLER, async (request) => { - if (options.routesWhiteList.includes(request.url)) { + const isRouteInWhiteList = options.routesWhiteList.includes( + request.url, + ); + + if (isRouteInWhiteList) { return; } From 9e4004b973c0a423d80d75947835ea3b5da935dd Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 20:07:13 +0200 Subject: [PATCH 14/25] OV-8: * use white routes constant --- backend/src/common/server-application/base-server-app.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/src/common/server-application/base-server-app.ts b/backend/src/common/server-application/base-server-app.ts index d6a39d8ba..35a5b6ffd 100644 --- a/backend/src/common/server-application/base-server-app.ts +++ b/backend/src/common/server-application/base-server-app.ts @@ -22,6 +22,7 @@ import { type ValidationSchema, } from '~/common/types/types.js'; +import { WHITE_ROUTES } from '../constants/constants.js'; import { authenticateJWT } from '../plugins/plugins.js'; import { type ServerApp, @@ -125,7 +126,7 @@ class BaseServerApp implements ServerApp { private registerPlugins(): void { this.app.register(authenticateJWT, { - routesWhiteList: ['/api/v1/users/'], + routesWhiteList: WHITE_ROUTES, }); } From 502aad9dd79dec10ea36437a2ae1af95a73e0529 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 20 Aug 2024 20:13:25 +0200 Subject: [PATCH 15/25] OV-8: * extract fastify module augmentation into file --- backend/src/common/plugins/auth/auth-jwt.plugin.ts | 8 +------- backend/src/common/types/fastify.d.ts | 9 +++++++++ package-lock.json | 1 + 3 files changed, 11 insertions(+), 7 deletions(-) create mode 100644 backend/src/common/types/fastify.d.ts diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index a4d9b3723..82c36e3df 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -1,7 +1,7 @@ import fp from 'fastify-plugin'; import { HttpCode, HttpError, HttpHeader } from 'shared'; -import { type UserEntity, userService } from '~/bundles/users/users.js'; +import { userService } from '~/bundles/users/users.js'; import { tokenService } from '~/common/services/services.js'; import { ErrorMessage, Hook } from './enums/enums.js'; @@ -10,12 +10,6 @@ type Options = { routesWhiteList: string[]; }; -declare module 'fastify' { - interface FastifyRequest { - user: UserEntity; - } -} - const authenticateJWT = fp((fastify, options, done) => { fastify.decorateRequest('user', null); diff --git a/backend/src/common/types/fastify.d.ts b/backend/src/common/types/fastify.d.ts new file mode 100644 index 000000000..f1b244180 --- /dev/null +++ b/backend/src/common/types/fastify.d.ts @@ -0,0 +1,9 @@ +import 'fastify'; + +import { type UserEntity } from '~/bundles/users/users.js'; + +declare module 'fastify' { + interface FastifyRequest { + user: UserEntity; + } +} diff --git a/package-lock.json b/package-lock.json index a0a8c132c..35a05e5d9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,6 +50,7 @@ "convict": "6.2.4", "dotenv": "16.4.5", "fastify": "4.28.1", + "jose": "5.7.0", "knex": "3.1.0", "objection": "3.1.4", "pg": "8.12.0", From 218665a268659ca330cb549b82bc8e919bf29bca Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 15:47:33 +0200 Subject: [PATCH 16/25] OV-8: * modify find user method instead of adding findById --- backend/src/bundles/users/user.service.ts | 8 ++------ backend/src/common/plugins/auth/auth-jwt.plugin.ts | 2 +- backend/src/common/types/service.type.ts | 3 +-- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/backend/src/bundles/users/user.service.ts b/backend/src/bundles/users/user.service.ts index 3854c999e..532ac1661 100644 --- a/backend/src/bundles/users/user.service.ts +++ b/backend/src/bundles/users/user.service.ts @@ -16,18 +16,14 @@ class UserService implements Service { this.userRepository = userRepository; } - public find(): ReturnType { - return Promise.resolve(null); + public async find(userId: number): Promise { + return await this.userRepository.findById(userId); } public async findByEmail(email: string): Promise { return await this.userRepository.findByEmail(email); } - public async findById(userId: number): Promise { - return await this.userRepository.findById(userId); - } - public async findAll(): Promise { const items = await this.userRepository.findAll(); diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index 82c36e3df..5159365f5 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -42,7 +42,7 @@ const authenticateJWT = fp((fastify, options, done) => { }); } - const user = await userService.findById(userId); + const user = await userService.find(userId); if (!user) { throw new HttpError({ diff --git a/backend/src/common/types/service.type.ts b/backend/src/common/types/service.type.ts index a1a961cc1..90c8f4812 100644 --- a/backend/src/common/types/service.type.ts +++ b/backend/src/common/types/service.type.ts @@ -1,9 +1,8 @@ type Service = { - find(): Promise; + find(userId: number): Promise; findAll(): Promise<{ items: T[]; }>; - findById(userId: number): Promise; create(payload: unknown): Promise; update(): Promise; delete(): Promise; From 2f9f95188723620c645aee1ffec95bf475d3bcdd Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 16:04:48 +0200 Subject: [PATCH 17/25] OV-8: * move dependencies to backend --- backend/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/package.json b/backend/package.json index 1585f78ae..d5afb9b7f 100644 --- a/backend/package.json +++ b/backend/package.json @@ -34,13 +34,14 @@ "convict": "6.2.4", "dotenv": "16.4.5", "fastify": "4.28.1", + "fastify-plugin": "4.5.1", + "jose": "5.7.0", "knex": "3.1.0", "objection": "3.1.4", "pg": "8.12.0", "pino": "9.3.2", "pino-pretty": "10.3.1", "shared": "*", - "swagger-jsdoc": "6.2.8", - "jose": "5.7.0" + "swagger-jsdoc": "6.2.8" } } From 9f17f91d14fd270f9cbcc9b8ca6a1dbcb5d40dc2 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 16:30:33 +0200 Subject: [PATCH 18/25] OV-8: * white routes constant to include path method --- backend/src/common/constants/white-routes.constants.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/backend/src/common/constants/white-routes.constants.ts b/backend/src/common/constants/white-routes.constants.ts index b2837860d..faf1348e1 100644 --- a/backend/src/common/constants/white-routes.constants.ts +++ b/backend/src/common/constants/white-routes.constants.ts @@ -1,8 +1,14 @@ import { ApiPath, AuthApiPath } from 'shared'; const WHITE_ROUTES = [ - `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_IN}`, - `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_UP}`, + { + path: `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_IN}`, + method: 'POST', + }, + { + path: `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_UP}`, + method: 'POST', + }, ]; export { WHITE_ROUTES }; From 3aaf5396f49a75824365049382a43c3ce8d68ec3 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 16:35:27 +0200 Subject: [PATCH 19/25] OV-8: + route type --- backend/src/common/plugins/auth/types/route.type.ts | 6 ++++++ backend/src/common/plugins/auth/types/types.ts | 1 + 2 files changed, 7 insertions(+) create mode 100644 backend/src/common/plugins/auth/types/route.type.ts create mode 100644 backend/src/common/plugins/auth/types/types.ts diff --git a/backend/src/common/plugins/auth/types/route.type.ts b/backend/src/common/plugins/auth/types/route.type.ts new file mode 100644 index 000000000..2ece81d01 --- /dev/null +++ b/backend/src/common/plugins/auth/types/route.type.ts @@ -0,0 +1,6 @@ +type Route = { + path: string; + method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; +}; + +export { type Route }; diff --git a/backend/src/common/plugins/auth/types/types.ts b/backend/src/common/plugins/auth/types/types.ts new file mode 100644 index 000000000..da236e3fd --- /dev/null +++ b/backend/src/common/plugins/auth/types/types.ts @@ -0,0 +1 @@ +export { type Route } from './route.type.js'; From dbfec2d8f98310a4b64e5cac0dfe578d4eb6f65d Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 16:45:58 +0200 Subject: [PATCH 20/25] OV-8: * checking if route is in white list with method --- backend/src/common/plugins/auth/auth-jwt.plugin.ts | 10 ++++++---- package-lock.json | 5 +---- package.json | 4 ---- 3 files changed, 7 insertions(+), 12 deletions(-) diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index 5159365f5..e77b4f82f 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -5,17 +5,19 @@ import { userService } from '~/bundles/users/users.js'; import { tokenService } from '~/common/services/services.js'; import { ErrorMessage, Hook } from './enums/enums.js'; +import { type Route } from './types/types.js'; type Options = { - routesWhiteList: string[]; + routesWhiteList: Route[]; }; -const authenticateJWT = fp((fastify, options, done) => { +const authenticateJWT = fp((fastify, { routesWhiteList }, done) => { fastify.decorateRequest('user', null); fastify.addHook(Hook.PRE_HANDLER, async (request) => { - const isRouteInWhiteList = options.routesWhiteList.includes( - request.url, + const isRouteInWhiteList = routesWhiteList.some( + (route) => + route.path === request.url && route.method === request.method, ); if (isRouteInWhiteList) { diff --git a/package-lock.json b/package-lock.json index 35a05e5d9..2ce5f1c2f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,10 +11,6 @@ "backend", "frontend" ], - "dependencies": { - "fastify-plugin": "4.5.1", - "jose": "5.7.0" - }, "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", @@ -50,6 +46,7 @@ "convict": "6.2.4", "dotenv": "16.4.5", "fastify": "4.28.1", + "fastify-plugin": "4.5.1", "jose": "5.7.0", "knex": "3.1.0", "objection": "3.1.4", diff --git a/package.json b/package.json index fdb0aec4f..8bf4426ea 100644 --- a/package.json +++ b/package.json @@ -48,9 +48,5 @@ "simple-git-hooks": { "pre-commit": "npx lint-staged", "commit-msg": "npx commitlint --edit $1" - }, - "dependencies": { - "fastify-plugin": "4.5.1", - "jose": "5.7.0" } } From b4fbbdeaea191a712dd57694860429335a7be9f1 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 17:32:21 +0200 Subject: [PATCH 21/25] OV-8: + util function for checking route in white routes --- .../src/common/plugins/auth/auth-jwt.plugin.ts | 8 ++------ .../plugins/auth/utils/check-white-routes.util.ts | 15 +++++++++++++++ backend/src/common/plugins/auth/utils/utils.ts | 1 + 3 files changed, 18 insertions(+), 6 deletions(-) create mode 100644 backend/src/common/plugins/auth/utils/check-white-routes.util.ts create mode 100644 backend/src/common/plugins/auth/utils/utils.ts diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index e77b4f82f..9a5c77635 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -6,6 +6,7 @@ import { tokenService } from '~/common/services/services.js'; import { ErrorMessage, Hook } from './enums/enums.js'; import { type Route } from './types/types.js'; +import { isRouteInWhiteList } from './utils/utils.js'; type Options = { routesWhiteList: Route[]; @@ -15,12 +16,7 @@ const authenticateJWT = fp((fastify, { routesWhiteList }, done) => { fastify.decorateRequest('user', null); fastify.addHook(Hook.PRE_HANDLER, async (request) => { - const isRouteInWhiteList = routesWhiteList.some( - (route) => - route.path === request.url && route.method === request.method, - ); - - if (isRouteInWhiteList) { + if (isRouteInWhiteList(routesWhiteList, request)) { return; } diff --git a/backend/src/common/plugins/auth/utils/check-white-routes.util.ts b/backend/src/common/plugins/auth/utils/check-white-routes.util.ts new file mode 100644 index 000000000..09f040f31 --- /dev/null +++ b/backend/src/common/plugins/auth/utils/check-white-routes.util.ts @@ -0,0 +1,15 @@ +import { type FastifyRequest } from 'fastify'; + +import { type Route } from '../types/types.js'; + +const isRouteInWhiteList = ( + routesWhiteList: Route[], + request: FastifyRequest, +): boolean => { + return routesWhiteList.some( + (route) => + route.path === request.url && route.method === request.method, + ); +}; + +export { isRouteInWhiteList }; diff --git a/backend/src/common/plugins/auth/utils/utils.ts b/backend/src/common/plugins/auth/utils/utils.ts new file mode 100644 index 000000000..7dc2439bd --- /dev/null +++ b/backend/src/common/plugins/auth/utils/utils.ts @@ -0,0 +1 @@ +export { isRouteInWhiteList } from './check-white-routes.util.js'; From a88eca175949731a610f75e63c7a49da1ebe5e5a Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 17:38:35 +0200 Subject: [PATCH 22/25] OV-8: * modify find method in user repository instead of findById --- backend/src/bundles/users/user.repository.ts | 14 ++++++++------ backend/src/bundles/users/user.service.ts | 2 +- backend/src/common/types/repository.type.ts | 3 +-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/backend/src/bundles/users/user.repository.ts b/backend/src/bundles/users/user.repository.ts index 914108bd1..f9f8d8c03 100644 --- a/backend/src/bundles/users/user.repository.ts +++ b/backend/src/bundles/users/user.repository.ts @@ -10,8 +10,10 @@ class UserRepository implements Repository { this.userModel = userModel; } - public find(): ReturnType { - return Promise.resolve(null); + public async find(userId: number): Promise { + const user = await this.userModel.query().findById(userId).execute(); + + return user ? UserEntity.initialize(user) : null; } public async findByEmail(email: string): Promise { @@ -20,11 +22,11 @@ class UserRepository implements Repository { return user ? UserEntity.initialize(user) : null; } - public async findById(userId: number): Promise { - const user = await this.userModel.query().findById(userId).execute(); + // public async findById(userId: number): Promise { + // const user = await this.userModel.query().findById(userId).execute(); - return user ? UserEntity.initialize(user) : null; - } + // return user ? UserEntity.initialize(user) : null; + // } public async findAll(): Promise { const users = await this.userModel.query().execute(); diff --git a/backend/src/bundles/users/user.service.ts b/backend/src/bundles/users/user.service.ts index 532ac1661..6b4f851d3 100644 --- a/backend/src/bundles/users/user.service.ts +++ b/backend/src/bundles/users/user.service.ts @@ -17,7 +17,7 @@ class UserService implements Service { } public async find(userId: number): Promise { - return await this.userRepository.findById(userId); + return await this.userRepository.find(userId); } public async findByEmail(email: string): Promise { diff --git a/backend/src/common/types/repository.type.ts b/backend/src/common/types/repository.type.ts index 780e27a0a..ca82dc936 100644 --- a/backend/src/common/types/repository.type.ts +++ b/backend/src/common/types/repository.type.ts @@ -1,10 +1,9 @@ type Repository = { - find(): Promise; + find(userId: number): Promise; findAll(): Promise; create(payload: unknown): Promise; update(): Promise; delete(): Promise; - findById(userId: number): Promise; }; export { type Repository }; From 1ac2392101891597572c3a759714a3d95ed2de71 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Wed, 21 Aug 2024 18:40:22 +0200 Subject: [PATCH 23/25] OV-8: * use id instead of userId in types for repository and service --- backend/src/common/types/repository.type.ts | 2 +- backend/src/common/types/service.type.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/common/types/repository.type.ts b/backend/src/common/types/repository.type.ts index ca82dc936..999b9b1c5 100644 --- a/backend/src/common/types/repository.type.ts +++ b/backend/src/common/types/repository.type.ts @@ -1,5 +1,5 @@ type Repository = { - find(userId: number): Promise; + find(id: number): Promise; findAll(): Promise; create(payload: unknown): Promise; update(): Promise; diff --git a/backend/src/common/types/service.type.ts b/backend/src/common/types/service.type.ts index 90c8f4812..8b78c7cd5 100644 --- a/backend/src/common/types/service.type.ts +++ b/backend/src/common/types/service.type.ts @@ -1,5 +1,5 @@ type Service = { - find(userId: number): Promise; + find(id: number): Promise; findAll(): Promise<{ items: T[]; }>; From 035493226e649f0e290b82074debc7c1f655441c Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Fri, 23 Aug 2024 15:07:06 +0200 Subject: [PATCH 24/25] OV-8: - remove commented code --- backend/src/bundles/users/user.repository.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backend/src/bundles/users/user.repository.ts b/backend/src/bundles/users/user.repository.ts index f9f8d8c03..adefc0e8d 100644 --- a/backend/src/bundles/users/user.repository.ts +++ b/backend/src/bundles/users/user.repository.ts @@ -22,12 +22,6 @@ class UserRepository implements Repository { return user ? UserEntity.initialize(user) : null; } - // public async findById(userId: number): Promise { - // const user = await this.userModel.query().findById(userId).execute(); - - // return user ? UserEntity.initialize(user) : null; - // } - public async findAll(): Promise { const users = await this.userModel.query().execute(); From e9b8425914558b1ce58b10c4c8b4931e2af353f5 Mon Sep 17 00:00:00 2001 From: Oleksandra Okhotnykova Date: Tue, 27 Aug 2024 15:21:57 +0200 Subject: [PATCH 25/25] OV-8: * rename find to findById in service and repository --- backend/src/bundles/users/user.repository.ts | 2 +- backend/src/bundles/users/user.service.ts | 4 ++-- backend/src/common/plugins/auth/auth-jwt.plugin.ts | 2 +- backend/src/common/types/repository.type.ts | 2 +- backend/src/common/types/service.type.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/src/bundles/users/user.repository.ts b/backend/src/bundles/users/user.repository.ts index adefc0e8d..8924dcf21 100644 --- a/backend/src/bundles/users/user.repository.ts +++ b/backend/src/bundles/users/user.repository.ts @@ -10,7 +10,7 @@ class UserRepository implements Repository { this.userModel = userModel; } - public async find(userId: number): Promise { + public async findById(userId: number): Promise { const user = await this.userModel.query().findById(userId).execute(); return user ? UserEntity.initialize(user) : null; diff --git a/backend/src/bundles/users/user.service.ts b/backend/src/bundles/users/user.service.ts index 6b4f851d3..9109c5d03 100644 --- a/backend/src/bundles/users/user.service.ts +++ b/backend/src/bundles/users/user.service.ts @@ -16,8 +16,8 @@ class UserService implements Service { this.userRepository = userRepository; } - public async find(userId: number): Promise { - return await this.userRepository.find(userId); + public async findById(userId: number): Promise { + return await this.userRepository.findById(userId); } public async findByEmail(email: string): Promise { diff --git a/backend/src/common/plugins/auth/auth-jwt.plugin.ts b/backend/src/common/plugins/auth/auth-jwt.plugin.ts index 9a5c77635..7eb20583c 100644 --- a/backend/src/common/plugins/auth/auth-jwt.plugin.ts +++ b/backend/src/common/plugins/auth/auth-jwt.plugin.ts @@ -40,7 +40,7 @@ const authenticateJWT = fp((fastify, { routesWhiteList }, done) => { }); } - const user = await userService.find(userId); + const user = await userService.findById(userId); if (!user) { throw new HttpError({ diff --git a/backend/src/common/types/repository.type.ts b/backend/src/common/types/repository.type.ts index 999b9b1c5..de7d12a83 100644 --- a/backend/src/common/types/repository.type.ts +++ b/backend/src/common/types/repository.type.ts @@ -1,5 +1,5 @@ type Repository = { - find(id: number): Promise; + findById(id: number): Promise; findAll(): Promise; create(payload: unknown): Promise; update(): Promise; diff --git a/backend/src/common/types/service.type.ts b/backend/src/common/types/service.type.ts index 8b78c7cd5..a84006347 100644 --- a/backend/src/common/types/service.type.ts +++ b/backend/src/common/types/service.type.ts @@ -1,5 +1,5 @@ type Service = { - find(id: number): Promise; + findById(id: number): Promise; findAll(): Promise<{ items: T[]; }>;