-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #11 from FoxMalder-coder/module8-task1
- Loading branch information
Showing
54 changed files
with
494 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { TokenPayload } from './src/shared/modules/auth/index.js'; | ||
|
||
declare module 'express-serve-static-core' { | ||
export interface Request { | ||
tokenPayload: TokenPayload; | ||
} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { createSecretKey } from 'node:crypto'; | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { StatusCodes } from 'http-status-codes'; | ||
import { jwtVerify } from 'jose'; | ||
import { TokenPayload } from '../../../modules/auth/index.js'; | ||
import { HttpError } from '../http-error.js'; | ||
import { Middleware } from './middleware.interface.js'; | ||
|
||
function isTokenPayload(payload: unknown): payload is TokenPayload { | ||
return ( | ||
(typeof payload === 'object' && payload !== null) && | ||
('email' in payload && typeof payload.email === 'string') && | ||
('id' in payload && typeof payload.id === 'string') | ||
); | ||
} | ||
|
||
export class ParseTokenMiddleware implements Middleware { | ||
constructor(private readonly jwtSecret: string) { } | ||
|
||
public async execute(req: Request, _res: Response, next: NextFunction): Promise<void> { | ||
const authorizationHeader = req.headers?.authorization?.split(' '); | ||
if (!authorizationHeader) { | ||
return next(); | ||
} | ||
|
||
const [, token] = authorizationHeader; | ||
|
||
try { | ||
const { payload } = await jwtVerify(token, createSecretKey(this.jwtSecret, 'utf-8')); | ||
|
||
if (isTokenPayload(payload)) { | ||
req.tokenPayload = { ...payload }; | ||
return next(); | ||
} else { | ||
throw new Error('Bad token'); | ||
} | ||
} catch { | ||
|
||
return next(new HttpError( | ||
StatusCodes.UNAUTHORIZED, | ||
'Invalid token', | ||
'AuthenticateMiddleware') | ||
); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
src/shared/libs/rest/middleware/private-route.middleware.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { Middleware } from './middleware.interface.js'; | ||
import { HttpError } from '../index.js'; | ||
import { StatusCodes } from 'http-status-codes'; | ||
|
||
export class PrivateRouteMiddleware implements Middleware { | ||
public async execute({ tokenPayload }: Request, _res: Response, next: NextFunction): Promise<void> { | ||
if (!tokenPayload) { | ||
throw new HttpError( | ||
StatusCodes.UNAUTHORIZED, | ||
'Unauthorized', | ||
'PrivateRouteMiddleware' | ||
); | ||
} | ||
|
||
return next(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import { Request, Response, NextFunction } from 'express'; | ||
import { injectable, inject } from 'inversify'; | ||
import { Component } from '../../const.js'; | ||
import { Logger } from '../../libs/logger/logger.interface.js'; | ||
import { ExceptionFilter } from '../../libs/rest/index.js'; | ||
import { BaseUserException } from './errors/base-user.exception.js'; | ||
|
||
@injectable() | ||
export class AuthExceptionFilter implements ExceptionFilter { | ||
constructor( | ||
@inject(Component.Logger) private readonly logger: Logger | ||
) { | ||
this.logger.info('Register AuthExceptionFilter'); | ||
} | ||
|
||
public catch(error: unknown, _req: Request, res: Response, next: NextFunction): void { | ||
if (!(error instanceof BaseUserException)) { | ||
return next(error); | ||
} | ||
|
||
this.logger.error(`[AuthModule] ${error.message}`, error); | ||
res.status(error.httpStatusCode) | ||
.json({ type: 'AUTHORIZATION', error: error.message }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { LoginUserDto, UserEntity } from '../user/index.js'; | ||
|
||
export interface AuthService { | ||
authenticate(user: UserEntity): Promise<string>; | ||
verify(dto: LoginUserDto): Promise<UserEntity>; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export const JWT_ALGORITHM = 'HS256'; | ||
export const JWT_EXPIRED = '2d'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { Container } from 'inversify'; | ||
import { Component } from '../../const.js'; | ||
import { ExceptionFilter } from '../../libs/rest/index.js'; | ||
import { AuthExceptionFilter } from './auth-exception-filter.js'; | ||
import { AuthService } from './auth-service.interface.js'; | ||
import { DefaultAuthService } from './default-auth.service.js'; | ||
|
||
export function createAuthContainer() { | ||
const authContainer = new Container(); | ||
authContainer.bind<AuthService>(Component.AuthService).to(DefaultAuthService).inSingletonScope(); | ||
authContainer.bind<ExceptionFilter>(Component.AuthExceptionFilter).to(AuthExceptionFilter).inSingletonScope(); | ||
|
||
return authContainer; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import { inject, injectable } from 'inversify'; | ||
import * as crypto from 'node:crypto'; | ||
import { Component } from '../../const.js'; | ||
import { Logger } from '../../libs/logger/logger.interface.js'; | ||
import { Config } from 'convict'; | ||
import { SignJWT } from 'jose'; | ||
import { RestSchema } from '../../libs/config/rest.schema.js'; | ||
import { LoginUserDto } from '../user/index.js'; | ||
import { UserService } from '../user/user-service.interface.js'; | ||
import { UserEntity } from '../user/user.entity.js'; | ||
import { AuthService } from './auth-service.interface.js'; | ||
import { JWT_ALGORITHM, JWT_EXPIRED } from './auth.constant.js'; | ||
import { TokenPayload } from './types/token-payload.type.js'; | ||
import { UserNotFoundException } from './errors/user-not-found.exception.js'; | ||
import { UserPasswordIncorrectException } from './errors/user-password-incorrect.exception.js'; | ||
|
||
@injectable() | ||
export class DefaultAuthService implements AuthService { | ||
constructor( | ||
@inject(Component.Logger) private readonly logger: Logger, | ||
@inject(Component.UserService) private readonly userService: UserService, | ||
@inject(Component.Config) private readonly config: Config<RestSchema>, | ||
) { } | ||
|
||
public async authenticate(user: UserEntity): Promise<string> { | ||
const jwtSecret = this.config.get('JWT_SECRET'); | ||
const secretKey = crypto.createSecretKey(jwtSecret, 'utf-8'); | ||
const tokenPayload: TokenPayload = { | ||
email: user.email, | ||
id: user.id, | ||
}; | ||
|
||
this.logger.info(`Create token for ${user.email}`); | ||
return new SignJWT(tokenPayload) | ||
.setProtectedHeader({ alg: JWT_ALGORITHM }) | ||
.setIssuedAt() | ||
.setExpirationTime(JWT_EXPIRED) | ||
.sign(secretKey); | ||
} | ||
|
||
public async verify(dto: LoginUserDto): Promise<UserEntity> { | ||
const user = await this.userService.findByEmail(dto.email); | ||
if (!user) { | ||
this.logger.warn(`User with ${dto.email} not found`); | ||
throw new UserNotFoundException(); | ||
} | ||
|
||
if (!user.verifyPassword(dto.password, this.config.get('SALT'))) { | ||
this.logger.warn(`Incorrect password for ${dto.email}`); | ||
throw new UserPasswordIncorrectException(); | ||
} | ||
|
||
return user; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { HttpError } from '../../../libs/rest/index.js'; | ||
|
||
export class BaseUserException extends HttpError { | ||
constructor(httpStatusCode: number, message: string) { | ||
super(httpStatusCode, message); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { StatusCodes } from 'http-status-codes'; | ||
import { BaseUserException } from './base-user.exception.js'; | ||
|
||
export class UserNotFoundException extends BaseUserException { | ||
constructor() { | ||
super(StatusCodes.NOT_FOUND, 'User not found'); | ||
} | ||
} |
8 changes: 8 additions & 0 deletions
8
src/shared/modules/auth/errors/user-password-incorrect.exception.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { StatusCodes } from 'http-status-codes'; | ||
import { BaseUserException } from './base-user.exception.js'; | ||
|
||
export class UserPasswordIncorrectException extends BaseUserException { | ||
constructor() { | ||
super(StatusCodes.UNAUTHORIZED, 'Incorrect user name or password'); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export { AuthService } from './auth-service.interface.js'; | ||
export { TokenPayload } from './types/token-payload.type.js'; | ||
export { DefaultAuthService } from './default-auth.service.js'; | ||
export { BaseUserException } from './errors/base-user.exception.js'; | ||
export { UserNotFoundException } from './errors/user-not-found.exception.js'; | ||
export { UserPasswordIncorrectException } from './errors/user-password-incorrect.exception.js'; | ||
export { createAuthContainer } from './auth.container.js'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export type TokenPayload = { | ||
email: string; | ||
id: string; | ||
}; |
File renamed without changes.
File renamed without changes.
Oops, something went wrong.