From 83c5f3228aff6d585f377a984a7e1e3315784123 Mon Sep 17 00:00:00 2001 From: FORESTIER Fabien <fabien.forestier@soprasteria.com> Date: Mon, 17 Jun 2019 14:15:47 +0200 Subject: [PATCH] Update logging system, simplify var env export for local deployment, update README file --- README.md | 78 +++--- docker-compose.yml | 5 + favicon.ico | Bin 4286 -> 32038 bytes package.json | 4 +- src/app-logger.ts | 19 ++ src/app.module.ts | 4 + src/configuration/config.service.ts | 17 +- src/configuration/config.ts | 10 +- src/configuration/template.env | 8 - src/legacy/encryptionHelpers.ts | 5 +- src/legacy/legacy.controller.ts | 88 ++----- src/legacy/legacy.service.ts | 245 ++++++++++++------ src/main.ts | 7 +- .../decode-jwt-payload.middleware.ts | 11 +- template.env | 11 + 15 files changed, 286 insertions(+), 226 deletions(-) create mode 100644 src/app-logger.ts delete mode 100644 src/configuration/template.env create mode 100644 template.env diff --git a/README.md b/README.md index b73cc61..83a4338 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,23 @@ -<p align="center"> - <a href="http://nestjs.com/" target="blank"><img src="https://nestjs.com/img/logo_text.svg" width="320" alt="Nest Logo" /></a> -</p> - -[travis-image]: https://api.travis-ci.org/nestjs/nest.svg?branch=master -[travis-url]: https://travis-ci.org/nestjs/nest -[linux-image]: https://img.shields.io/travis/nestjs/nest/master.svg?label=linux -[linux-url]: https://travis-ci.org/nestjs/nest - - <p align="center">A progressive <a href="http://nodejs.org" target="blank">Node.js</a> framework for building efficient and scalable server-side applications, heavily inspired by <a href="https://angular.io" target="blank">Angular</a>.</p> - <p align="center"> -<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/v/@nestjs/core.svg" alt="NPM Version" /></a> -<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/l/@nestjs/core.svg" alt="Package License" /></a> -<a href="https://www.npmjs.com/~nestjscore"><img src="https://img.shields.io/npm/dm/@nestjs/core.svg" alt="NPM Downloads" /></a> -<a href="https://travis-ci.org/nestjs/nest"><img src="https://api.travis-ci.org/nestjs/nest.svg?branch=master" alt="Travis" /></a> -<a href="https://travis-ci.org/nestjs/nest"><img src="https://img.shields.io/travis/nestjs/nest/master.svg?label=linux" alt="Linux" /></a> -<a href="https://coveralls.io/github/nestjs/nest?branch=master"><img src="https://coveralls.io/repos/github/nestjs/nest/badge.svg?branch=master#5" alt="Coverage" /></a> -<a href="https://gitter.im/nestjs/nestjs?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge"><img src="https://badges.gitter.im/nestjs/nestjs.svg" alt="Gitter" /></a> -<a href="https://opencollective.com/nest#backer"><img src="https://opencollective.com/nest/backers/badge.svg" alt="Backers on Open Collective" /></a> -<a href="https://opencollective.com/nest#sponsor"><img src="https://opencollective.com/nest/sponsors/badge.svg" alt="Sponsors on Open Collective" /></a> - <a href="https://paypal.me/kamilmysliwiec"><img src="https://img.shields.io/badge/Donate-PayPal-dc3d53.svg"/></a> - <a href="https://twitter.com/nestframework"><img src="https://img.shields.io/twitter/follow/nestframework.svg?style=social&label=Follow"></a> -</p> - <!--[](https://opencollective.com/nest#backer) - [](https://opencollective.com/nest#sponsor)--> - -## Description - -[Nest](https://github.com/nestjs/nest) framework TypeScript starter repository. - ## Installation ```bash $ npm install ``` -## Running the app +## Environment variables + +In order to run the code, some environment variables are needed. They are specified in the `template.env` file at the root of the project. + +For a local deployment: + +1. `cp template.env .env` +2. Edit .env according to the chosen configuration + +The values will be read from the file by default, but you can override any of those by exporting manually the variable before launching the service. + +## Running the app without docker + +You will need to provide a healthy connection to a database in order for the service to start. ```bash # development @@ -43,15 +26,24 @@ $ npm run start # watch mode $ npm run start:dev -# incremental rebuild (webpack) -$ npm run webpack -$ npm run start:hmr - # production mode $ npm run start:prod ``` -## Test +## Running the app with docker + +```bash +# build +$ docker-compose build + +# deploy +$ docker-compose up [-d] + +# build and deploy +$ docker-compose up --build [-d] +``` + +<!-- ## Test ```bash # unit tests @@ -62,18 +54,6 @@ $ npm run test:e2e # test coverage $ npm run test:cov -``` - -## Support - -Nest is an MIT-licensed open source project. It can grow thanks to the sponsors and support by the amazing backers. If you'd like to join them, please [read more here](https://docs.nestjs.com/support). - -## Stay in touch - -- Author - [Kamil Myśliwiec](https://kamilmysliwiec.com) -- Website - [https://nestjs.com](https://nestjs.com/) -- Twitter - [@nestframework](https://twitter.com/nestframework) +``` --> -## License - Nest is [MIT licensed](LICENSE). diff --git a/docker-compose.yml b/docker-compose.yml index 14a9dec..be4435a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -13,8 +13,13 @@ services: - SERVICE_EMAIL_URL=${SERVICE_EMAIL_URL} - USER_SUPPORT_MAILBOX=${USER_SUPPORT_MAILBOX} - FRONT_END_URL=${FRONT_END_URL} + - VALIDATE_ACCOUNT_URI=login + - PASSWORD_RESET_URI=reinitialiser-mon-mot-de-passe - API_KEY=${API_KEY} - ACCESS_TOKEN_COOKIE_KEY=${ACCESS_TOKEN_COOKIE_KEY} + - IMAGE_HOST=https://minio.alpha.grandlyon.com/email-template-assets + - REDIS_HOST=redis + - REDIS_PORT=6379 restart: unless-stopped depends_on: - redis diff --git a/favicon.ico b/favicon.ico index c5ead77ef7e55ad35e680fb70ce37554e4415521..e2c6f06d1073863153b63a50f6191e7c5e03daf2 100644 GIT binary patch literal 32038 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 a9mD)XtUpLqPprAbs)L*sFiMWp5C8yDU&ERJ literal 4286 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 G5(5ArT%%h6 diff --git a/package.json b/package.json index 6826679..c770a7f 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "legacy-auth-middleware", - "version": "3.2.0", - "description": "description", + "version": "3.2.1", + "description": "", "author": "", "license": "MIT", "scripts": { diff --git a/src/app-logger.ts b/src/app-logger.ts new file mode 100644 index 0000000..5c9db3a --- /dev/null +++ b/src/app-logger.ts @@ -0,0 +1,19 @@ +import { Logger } from '@nestjs/common'; + +export class AppLogger extends Logger { + log(message: string, context?: string) { + // add your tailored logic here + super.log(`[log] ${message}`, context); + } + + warn(message: string, context?: string) { + // add your tailored logic here + super.warn(`[warn] ${message}`, context); + } + + error(message: string, trace?: string, context?: string) { + // add your tailored logic here + super.error(`[error] ${message}`, trace, context); + } + +} \ No newline at end of file diff --git a/src/app.module.ts b/src/app.module.ts index 4c565ba..09261fa 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -3,6 +3,7 @@ import { LegacyModule } from './legacy/legacy.module'; import { ConfigModule } from './configuration/config.module'; import { VerifyXsrfTokenAndDecodeJWTPayloadMiddleware } from './middlewares/decode-jwt-payload.middleware'; import { HealthModule } from './health/health.module'; +import { AppLogger } from './app-logger'; @Module({ imports: [ @@ -10,6 +11,9 @@ import { HealthModule } from './health/health.module'; HealthModule, LegacyModule, ], + providers: [ + AppLogger, + ] }) export class AppModule { configure(consumer: MiddlewareConsumer) { diff --git a/src/configuration/config.service.ts b/src/configuration/config.service.ts index a0a4571..2b0f608 100644 --- a/src/configuration/config.service.ts +++ b/src/configuration/config.service.ts @@ -8,16 +8,6 @@ export class ConfigService { private _config = Config; constructor() { - // Only for development purpose, set environment variable based on the env file provided - if (process.env.NODE_ENV === 'LOCAL') { - const envConfig = dotenv.parse(fs.readFileSync(`./src/configuration/${process.env.NODE_ENV}.env`)); - for (const k in envConfig) { - if (envConfig.hasOwnProperty(k)) { - process.env[k] = envConfig[k]; - } - } - } - this._config.legacyAuthServiceUrl = process.env.LEGACY_AUTH_SERVICE_URL; this._config.adminPassword = process.env.ADMIN_PASSWORD; this._config.adminUsername = process.env.ADMIN_USERNAME; @@ -26,6 +16,11 @@ export class ConfigService { this._config.frontEnd.url = process.env.FRONT_END_URL; this._config.apiKey = process.env.API_KEY; this._config.accessTokenCookieKey = process.env.ACCESS_TOKEN_COOKIE_KEY; + this._config.imageHost = process.env.IMAGE_HOST; + this._config.redis.host = process.env.REDIS_HOST; + this._config.redis.port = process.env.REDIS_PORT; + this._config.frontEnd.validateAccountUri = process.env.VALIDATE_ACCOUNT_URI; + this._config.frontEnd.passwordResetUri = process.env.PASSWORD_RESET_URI; this.initilizePublicPrivateKeys(); } @@ -35,7 +30,7 @@ export class ConfigService { } initilizePublicPrivateKeys() { - const key = new NodeRSA({b: 2048}); + const key = new NodeRSA({ b: 2048 }); this._config.publicKey = key.exportKey('public'); this._config.privateKey = key.exportKey('private'); diff --git a/src/configuration/config.ts b/src/configuration/config.ts index d53d73e..e411ad0 100644 --- a/src/configuration/config.ts +++ b/src/configuration/config.ts @@ -9,15 +9,15 @@ export const Config = { accountCreationTokenTTL: 86400, // Time to live of the token used to validate the cration of an account in second (24h) frontEnd: { url: '', - validateAccountUri: 'login', - passwordResetUri: 'reinitialiser-mon-mot-de-passe', + validateAccountUri: '', + passwordResetUri: '', }, resetPasswordSessionTtl: 86400, // 24 hours redis: { - port: 6379, - host: 'redis', + port: null, + host: '', }, - imageHost: 'https://highway-to-data.alpha.grandlyon.com/email-template-assets', + imageHost: '', apiKey: '', accessTokenCookieKey: '', }; \ No newline at end of file diff --git a/src/configuration/template.env b/src/configuration/template.env deleted file mode 100644 index 50009a4..0000000 --- a/src/configuration/template.env +++ /dev/null @@ -1,8 +0,0 @@ -LEGACY_AUTH_SERVICE_URL= -ADMIN_PASSWORD= -ADMIN_USERNAME= -SERVICE_EMAIL_URL= -USER_SUPPORT_MAILBOX= -FRONT_END_URL= -API_KEY= -ACCESS_TOKEN_COOKIE_KEY= diff --git a/src/legacy/encryptionHelpers.ts b/src/legacy/encryptionHelpers.ts index 61e6378..83f3092 100644 --- a/src/legacy/encryptionHelpers.ts +++ b/src/legacy/encryptionHelpers.ts @@ -1,4 +1,4 @@ -import { UnauthorizedException, InternalServerErrorException, BadRequestException, Logger } from '@nestjs/common'; +import { UnauthorizedException, BadRequestException, Logger } from '@nestjs/common'; import * as NodeRSA from 'node-rsa'; export const decrypt = (encrypted: string, privateKey) => { @@ -8,7 +8,8 @@ export const decrypt = (encrypted: string, privateKey) => { const decrypted = key.decrypt(encrypted, 'utf8'); return decrypted; } catch (error) { - Logger.error(error); + const logger = new Logger(); + logger.error('Couldn\'t decrypt password', error, 'Decrypt password'); throw new UnauthorizedException('Couldn\'t decrypt password'); } } else { diff --git a/src/legacy/legacy.controller.ts b/src/legacy/legacy.controller.ts index 61b785c..dcba32c 100644 --- a/src/legacy/legacy.controller.ts +++ b/src/legacy/legacy.controller.ts @@ -1,10 +1,14 @@ -import { Controller, Post, Body, Logger, HttpException, InternalServerErrorException, - HttpCode, Get, Req, Delete, Put, Query } from '@nestjs/common'; +import { + Controller, Post, Body, HttpException, InternalServerErrorException, + HttpCode, Get, Req, Delete, Put, Query +} from '@nestjs/common'; import { LegacyService } from './legacy.service'; import { ApiOperation, ApiResponse, ApiUseTags, ApiImplicitHeader, ApiImplicitBody } from '@nestjs/swagger'; -import { LoginForm, UserCreationForm, UserInfoWithEcryptedPassword, JWTToken, Service, Resource, RestrictedAccessDataset, - AccessRequest, UpdatePasswordForm, UserUpdateForm, UserInfo, AccessDeletionResponse, - AccessRequestResponse, AccessRenewalResponse, UserAccountValidationRequest, PasswordResetForm, PasswordForgottenForm} from './legacy.model'; +import { + LoginForm, UserCreationForm, UserInfoWithEcryptedPassword, JWTToken, Service, Resource, RestrictedAccessDataset, + AccessRequest, UpdatePasswordForm, UserUpdateForm, UserInfo, AccessDeletionResponse, + AccessRequestResponse, AccessRenewalResponse, UserAccountValidationRequest, PasswordResetForm, PasswordForgottenForm +} from './legacy.model'; import { handleError } from './errorHandlingHelper'; @ApiUseTags('legacy') @@ -21,17 +25,15 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiResponse({ status: 200, description: 'User is existing, returning its info', type: UserInfo }) @ApiResponse({ status: 400, description: 'Bad Request' }) @ApiResponse({ status: 500, description: 'Internal error' }) async getUserInfo(@Req() req) { - Logger.log('[-] get user info endpoint'); const token: JWTToken = req.headers.token; try { return await this.legacyService.getUserInfo(token.username, token.authzKey); } catch (error) { - Logger.error(`[x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -47,12 +49,9 @@ export class LegacyController { @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(201) async createUser(@Body() userCreationForm: UserCreationForm) { - Logger.log('[-] Add user endpoint'); - try { return await this.legacyService.createUser(userCreationForm); } catch (error) { - Logger.error(`[x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -68,12 +67,9 @@ export class LegacyController { @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(201) async validateAccount(@Body() body: UserAccountValidationRequest) { - Logger.log('[-] Validate user account endpoint'); - try { return await this.legacyService.validateUserAccount(body.token); } catch (error) { - Logger.error(`[x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -88,12 +84,10 @@ export class LegacyController { @ApiResponse({ status: 400, description: 'Bad Request (user not found)' }) @ApiResponse({ status: 500, description: 'Internal error' }) async login(@Body() loginForm: LoginForm): Promise<UserInfoWithEcryptedPassword> { - Logger.log('[-] user login endpoint'); try { const userInfo = await this.legacyService.getUser(loginForm); return userInfo; } catch (error) { - Logger.error(` [x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -108,19 +102,16 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiResponse({ status: 204, description: 'Account deleted' }) @ApiResponse({ status: 400, description: 'Bad Request (Invalid user credentials.)' }) @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(204) async deleteUserAccount(@Req() req) { - Logger.log('[-] DELETE user endpoint'); const token: JWTToken = req.headers.token; try { return await this.legacyService.deleteUserAccount(token); } catch (error) { - Logger.error(`[x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -135,18 +126,16 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiResponse({ status: 200, description: 'Success' }) @ApiResponse({ status: 400, description: 'Bad Request (user not found, password incorrect)' }) @ApiResponse({ status: 500, description: 'Internal error' }) async updatePässword(@Req() req, @Body() updatePasswordForm: UpdatePasswordForm): Promise<void> { - Logger.log('[-] update user password endpoint'); const token: JWTToken = req.headers.token; try { const res = await this.legacyService.updateUserPassword(token.username, updatePasswordForm); return res; } catch (error) { - Logger.error(` [x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -161,12 +150,11 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiResponse({ status: 200, description: 'Success', type: UserInfo }) @ApiResponse({ status: 400, description: 'Bad Request (user not found, password incorrect)' }) @ApiResponse({ status: 500, description: 'Internal error' }) async updateUserInfo(@Req() req, @Body() userUpdateForm: UserUpdateForm): Promise<UserInfoWithEcryptedPassword> { - Logger.log('[-] update user password endpoint'); const token: JWTToken = req.headers.token; try { await this.legacyService.updateUserInfo(token, userUpdateForm); @@ -176,7 +164,6 @@ export class LegacyController { }); return userInfo; } catch (error) { - Logger.error(` [x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -187,9 +174,9 @@ export class LegacyController { @Put('user/resetPassword') @ApiOperation({ title: 'Replace user password with the one provided (user is identified with the email associated to the token provided)' }) - @ApiResponse({ status: 200, description: 'Password updated'}) - @ApiResponse({ status: 400, description: 'Bad request'}) - @ApiResponse({ status: 500, description: 'Internal error'}) + @ApiResponse({ status: 200, description: 'Password updated' }) + @ApiResponse({ status: 400, description: 'Bad request' }) + @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(200) async resetPassword(@Body() body: PasswordResetForm): Promise<void> { try { @@ -200,10 +187,10 @@ export class LegacyController { } @Get('/isPasswordResetTokenValid') - @ApiOperation({ title: 'Verify the validity of the password reset token'}) - @ApiResponse({ status: 200, description: 'Returns the validity status of the token' , type: Boolean }) - @ApiResponse({ status: 400, description: 'Bad request'}) - @ApiResponse({ status: 500, description: 'Internal error'}) + @ApiOperation({ title: 'Verify the validity of the password reset token' }) + @ApiResponse({ status: 200, description: 'Returns the validity status of the token', type: Boolean }) + @ApiResponse({ status: 400, description: 'Bad request' }) + @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(200) async isPasswordResetTokenValid(@Query('token') token: string): Promise<boolean> { try { @@ -215,9 +202,9 @@ export class LegacyController { @Post('/passwordForgotten') @ApiOperation({ title: 'Launch the password forgotten procedure' }) - @ApiResponse({ status: 200, description: 'Procedure launched'}) - @ApiResponse({ status: 400, description: 'Bad request'}) - @ApiResponse({ status: 500, description: 'Internal error'}) + @ApiResponse({ status: 200, description: 'Procedure launched' }) + @ApiResponse({ status: 400, description: 'Bad request' }) + @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(200) async passwordForgotten(@Body() body: PasswordForgottenForm): Promise<void> { try { @@ -234,19 +221,16 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiResponse({ status: 200, description: 'Success, returns accessible resources', type: [Resource] }) - @ApiResponse({ status: 401, description: 'Authorization is not set, not a valid token, or user credentials are not correct'}) + @ApiResponse({ status: 401, description: 'Authorization is not set, not a valid token, or user credentials are not correct' }) @ApiResponse({ status: 500, description: 'Internal error' }) async getUserResources(@Req() req): Promise<Resource[]> { const token: JWTToken = req.headers.token; - Logger.log('[-] user/resources endpoint'); try { const userServices = await this.legacyService.getUserResources(token.username, token.authzKey); return userServices; } catch (error) { - Logger.error(` [x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -261,20 +245,17 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiImplicitBody({ name: 'body', type: AccessRequest, isArray: true }) @ApiResponse({ status: 201, description: 'Request created', type: AccessRequestResponse }) @ApiResponse({ status: 400, description: 'Bad Request (Mode does not exist)' }) @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(201) async addUserResource(@Req() req, @Body() body) { - Logger.log('[-] user/resources/add endpoint'); const token: JWTToken = req.headers.token; try { return await this.legacyService.addUserResource(token, body); } catch (error) { - Logger.error(`[x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -289,20 +270,17 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiImplicitBody({ name: 'body', type: AccessRequest, isArray: true }) @ApiResponse({ status: 201, description: 'Request created', type: AccessRenewalResponse }) @ApiResponse({ status: 400, description: 'Bad Request (Mode does not exist)' }) @ApiResponse({ status: 500, description: 'Internal error' }) @HttpCode(201) async renewUserResource(@Req() req, @Body() body: AccessRequest[]) { - Logger.log('[-] user/resources/renew endpoint'); const token: JWTToken = req.headers.token; try { return await this.legacyService.renewUserResource(token, body); } catch (error) { - Logger.error(`[x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -317,18 +295,15 @@ export class LegacyController { name: 'Cookie', description: 'The JWT token is sent by the browser as a cookie (refer to the config of the Authentication project to know which key is used)', }) - @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token'}) + @ApiImplicitHeader({ name: 'x-xsrf-token', description: 'Xsrf Token' }) @ApiImplicitBody({ name: 'body', type: AccessRequest, isArray: true }) @ApiResponse({ status: 200, description: 'Access removed', type: AccessDeletionResponse }) @ApiResponse({ status: 500, description: 'Internal error' }) async deleteUserResource(@Req() req, @Body() body) { - Logger.log('[-] user/resources/delete endpoint'); const token: JWTToken = req.headers.token; try { return await this.legacyService.deleteUserResource(token, body); } catch (error) { - Logger.error(`[x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -342,11 +317,9 @@ export class LegacyController { @ApiResponse({ status: 200, description: 'OK', type: [Service] }) @ApiResponse({ status: 500, description: 'Internal error' }) async getServices(): Promise<Service[]> { - Logger.log('[-] Services list endpoint'); try { return await this.legacyService.getServices(); } catch (error) { - Logger.error(`[x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { @@ -360,12 +333,9 @@ export class LegacyController { @ApiResponse({ status: 200, description: 'OK', type: [RestrictedAccessDataset] }) @ApiResponse({ status: 500, description: 'Internal error' }) async getRestrictedAccessDatasets(): Promise<RestrictedAccessDataset[]> { - Logger.log('[-] Restricted Access Dataset list endpoint'); try { return await this.legacyService.getRestrictedAccessDatasets(); } catch (error) { - Logger.error(`[x] Error in controller:`); - Logger.error(error); if (error instanceof HttpException) { throw error; } else { @@ -379,11 +349,9 @@ export class LegacyController { @ApiResponse({ status: 200, description: 'Return the public key' }) @ApiResponse({ status: 500, description: 'Internal error' }) getPublicKey() { - Logger.log('[-] getPublicKey'); try { return this.legacyService.getPublicKey(); } catch (error) { - Logger.error(` [x] Error in controller: ${error}`); if (error instanceof HttpException) { throw error; } else { diff --git a/src/legacy/legacy.service.ts b/src/legacy/legacy.service.ts index 1188b3b..471f48d 100644 --- a/src/legacy/legacy.service.ts +++ b/src/legacy/legacy.service.ts @@ -26,28 +26,38 @@ moment.tz.setDefault('Europe/Paris'); @Injectable() export class LegacyService { conf: any; + private logger: Logger; constructor( private configService: ConfigService, ) { this.conf = this.configService.config; + this.logger = new Logger(LegacyService.name); } async getUser(loginForm: LoginForm): Promise<UserInfoWithEcryptedPassword> { - Logger.log(`[-] Get User method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.getUser.name}`); try { const decryptedPassword = decrypt(loginForm.password, this.conf.privateKey); - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form({ username: loginForm.username, password: decryptedPassword }); + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form( + { + username: loginForm.username, + password: decryptedPassword, + } + ).catch((error) => { + this.logger.error('Couldn\'t get the user', error, `${LegacyService.name} - ${this.getUser.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get the user.' }); + }); + res = JSON.parse(res); if (res.server_response && res.server_response === 'Success') { const userInfo = new UserInfoWithEcryptedPassword(res.user, loginForm.password); return userInfo; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t get the user', res.message, `${LegacyService.name} - ${this.getUser.name}`); throw new BadRequestException(res.message); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -57,20 +67,28 @@ export class LegacyService { } async getUserInfo(username: string, encryptedPassword: string): Promise<UserInfo> { - Logger.log(`[-] Get User method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.getUserInfo.name}`); try { const password = decrypt(encryptedPassword, this.conf.privateKey); - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form({ username, password }); + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form( + { + username, + password, + }).catch((error) => { + this.logger.error('Couldn\'t get the user info', error, `${LegacyService.name} - ${this.getUserInfo.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get the user info.' }); + }); + res = JSON.parse(res); + if (res.server_response && res.server_response === 'Success') { const userInfo = new UserInfo(res.user); return userInfo; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t get the user info', res.message, `${LegacyService.name} - ${this.getUserInfo.name}`); throw new BadRequestException(res.message); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -80,11 +98,21 @@ export class LegacyService { } async updateUserPassword(username: string, updatePasswordForm: UpdatePasswordForm): Promise<void> { - Logger.log(`[-] Update User method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.updateUserPassword.name}`); try { const decryptedOldPassword = decrypt(updatePasswordForm.oldPassword, this.conf.privateKey); - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form({ username, password: decryptedOldPassword }); + + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user/`).form( + { + username, + password: decryptedOldPassword, + }).catch((error) => { + this.logger.error('Couldn\'t get user.', error, `${LegacyService.name} - ${this.updateUserPassword.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get user.' }); + }); + res = JSON.parse(res); + if (res.server_response && res.server_response === 'Success') { const decryptedNewPassword = decrypt(updatePasswordForm.newPassword, this.conf.privateKey); res = await request.post(`${this.conf.legacyAuthServiceUrl}/update_user_password/`).form({ @@ -92,16 +120,21 @@ export class LegacyService { password: decryptedNewPassword, admin_username: this.conf.adminUsername, admin_password: this.conf.adminPassword, + }).catch((error) => { + this.logger.error('Couldn\'t update user password.', error, `${LegacyService.name} - ${this.updateUserPassword.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t update user password.' }); }); + res = JSON.parse(res); + if (res.server_response && res.server_response === 'Success') { return; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t update user password.', res.message, `${LegacyService.name} - ${this.updateUserPassword.name}`); throw new BadRequestException(res.message); } } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t update user password.', res.message, `${LegacyService.name} - ${this.updateUserPassword.name}`); if (res.message === 'Unidentified user') { throw new BadRequestException('unidentifiedUser'); } else { @@ -109,7 +142,6 @@ export class LegacyService { } } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -119,14 +151,13 @@ export class LegacyService { } async createUser(form: UserCreationForm): Promise<void> { - Logger.log(`[-] createUser method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.createUser.name}`); try { // form.password = decrypt(form.password, this.conf.privateKey); const legacyForm = new LegacyUserCreationForm(form); // Generate a unique random token const accountCreationToken = uuid4(); - Logger.log('Reset password token:', accountCreationToken); // Set a redis key/value, this allow to open a 24h session with the token as key that will let us identify the email associated to the token await this.setRedisKeyValue(accountCreationToken, JSON.stringify(legacyForm), this.conf.accountCreationTokenTTL); @@ -158,7 +189,7 @@ export class LegacyService { } async validateUserAccount(token: string): Promise<void> { - Logger.log(`[-] ValidUserAccount method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.validateUserAccount.name}`); try { @@ -168,18 +199,23 @@ export class LegacyService { userInfo.password = decrypt(userInfo.password, this.conf.privateKey); if (userInfo) { - Logger.log(`User account validation for : ${userInfo.email}`); + Logger.log(`User account validation for : ${userInfo.email}`, `${LegacyService.name} - ${this.validateUserAccount.name}`); + + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/add_user/`).form(userInfo).catch((error) => { + this.logger.error('Couldn\'t create user.', error, `${LegacyService.name} - ${this.validateUserAccount.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t create user.' }); + }); - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/add_user/`).form(userInfo); res = JSON.parse(res); + if (res.server_response && res.server_response === 'Success') { - Logger.log(res); + Logger.log(`User account created.`, `${LegacyService.name} - ${this.validateUserAccount.name}`); // Deleting the key from redis when the account has successfully been created this.deleteRedisKey(token); return; } else { - Logger.error(` [x] Error: ${res}`); + this.logger.error('Couldn\'t create user.', res, `${LegacyService.name} - ${this.validateUserAccount.name}`); if (res.message === 'Error during account creation') { throw new InternalServerErrorException(res.message); } @@ -193,24 +229,30 @@ export class LegacyService { } } } else { + this.logger.warn('Token not found.', `${LegacyService.name} - ${this.validateUserAccount.name}`); throw new BadRequestException('tokenNotFound'); } } catch (err) { - Logger.error(err); handleError(err, new InternalServerErrorException('Something went wrong.')); } } async updateUserInfo(token: JWTToken, form: UserUpdateForm): Promise<void> { - Logger.log(`[-] update User method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.updateUserInfo.name}`); try { const legacyForm = new LegacyUserUpdateForm(form, token.username, decrypt(token.authzKey, this.conf.privateKey)); - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/update_user/`).form(legacyForm); + + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/update_user/`).form(legacyForm).catch((error) => { + this.logger.error('Couldn\'t update user info.', error, `${LegacyService.name} - ${this.updateUserInfo.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t update user info.' }); + }); + res = JSON.parse(res); + if (res.server_response && res.server_response === 'Success') { return; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t update user.', res.message, `${LegacyService.name} - ${this.updateUserInfo.name}`); if (res.message === 'Unidentified user') { throw new BadRequestException('unidentifiedUser'); } @@ -221,7 +263,6 @@ export class LegacyService { } } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -231,7 +272,7 @@ export class LegacyService { } async resetPassword(form: PasswordResetForm): Promise<void> { - Logger.log(`[-] resetPassword with params: ${form.token} and password...`); + this.logger.log(`Entering function with token ${form.token}`, `${LegacyService.name} - ${this.resetPassword.name}`); try { const username = await this.getRedisValueByKey(form.token); @@ -245,7 +286,10 @@ export class LegacyService { password: decryptedPassword, admin_username: this.conf.adminUsername, admin_password: this.conf.adminPassword, - }); + }).catch((error) => { + this.logger.error('Couldn\'t update user password.', error, `${LegacyService.name} - ${this.resetPassword.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t update user password.' }); + }); res = JSON.parse(res); @@ -254,41 +298,38 @@ export class LegacyService { await this.deleteRedisKey(form.token); return; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t update user password.', res.message, `${LegacyService.name} - ${this.resetPassword.name}`); throw new BadRequestException(res.message); } } else { + this.logger.warn('Invalid token.', `${LegacyService.name} - ${this.resetPassword.name}`); throw new BadRequestException('invalidToken'); } } catch (error) { - Logger.error(` [x] Failed to reset the password:`); - Logger.error(error); handleError(error, new InternalServerErrorException('Couldn\'t reset the password.')); } } async isPasswordResetTokenValid(token: string): Promise<boolean> { - Logger.log(`[-] isPasswordResetTokenValid with params: ${token}`); + this.logger.log(`Entering function with token ${token}`, `${LegacyService.name} - ${this.isPasswordResetTokenValid.name}`); try { const email = await this.getRedisValueByKey(token); - Logger.log(email); + + Logger.log(`Password reset token is valid for email: ${email}`, `${LegacyService.name} - ${this.isPasswordResetTokenValid.name}`); return email ? true : false; } catch (error) { - Logger.error(` [x] Failed to verify the validity of the passwordResetToken:`); - Logger.error(error); handleError(error, new InternalServerErrorException('Couldn\'t verify the validity of the password rest token.')); } } async passwordForgotten(form: PasswordForgottenForm): Promise<void> { - Logger.log('[-] passwordForgotten:'); + this.logger.log('Entering function', `${LegacyService.name} - ${this.passwordForgotten.name}`); try { // Generate a unique random token const resetPasswordToken = uuid4(); - Logger.log('Reset password token:', resetPasswordToken); // Set a redis key/value, this allow to open a 24h session with the token as key that will let us identify the email associated to the token await this.setRedisKeyValue(resetPasswordToken, form.email, this.conf.resetPasswordSessionTtl); @@ -310,16 +351,20 @@ export class LegacyService { return; } catch (error) { - Logger.error(' [x] error:', JSON.stringify(error)); handleError(error, new InternalServerErrorException()); } } async getServices(): Promise<Service[]> { - Logger.log(`[-] Get services method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.getServices.name}`); try { - let res = await request.get(`${this.conf.legacyAuthServiceUrl}/get_modes/`); + let res = await request.get(`${this.conf.legacyAuthServiceUrl}/get_modes/`).catch((error) => { + this.logger.error('Couldn\'t get the services list.', error, `${LegacyService.name} - ${this.getServices.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get the services list.' }); + }); + res = JSON.parse(res); + if (res.services) { const modes: Service[] = []; // Create a new object for each service @@ -328,10 +373,10 @@ export class LegacyService { }); return modes; } else { + this.logger.error('Couldn\'t get the services list.', res, `${LegacyService.name} - ${this.getServices.name}`); throw new InternalServerErrorException('Couldn\'t get the different modes'); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -341,7 +386,7 @@ export class LegacyService { } async getUserResources(username: string, password: string): Promise<Resource[]> { - Logger.log(`[-] Get User resources method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.getUserResources.name}`); try { // Decrypt the password password = decrypt(password, this.conf.privateKey); @@ -351,7 +396,10 @@ export class LegacyService { } // Get the list of the accessible services by the user - let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user_service/`).form({ username, password }); + let res = await request.post(`${this.conf.legacyAuthServiceUrl}/get_user_service/`).form({ username, password }).catch((error) => { + this.logger.error('Couldn\'t get the user`\'s services list.', error, `${LegacyService.name} - ${this.getUserResources.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get the user`\'s services list.' }); + }); res = JSON.parse(res); @@ -366,11 +414,10 @@ export class LegacyService { } return services; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t get the user`\'s services list.', res.message, `${LegacyService.name} - ${this.getUserResources.name}`); throw new BadRequestException(res.message); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -380,9 +427,13 @@ export class LegacyService { } async getRestrictedAccessDatasets(): Promise<RestrictedAccessDataset[]> { - Logger.log(`[-] Get Restricted Access dataset method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`); try { - let rawRestrictedService = await request.get(`${this.conf.legacyAuthServiceUrl}/get_services/`); + let rawRestrictedService = await request.get(`${this.conf.legacyAuthServiceUrl}/get_services/`).catch((error) => { + this.logger.error('Couldn\'t get the services list.', error, `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get the services list.' }); + }); + rawRestrictedService = JSON.parse(rawRestrictedService); const restrictedServices = []; @@ -395,10 +446,10 @@ export class LegacyService { return restrictedServices; } else { + this.logger.error('Couldn\'t get the different restricted services.', rawRestrictedService, `${LegacyService.name} - ${this.getRestrictedAccessDatasets.name}`); throw new InternalServerErrorException('Couldn\'t get the different restricted services.'); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -408,7 +459,7 @@ export class LegacyService { } async addUserResource(token: JWTToken, accessRequests: AccessRequest[]): Promise<AccessRequestResponse> { - Logger.log(`[-] add user resource method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.addUserResource.name}`); try { // Decrypt the password const password = decrypt(token.authzKey, this.conf.privateKey); @@ -434,7 +485,11 @@ export class LegacyService { username: token.username, service_id: accessRequest.id, modes: accessRequest.servicesId.toString(), - }); + } + ).catch((error) => { + this.logger.error('Couldn\'t request access to the resource.', error, `${LegacyService.name} - ${this.addUserResource.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t request access to the resource.' }); + }); res = JSON.parse(res); @@ -457,7 +512,7 @@ export class LegacyService { accessSuccessfullyRequested.push(`${dataset.datasetName} (${servicesName.toString()})`); } } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t request access to the resource.', res.message, `${LegacyService.name} - ${this.addUserResource.name}`); accessUnsuccessfullyRequested.push(`${dataset.datasetName} (${servicesName.toString()})`); } } @@ -497,7 +552,6 @@ export class LegacyService { return { successfullyRequested: accessSuccessfullyRequested, unsuccessfullyRequested: accessUnsuccessfullyRequested }; } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -507,12 +561,13 @@ export class LegacyService { } async renewUserResource(token: JWTToken, accessRequests: AccessRequest[]): Promise<AccessRenewalResponse> { - Logger.log(`[-] add user resource method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.renewUserResource.name}`); try { // Decrypt the password const password = decrypt(token.authzKey, this.conf.privateKey); if (!password) { + this.logger.warn('Invalid user credentials.', `${LegacyService.name} - ${this.renewUserResource.name}`); throw new UnauthorizedException('Invalid user credentials.'); } @@ -600,7 +655,6 @@ export class LegacyService { unsuccessfullyRenewalRequested: accessRenewalUnsuccessfullyRequested, }; } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -610,12 +664,13 @@ export class LegacyService { } async deleteUserResource(token: JWTToken, accessRequests: AccessRequest[]): Promise<AccessDeletionResponse> { - Logger.log(`[-] deleteUserResource method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.deleteUserResource.name}`); try { // Decrypt the password const password = decrypt(token.authzKey, this.conf.privateKey); if (!password) { + this.logger.warn('Invalid user credentials.', `${LegacyService.name} - ${this.deleteUserResource.name}`); throw new UnauthorizedException('Invalid user credentials.'); } @@ -637,7 +692,10 @@ export class LegacyService { service_id: accessRequest.id, modes: accessRequest.servicesId.toString(), }, - ); + ).catch((error) => { + this.logger.error('Couldn\'t remove access to the resource.', error, `${LegacyService.name} - ${this.deleteUserResource.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t remove access to the resource.' }); + }); res = JSON.parse(res); @@ -698,7 +756,6 @@ export class LegacyService { return { successfullyDeleted: datasetsSuccessfullyDeleted, unsuccessfullyDeleted: datasetsUnsuccessfullyDeleted }; } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -708,11 +765,12 @@ export class LegacyService { } async deleteUserAccount(token: JWTToken): Promise<void> { - Logger.log(`[-] deleteUserAccount method`); + this.logger.log('Entering function', `${LegacyService.name} - ${this.deleteUserAccount.name}`); try { // Decrypt the password const password = decrypt(token.authzKey, this.conf.privateKey); if (!password) { + this.logger.error('Invalid user credentials.', null, `${LegacyService.name} - ${this.deleteUserAccount.name}`); throw new UnauthorizedException('Invalid user credentials.'); } @@ -722,18 +780,20 @@ export class LegacyService { password, username: token.username, }, - ); + ).catch((error) => { + this.logger.error('Couldn\'t delete user account.', error, `${LegacyService.name} - ${this.deleteUserAccount.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t delete user account.' }); + }); res = JSON.parse(res); if (res.server_response && res.server_response === 'Success') { return; } else { - Logger.error(` [x] Error: ${res.message}`); + this.logger.error('Couldn\'t delete user account.', res.message, `${LegacyService.name} - ${this.deleteUserAccount.name}`); throw new BadRequestException(res.message); } } catch (err) { - Logger.error(err); if (err instanceof HttpException) { throw new HttpException(err.message, err.getStatus()); } else { @@ -743,9 +803,11 @@ export class LegacyService { } getPublicKey() { + this.logger.log(`Entering function`, `${LegacyService.name} - ${this.getPublicKey.name}`); if (this.conf.publicKey) { return { publicKey: this.conf.publicKey }; } else { + this.logger.error('Couldn\'t get the public key.', null, `${LegacyService.name} - ${this.getPublicKey.name}`); throw new InternalServerErrorException('Couldn\'t get the public key.'); } } @@ -753,69 +815,72 @@ export class LegacyService { /**** Redis methods ****/ private async setRedisKeyValue(key: string, value: string, ttl: number): Promise<any> { - Logger.log(`[-] setRedisKeyValue with params: ${key} ${value} ${ttl}`); + this.logger.log(`Entering function with params ${key} ${value} ${ttl}`, `${LegacyService.name} - ${this.setRedisKeyValue.name}`); const client = this.connectToRedis(); try { // Set key value with expiration time in seconds - const res = await client.setAsync(key, value, 'EX', ttl); - Logger.log(` [*] Setting key/pair result => ${res}`); + const res = await client.setAsync(key, value, 'EX', ttl).catch((error) => { + this.logger.error('Couldn\'t set redis key/value.', error, `${LegacyService.name} - ${this.setRedisKeyValue.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t set redis key/value.' }); + }); + + Logger.log(`Setting key/pair, result is: ${res}`, `${LegacyService.name} - ${this.setRedisKeyValue.name}`); client.quit(); return res; } catch (error) { - Logger.error(` [x] Setting key/pair error:`); - Logger.error(error); client.quit(); handleError(error, new InternalServerErrorException('Couldn\'t set key/value in redis.')); } } private async deleteRedisKey(key: string): Promise<any> { - Logger.log(`[-] deleteRedisKey with params: ${key}`); + this.logger.log(`Entering function with params ${key}`, `${LegacyService.name} - ${this.deleteRedisKey.name}`); const client = this.connectToRedis(); try { // Set key value with expiration time in seconds - const res = await client.delAsync(key); - Logger.log(` [*] Removing key/pair result => ${res}`); + const res = await client.delAsync(key).catch((error) => { + this.logger.error('Couldn\'t delete redis key/value.', error, `${LegacyService.name} - ${this.deleteRedisKey.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t delete redis key/value.' }); + }); + Logger.log(`Removing key/pair, result is: ${res}`, `${LegacyService.name} - ${this.deleteRedisKey.name}`); client.quit(); return res; } catch (error) { - Logger.error(` [x] Removing key/pair error:`); - Logger.error(error); client.quit(); handleError(error, new InternalServerErrorException('Couldn\'t remove key/value in redis.')); } } private async getRedisValueByKey(key: string): Promise<string> { - Logger.log(`[-] getRedisValueByKey with key: ${key}`); + this.logger.log(`Entering function with params ${key}`, `${LegacyService.name} - ${this.getRedisValueByKey.name}`); const client = this.connectToRedis(); try { - const res = await client.getAsync(key); - Logger.log(` [*] Value found => ${res}`); + const res = await client.getAsync(key).catch((error) => { + this.logger.error('Couldn\'t get redis value.', error, `${LegacyService.name} - ${this.getRedisValueByKey.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t get redis value.' }); + }); + Logger.log(`Value found: ${res}`, `${LegacyService.name} - ${this.getRedisValueByKey.name}`); client.quit(); return res; } catch (error) { - Logger.error(` [x] Error getting value from redis:`); - Logger.error(error); client.quit(); handleError(error, new InternalServerErrorException('Couldn\'t get value from redis.')); } } private connectToRedis() { - Logger.log(`[-] Connecting to redis`); + this.logger.log(`Entering function`, `${LegacyService.name} - ${this.connectToRedis.name}`); const client = redis.createClient({ host: this.conf.redis.host, port: this.conf.redis.port }); - client.on('error', (err) => { - Logger.error(' [x] Redis client error:'); - Logger.error(err); + client.on('error', (error) => { + this.logger.error('Redis client error.', error, `${LegacyService.name} - ${this.connectToRedis.name}`); client.quit(); }); @@ -823,13 +888,21 @@ export class LegacyService { } private async sendEmail(emailBody: Email) { - return request.post( - { - url: `${this.conf.serviceEmailUrl}/send`, - headers: { - apiKey: this.configService.config.apiKey, + try { + this.logger.log(`Entering function`, `${LegacyService.name} - ${this.sendEmail.name}`); + return request.post( + { + url: `${this.conf.serviceEmailUrl}/send`, + headers: { + apiKey: this.configService.config.apiKey, + }, }, - }, - ).form(emailBody); + ).form(emailBody).catch((error) => { + this.logger.error('Couldn\'t send email.', error, `${LegacyService.name} - ${this.sendEmail.name}`); + throw new InternalServerErrorException({ error, message: 'Couldn\'t send email.' }); + }); + } catch(error) { + handleError(error, new InternalServerErrorException('Couldn\'t send email.')); + } } } \ No newline at end of file diff --git a/src/main.ts b/src/main.ts index 13ac824..aec5208 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,9 +6,12 @@ import * as cookieParser from 'cookie-parser'; import * as swStats from 'swagger-stats'; import * as favicon from 'serve-favicon'; import * as path from 'path'; +import { AppLogger } from './app-logger'; async function bootstrap() { - const app = await NestFactory.create(AppModule); + const app = await NestFactory.create(AppModule, { + logger: false, + }); app.enableCors({ credentials: true, origin: true }); app.use(cookieParser()); @@ -31,6 +34,8 @@ async function bootstrap() { app.useGlobalPipes(new ValidationPipe()); + app.useLogger(app.get(AppLogger)); + await app.listen(3000); } bootstrap(); diff --git a/src/middlewares/decode-jwt-payload.middleware.ts b/src/middlewares/decode-jwt-payload.middleware.ts index 8b7e055..da4c051 100644 --- a/src/middlewares/decode-jwt-payload.middleware.ts +++ b/src/middlewares/decode-jwt-payload.middleware.ts @@ -5,13 +5,17 @@ import { ConfigService } from '../configuration/config.service'; @Injectable() export class VerifyXsrfTokenAndDecodeJWTPayloadMiddleware implements NestMiddleware { + private logger: Logger; + constructor( private _configService: ConfigService, - ) {} + ) { + this.logger = new Logger(VerifyXsrfTokenAndDecodeJWTPayloadMiddleware.name); + } resolve(): MiddlewareFunction { return (req, res, next) => { - Logger.log('[-] VerifyXsrfTokenAndDecodeJWTPayloadMiddleware'); + this.logger.log('Entering function', `${VerifyXsrfTokenAndDecodeJWTPayloadMiddleware.name} - ${this.resolve.name}`); // Verifying that all the authentications part are set // tslint:disable-next-line:max-line-length if (req.headers['x-anonymous-consumer'] !== 'true' && req.cookies[this._configService.config.accessTokenCookieKey] && req.headers['x-xsrf-token']) { @@ -25,12 +29,15 @@ export class VerifyXsrfTokenAndDecodeJWTPayloadMiddleware implements NestMiddlew req.headers.token = token; next(); } else { + this.logger.log('Could\'t verify xsrf token.'); throw new UnauthorizedException('Could\'t verify xsrf token.'); } } else { + this.logger.log('Invalid token provided'); throw new UnauthorizedException('Invalid token provided.'); } } else { + this.logger.log('Missing credential information'); throw new UnauthorizedException('Missing credential information.'); } }; diff --git a/template.env b/template.env new file mode 100644 index 0000000..dae0ac0 --- /dev/null +++ b/template.env @@ -0,0 +1,11 @@ +TAG=<version of the service to deploy> +MIDDLEWARE_LEGACY_SERVICE_BIND_PORT=<listening port of the service> +LEGACY_AUTH_SERVICE_URL=<base url of the legacy auth service> +ADMIN_PASSWORD=<admin password of the legacy auth service> +ADMIN_USERNAME=<admin username of the legacy auth service> +SERVICE_EMAIL_URL=<base url of the mail service> +USER_SUPPORT_MAILBOX=<user support email address> +FRONT_END_URL=<web app url> +API_KEY=<api key of the of the service (generated in kong)> +ACCESS_TOKEN_COOKIE_KEY=<cookie key where the access token will be stored> +IMAGE_HOST=<host of the images present in the emails body> \ No newline at end of file -- GitLab