From 9e3adddd9bce969ee68b36494dc629c1aee13147 Mon Sep 17 00:00:00 2001 From: Mister-Mario Date: Sat, 27 Apr 2024 10:10:36 +0200 Subject: [PATCH] Forget password done in the backend --- gatewayservice/gateway-service.js | 91 ++++++++++++++++++++++++++++++- gatewayservice/package-lock.json | 9 +++ gatewayservice/package.json | 3 +- users/userservice/user-service.js | 79 +++++++++++++++++++++++++-- 4 files changed, 172 insertions(+), 10 deletions(-) diff --git a/gatewayservice/gateway-service.js b/gatewayservice/gateway-service.js index 49b59c0f..5e84ef08 100644 --- a/gatewayservice/gateway-service.js +++ b/gatewayservice/gateway-service.js @@ -8,13 +8,26 @@ const fs = require("fs") const YAML = require('yaml') const jwt = require('jsonwebtoken'); const app = express(); -const port = 8000; +const port = 8010; +//Setting up the email +const nodemailer = require('nodemailer'); + +const transporter = nodemailer.createTransport({ + service: 'Gmail', + auth: { + user: "wiqen1b@gmail.com", + pass: "akskfqgakjvcswyg ", + }, +}); const authServiceUrl = process.env.AUTH_SERVICE_URL || 'http://localhost:8002'; -const userServiceUrl = process.env.USER_SERVICE_URL || 'http://localhost:8001'; +const userServiceUrl = process.env.USER_SERVICE_URL || 'http://localhost:8011'; const questionServiceUrl = process.env.QUESTION_SERVICE_URL || 'http://localhost:8003'; const recordServiceUrl = process.env.RECORD_SERVICE_URL || 'http://localhost:8004'; + +var forgetPasswords = new Map() + app.use(cors()); app.use(express.json()); @@ -41,7 +54,50 @@ app.post('/adduser', async (req, res) => { try { // Forward the add user request to the user service const userResponse = await axios.post(userServiceUrl+'/adduser', req.body); - console.log(userResponse) + res.json(userResponse.data); + } catch (error) { + manageError(res, error); + + } +}); + +app.post('/forgetPassword', async (req, res) => { + try { + // Forward the forget password request to the user service + const userResponse = await axios.post(userServiceUrl+'/forgetPassword', req.body); + + let sixNumbers = getRandomSixDigitNumber(); + while(forgetPasswords.has(sixNumbers)) + sixNumbers = getRandomSixDigitNumber(); + + forgetPasswords.set(sixNumbers, userResponse.data.token) + await sendEmail(res, userResponse.data.email, userResponse.data.username, sixNumbers) + } catch (error) { + manageError(res, error); + + } +}); + +app.get('/tokenFromCode/:code', async (req, res) => { + try { + var code = parseInt(req.params.code); + if(forgetPasswords.has(code)){ + var token = forgetPasswords.get(code) + forgetPasswords.delete(code) + res.json({token: token}); + } + else + res.status(400).json({ error : "Invalid code" }); + } catch (error) { + manageError(res, error); + + } +}); + +app.post('/changePassword', verifyToken, async (req, res) => { + try { + // Forward the forget password request to the user service + const userResponse = await axios.post(userServiceUrl+'/changePassword', req.body); res.json(userResponse.data); } catch (error) { manageError(res, error); @@ -229,10 +285,39 @@ function validateUser(user){ } function manageError(res, error){ + console.log(error) if(error.response) //Some microservice responded with an error res.status(error.response.status).json({ error: error.response.data.error }); else //Some other error res.status(500).json({error : "Internal server error"}) } +function getRandomSixDigitNumber() { + const now = Date.now(); // Gets the current timestamp + const lastSixDigits = now.toString().slice(-6); // Gets the last 6 digits as a string + return parseInt(lastSixDigits, 10); // Converts it back to an integer +} + +async function sendEmail(res, email, username, numbers) { + console.log(numbers) + // Configuración del correo + const mailOptions = { + from: process.env.EMAIL_USER, // Remitente + to: email, // Destinatario + subject: 'Hello ' + username + ' this is the wiqen1b team', // Asunto + text: 'We see that you have requested a password change.\n' + + 'Please introduce the code: ' + numbers + '. You have around 10 minutes to change your password \n' + + 'In case you have not requested a password change forget this email existance', + }; + + try { + // Envía el correo + await transporter.sendMail(mailOptions); + res.send('Email sent successfully'); + } catch (error) { + console.error('Error sending email:', error); + res.status(500).send('Error sending email'); + } +} + module.exports = server diff --git a/gatewayservice/package-lock.json b/gatewayservice/package-lock.json index 48729129..8748d7db 100644 --- a/gatewayservice/package-lock.json +++ b/gatewayservice/package-lock.json @@ -15,6 +15,7 @@ "express-openapi": "^12.1.3", "express-prom-bundle": "^7.0.0", "jsonwebtoken": "^9.0.2", + "nodemailer": "^6.9.13", "swagger-ui-express": "^5.0.0", "yaml": "^2.4.1" }, @@ -3790,6 +3791,14 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/nodemailer": { + "version": "6.9.13", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.9.13.tgz", + "integrity": "sha512-7o38Yogx6krdoBf3jCAqnIN4oSQFx+fMa0I7dK1D+me9kBxx12D+/33wSb+fhOCtIxvYJ+4x4IMEhmhCKfAiOA==", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", diff --git a/gatewayservice/package.json b/gatewayservice/package.json index 0757ca8f..756bc677 100644 --- a/gatewayservice/package.json +++ b/gatewayservice/package.json @@ -22,8 +22,9 @@ "cors": "^2.8.5", "express": "^4.18.2", "express-openapi": "^12.1.3", - "jsonwebtoken": "^9.0.2", "express-prom-bundle": "^7.0.0", + "jsonwebtoken": "^9.0.2", + "nodemailer": "^6.9.13", "swagger-ui-express": "^5.0.0", "yaml": "^2.4.1" }, diff --git a/users/userservice/user-service.js b/users/userservice/user-service.js index a6ea8a09..7bc09273 100644 --- a/users/userservice/user-service.js +++ b/users/userservice/user-service.js @@ -7,7 +7,7 @@ const jwt = require('jsonwebtoken'); const User = require('./user-model') const app = express(); -const port = 8001; +const port = 8011; // Middleware to parse JSON in request body app.use(bodyParser.json()); @@ -31,10 +31,11 @@ function validateRequiredFields(req, requiredFields) { } } - let email = req.body.email.toString(); - let username = req.body.username.toString(); - let password = req.body.password.toString(); - let repeatPassword = req.body.repeatPassword.toString(); + //If there are not here is because they dont need to be, it has being check before which need to be here + let email = req.body.email ? req.body.email.toString() : "example@example.com"; + let username = req.body.username ? req.body.username.toString() : "example"; + let password = req.body.password ? req.body.password.toString() : "123456789"; + let repeatPassword = req.body.repeatPassword ? req.body.repeatPassword.toString() : "123456789"; if(!validateEmail(email)){ //User put a wrong format email @@ -106,7 +107,73 @@ app.post('/adduser', async (req, res) => { res.json({ token: token, username: savedUser.username, email: savedUser.email}); } catch (error) { res.status(400).json({ error: error.message }); - }}); + }} +); + +app.post('/forgetPassword', async (req, res) => { + try { + // Check if required fields are present in the request body + try{ + validateRequiredFields(req, ['email', 'username']); + } + catch(error){ + res.status(400).json({ error : error.message }); + return + } + //Check there is a user with that name + const userUsername = await User.findOne({username: req.body.username.toString()}); + + if(!userUsername || userUsername.email !== req.body.email) + return res.status(400).json({error : "No user found, review credentials"}) + + + const token = jwt.sign({ userId: userUsername._id }, (process.env.JWT_KEY??'my-key'), { expiresIn: '15m' }); + + res.json({ token: token, username: userUsername.username, email: userUsername.email}); + } catch (error) { + res.status(400).json({ error: error.message }); + }} +); + +app.post('/changePassword', async (req, res) => { + try { + // Check if required fields are present in the request body + try{ + validateRequiredFields(req, ['email', 'username', 'password', 'repeatPassword']); + } + catch(error){ + res.status(400).json({ error : error.message }); + console.log(res) + return + } + + + //Check there is a user with that name + const userUsername = await User.findOne({username: req.body.username.toString()}); + + if(!userUsername || userUsername.email !== req.body.email) + return res.status(400).json({error : "No user found, review credentials"}) + + // Encrypt the password before saving it + const hashedPassword = await bcrypt.hash(req.body.password, 10); + + const result = await User.updateOne( + { _id: userUsername._id }, + { $set: { password: hashedPassword } } + ); + + if (result.nModified === 0) { + res.status(404).send('User not found or no change'); + } else { + const token = jwt.sign({ userId: userUsername._id }, (process.env.JWT_KEY??'my-key'), { expiresIn: '1h' }); + res.json({ token: token, username: userUsername.username, email: userUsername.email}); + } + + + } catch (error) { + res.status(400).json({ error: error.message }); + }} +); const server = app.listen(port, () => { console.log(`User Service listening at http://localhost:${port}`);