From dbdc9f78c54d2dede16761276dcd7a0234ff8fde Mon Sep 17 00:00:00 2001 From: xfarrow Date: Mon, 25 Mar 2024 15:39:04 +0100 Subject: [PATCH] reset password API complete --- .../apis/nodejs/src/models/person_model.js | 3 +- .../nodejs/src/models/reset_password_model.js | 41 +++++++++++++++++-- .../src/routes/reset_password_routes.js | 36 +++++++++++++--- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/backend/apis/nodejs/src/models/person_model.js b/backend/apis/nodejs/src/models/person_model.js index ee615a1..f5d55f7 100644 --- a/backend/apis/nodejs/src/models/person_model.js +++ b/backend/apis/nodejs/src/models/person_model.js @@ -139,7 +139,7 @@ async function remove(personId) { async function confirmActivation(personId) { await knex.transaction(async (tr) => { - await knex('Person') + await tr('Person') .where('id', personId) .update({ enabled: true @@ -149,7 +149,6 @@ async function confirmActivation(personId) { .where('person_id', personId) .del(); }); - } // Exporting a function diff --git a/backend/apis/nodejs/src/models/reset_password_model.js b/backend/apis/nodejs/src/models/reset_password_model.js index 9a9551f..399ec8d 100644 --- a/backend/apis/nodejs/src/models/reset_password_model.js +++ b/backend/apis/nodejs/src/models/reset_password_model.js @@ -13,14 +13,47 @@ const knex = require('../utils/knex_config'); -async function add(email, secret){ +async function add(email, secret) { await knex('RequestResetPassword') - .insert({ - email, + .insert({ + email, + secret + }); +} + +async function findBySecret(secret) { + return await knex('RequestResetPassword').where({ secret + }).first(); +} + +/** + * Given a secret and a new password, update the Peron's personal password + * + * @param {*} password The new (hashed) password + * @param {*} secret The secret received via e-mail (table RequestResetPassword) + * @returns + */ +async function resetPassword(password, secret) { + const request = await findBySecret(secret); + if (!request) { + return; + } + await knex.transaction(async tr => { + await tr('Person').where({ + email: request.email + }).update({ + password + }); + + await tr('RequestResetPassword').where({ + email + }).del(); }); } module.exports = { - add + add, + findBySecret, + resetPassword } \ No newline at end of file diff --git a/backend/apis/nodejs/src/routes/reset_password_routes.js b/backend/apis/nodejs/src/routes/reset_password_routes.js index bcbba82..4ee258c 100644 --- a/backend/apis/nodejs/src/routes/reset_password_routes.js +++ b/backend/apis/nodejs/src/routes/reset_password_routes.js @@ -13,21 +13,22 @@ const Person = require('../models/person_model'); const mailUtils = require('../utils/mail_utils'); -const RequestResetPassword = require('../models/reset_password_model'); +const ResetPassword = require('../models/reset_password_model'); const crypto = require('crypto'); const express = require('express'); +const bcrypt = require('bcrypt'); async function add(req, res) { try { const userExists = await Person.findByEmail(req.body.email); // If the user does not exist, do not inform them of the absence - // of the user if (userExists) { const secret = crypto.randomBytes(16).toString('hex'); - await RequestResetPassword.add(req.body.email, secret); - mailUtils.sendMail(req.body.email, 'Blink Reset Password', secret, null); + await ResetPassword.add(req.body.email, secret); + const body = `Click on this link: ...${secret} to reset your Blink password. If you did not ask for such a change, simply ignore this e-mail.`; + mailUtils.sendMail(req.body.email, 'Blink Reset Password', body, null); } - return res.status(204).send(); + res.status(204).send(); } catch (error) { console.error(`Error in function ${registerPerson.name}: ${error}`); res.status(500).json({ @@ -36,9 +37,32 @@ async function add(req, res) { } } +async function reset(req, res) { + try { + const requester = await ResetPassword.findBySecret(req.body.secret); + if (requester) { + const diffMilliseconds = Date.now() - requester.time_of_request.getTime(); + // Check whether the request was not performed more than 30 minutes ago + if(diffMilliseconds / (1000 * 60) <= 30){ + const newPassword = await bcrypt.hash(req.body.password, 10); + ResetPassword.resetPassword(newPassword, req.body.secret); + return res.status(204).send(); + } + } + return res.status(400).send("Request either invalid or expired"); + + } catch (error) { + console.error(`Error in function ${reset.name}: ${error}`); + res.status(500).json({ + error: 'Internal server error' + }); + } +} + const routes = express.Router(); routes.post('/request', add); +routes.post('/reset', reset); module.exports = { - routes + routes }; \ No newline at end of file