-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OV-8: protect routing #33
Changes from 26 commits
8ce8243
44b2532
da1397e
5af5016
9721153
89ec60b
b707dc3
5e46444
50245d6
ee3a4e5
508cd31
8eb1aae
3561451
f034695
36a220e
9e4004b
502aad9
a9e0c53
218665a
2f9f951
9f17f91
3aaf539
dbfec2d
5a24c65
b4fbbde
a88eca1
1ac2392
0354932
e9b8425
9e20e1c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,2 @@ | ||
export { USER_PASSWORD_SALT_ROUNDS } from './user.constants.js'; | ||
export { WHITE_ROUTES } from './white-routes.constants.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { ApiPath, AuthApiPath } from 'shared'; | ||
|
||
const WHITE_ROUTES = [ | ||
{ | ||
path: `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_IN}`, | ||
method: 'POST', | ||
}, | ||
{ | ||
path: `/api/v1${ApiPath.AUTH}${AuthApiPath.SIGN_UP}`, | ||
method: 'POST', | ||
}, | ||
]; | ||
|
||
export { WHITE_ROUTES }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
import fp from 'fastify-plugin'; | ||
import { HttpCode, HttpError, HttpHeader } from 'shared'; | ||
|
||
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'; | ||
import { isRouteInWhiteList } from './utils/utils.js'; | ||
|
||
type Options = { | ||
routesWhiteList: Route[]; | ||
}; | ||
|
||
const authenticateJWT = fp<Options>((fastify, { routesWhiteList }, done) => { | ||
fastify.decorateRequest('user', null); | ||
|
||
fastify.addHook(Hook.PRE_HANDLER, async (request) => { | ||
if (isRouteInWhiteList(routesWhiteList, request)) { | ||
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.find(userId); | ||
|
||
if (!user) { | ||
throw new HttpError({ | ||
message: ErrorMessage.MISSING_USER, | ||
status: HttpCode.BAD_REQUEST, | ||
}); | ||
} | ||
|
||
request.user = user; | ||
}); | ||
|
||
done(); | ||
}); | ||
|
||
export { authenticateJWT }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { ErrorMessage } from './error-message.enum.js'; | ||
export { Hook } from './hook.enum.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +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 }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
const Hook = { | ||
PRE_HANDLER: 'preHandler', | ||
} as const; | ||
|
||
export { Hook }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
type Route = { | ||
path: string; | ||
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'; | ||
}; | ||
|
||
export { type Route }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { type Route } from './route.type.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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 }; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { isRouteInWhiteList } from './check-white-routes.util.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { authenticateJWT } from './auth/auth-jwt.plugin.js'; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import 'fastify'; | ||
|
||
import { type UserEntity } from '~/bundles/users/users.js'; | ||
|
||
declare module 'fastify' { | ||
interface FastifyRequest { | ||
user: UserEntity; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,5 @@ | ||||||
type Repository<T = unknown> = { | ||||||
find(): Promise<T>; | ||||||
find(userId: number): Promise<T | null>; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
we would use this method not only in user repo if we want to find something by id |
||||||
findAll(): Promise<T[]>; | ||||||
create(payload: unknown): Promise<T>; | ||||||
update(): Promise<T>; | ||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
type Service<T = unknown> = { | ||
find(): Promise<T>; | ||
find(userId: number): Promise<T | null>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same here |
||
findAll(): Promise<{ | ||
items: T[]; | ||
}>; | ||
|
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, I thought I deleted that already