diff --git a/README.md b/README.md index b73cc61e07235556621624fce8832e86d91fe2d5..83a433808efc1f0f06bffbd2825d59d635a7faaf 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 14a9dec7dac2f54bdd724a5d58d260482ae1cd2d..be4435a52e14371a748f229d4afd0b63e0f06f99 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 Binary files a/favicon.ico and b/favicon.ico differ diff --git a/package.json b/package.json index 6826679b36c6a1cc9d834fa8f493447c4c0bff18..c770a7f91ec6760be88d4f7e3e66c0650ad1f5dc 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 0000000000000000000000000000000000000000..5c9db3a7540cc094c7ba235cd6ec10e4293c9985 --- /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 4c565bac46f583e09c9a4ea203dd084dfa31c52f..09261fa5fe94f454145d0dc23272c2d00ecb7f40 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 a0a45717da7d8369b6bfecf6eee3db94dcbfd862..2b0f608f18f192bb311022c6fde644dc03f28aab 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 d53d73eebf8cf7646e74d7a8098f2bd8e8a8979e..e411ad023f2df0064b59ccdf0e2cc812028b6557 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 50009a4a08090e532fb16d619bae3e9bc9853e9b..0000000000000000000000000000000000000000 --- 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 61e63786a555c70ab74992a1e994d065956e4802..83f3092cdf66c01270a5d2eb18fd119c24c54a48 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 61b785ce94e706cdfd7fb8b37736f84556225952..dcba32c66a0970eb867dc4f14cd4cd3f523c3cf2 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 1188b3b2d82c75ba2c39d69c85c8f6564c94c879..471f48d93a89df2850537be6a5c54ca50bc269d0 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 13ac8247ba05be344200ad017883cab0223b6659..aec5208ce412e26bcf46f3ad57a978eb2b33a9d0 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 8b7e055396bbaef091128f04e6b06a2c7886adf4..da4c0515e0ad30698e7cb370bb16078bf01d4588 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 0000000000000000000000000000000000000000..dae0ac0cd45b652a9efa8e96c2163a0dad6a9214 --- /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