From 49d6fe40ae6b14262baf42742216da7d45d4da26 Mon Sep 17 00:00:00 2001 From: Sergey Yarkov Date: Sun, 25 Jul 2021 17:49:14 +0300 Subject: [PATCH] change password method in user controller --- app/Controllers/Http/AuthController.ts | 2 +- app/Controllers/Http/UsersController.ts | 51 +++++++++++++++++++++++ app/Validators/ChangePasswordValidator.ts | 13 ++++++ app/Validators/CreateUserValidator.ts | 7 +--- start/routes.ts | 6 +++ 5 files changed, 73 insertions(+), 6 deletions(-) create mode 100644 app/Validators/ChangePasswordValidator.ts diff --git a/app/Controllers/Http/AuthController.ts b/app/Controllers/Http/AuthController.ts index 3e3f09c..23daf78 100644 --- a/app/Controllers/Http/AuthController.ts +++ b/app/Controllers/Http/AuthController.ts @@ -24,7 +24,7 @@ export default class AuthController { const user = await this.user.query().preload('roles').where('login', login).firstOrFail(); if (!(await Hash.verify(user.password, password))) { - throw new Exception('Invalid credentials.', 401, 'E_INVALID_CREDENTIALS'); + throw new Exception('Invalid credentials.', 403, 'E_INVALID_CREDENTIALS'); } const token = await auth.use(this.guard).generate(user, { diff --git a/app/Controllers/Http/UsersController.ts b/app/Controllers/Http/UsersController.ts index a14cd6b..8171c7e 100644 --- a/app/Controllers/Http/UsersController.ts +++ b/app/Controllers/Http/UsersController.ts @@ -1,10 +1,17 @@ import { AuthenticationException } from '@adonisjs/auth/build/standalone'; import { Exception } from '@adonisjs/core/build/standalone'; import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; +import Hash from '@ioc:Adonis/Core/Hash'; +import Logger from '@ioc:Adonis/Core/Logger'; + +/* Models */ import Contact from 'App/Models/Contact'; import Role from 'App/Models/Role'; import User from 'App/Models/User'; + +/* Validators */ import AddRoleToUserValidator from 'App/Validators/AddRoleToUserValidator'; +import ChangePasswordValidator from 'App/Validators/ChangePasswordValidator'; import CreateUserValidator from 'App/Validators/CreateUserValidator'; import DelRoleFromUserValidator from 'App/Validators/DelRoleFromUserValidator'; import UpdateUserValidator from 'App/Validators/UpdateUserValidator'; @@ -187,6 +194,50 @@ export default class UsersController { }); } + /** + * Change password of authenticated user + * PATCH /users/me/password + */ + public async changePassword({ request, response, auth }: HttpContextContract) { + await request.validate(ChangePasswordValidator); + + const userId = auth.use('api').token?.userId; + + if (userId) { + const user = await this.user.findOrFail(userId); + const oldPassword: string = request.input('oldPassword'); + const newPassword: string = request.input('newPassword'); + + if (oldPassword === newPassword) { + throw new Exception('The new password is the same as the old one.', 400, 'E_PASSWORD_VALUES'); + } + + /** + * Verify old password + */ + if (!(await Hash.verify(user.password, oldPassword))) { + throw new Exception('Invalid credentials.', 403, 'E_INVALID_CREDENTIALS'); + } + + /** + * Update user password + */ + user.password = newPassword; + await user.save(); + + Logger.info(`Password of user with id: "${user.id}" was updated.`); + + return response.ok({ + message: 'The password was successfully changed to the new value.', + }); + } + + /** + * Unauthorized user + */ + throw new AuthenticationException('Unauthorized access', 'E_UNAUTHORIZED_ACCESS', 'api'); + } + /** * Finds roles by input value and throw error if role does not exist. * diff --git a/app/Validators/ChangePasswordValidator.ts b/app/Validators/ChangePasswordValidator.ts new file mode 100644 index 0000000..d86ea78 --- /dev/null +++ b/app/Validators/ChangePasswordValidator.ts @@ -0,0 +1,13 @@ +import { schema, rules } from '@ioc:Adonis/Core/Validator'; +import { HttpContextContract } from '@ioc:Adonis/Core/HttpContext'; + +export default class ChangePasswordValidator { + constructor(protected ctx: HttpContextContract) {} + + public schema = schema.create({ + oldPassword: schema.string(), + newPassword: schema.string({}, [rules.minLength(6), rules.maxLength(128)]), + }); + + public messages = {}; +} diff --git a/app/Validators/CreateUserValidator.ts b/app/Validators/CreateUserValidator.ts index e0bcf1e..e126d67 100644 --- a/app/Validators/CreateUserValidator.ts +++ b/app/Validators/CreateUserValidator.ts @@ -26,12 +26,9 @@ export default class CreateUserValidator { public schema = schema.create({ first_name: schema.string(), last_name: schema.string(), - login: schema.string({}, [ - rules.maxLength(128), - rules.unique({ table: 'users', column: 'login' }), - ]), + login: schema.string({}, [rules.maxLength(128), rules.unique({ table: 'users', column: 'login' })]), email: schema.string({}, [rules.email(), rules.unique({ table: 'contacts', column: 'email' })]), - password: schema.string(), + password: schema.string({}, [rules.minLength(6), rules.maxLength(128)]), }); /** diff --git a/start/routes.ts b/start/routes.ts index be5755a..6bff601 100644 --- a/start/routes.ts +++ b/start/routes.ts @@ -40,6 +40,12 @@ Route.group(() => { Route.post('users/:id/attach-roles', 'UsersController.attachRoles').middleware('role:admin').as('attachUserRole'); Route.delete('users/:id/detach-roles', 'UsersController.detachRoles').middleware('role:admin').as('detachUserRole'); Route.get('users/me', 'UsersController.showMe').middleware('role:admin,teacher,student').as('showMe'); + Route.patch('users/me/password', 'UsersController.changePassword') + .middleware('role:admin,teacher,student') + .as('changePassword'); + Route.patch('users/me/contacts', 'UsersController.updateContacts') + .middleware('role:admin,teacher,student') + .as('updateContacts'); }).middleware('auth'); }) .prefix('/api/v1')