Skip to content

Commit

Permalink
Merge pull request #134 from Arquisoft/132-add-a-forget-password-func…
Browse files Browse the repository at this point in the history
…tionality

Forget password
  • Loading branch information
UO289845 authored Apr 27, 2024
2 parents f879ccb + 5eaf7e6 commit 5f33898
Show file tree
Hide file tree
Showing 41 changed files with 1,186 additions and 234 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,4 @@ jobs:
wget https://raw.githubusercontent.com/arquisoft/wiq_en1b/master/docker-compose.yml -O docker-compose.yml
wget https://raw.githubusercontent.com/arquisoft/wiq_en1b/master/.env
docker compose down
docker compose --profile prod up -d
docker compose --profile prod up -d --pull always
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@
depends_on:
- gatewayservice
ports:
- "3000:3000"
- "80:80"

prometheus:
image: prom/prometheus
Expand Down
84 changes: 83 additions & 1 deletion gatewayservice/gateway-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,25 @@ const YAML = require('yaml')
const jwt = require('jsonwebtoken');
const app = express();
const port = 8000;
//Setting up the email
const nodemailer = require('nodemailer');

const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: "[email protected]",
pass: "akskfqgakjvcswyg",
},
});

const authServiceUrl = process.env.AUTH_SERVICE_URL || 'http://localhost:8002';
const userServiceUrl = process.env.USER_SERVICE_URL || 'http://localhost:8001';
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());

Expand All @@ -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);
Expand Down Expand Up @@ -235,4 +291,30 @@ function manageError(res, 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) {
// Configuración del correo
const mailOptions = {
from: process.env.EMAIL_USER,
to: email,
subject: 'Hello ' + username + ' this is the wiqen1b team',
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) {
res.status(500).send('Error sending email');
}
}

module.exports = server
51 changes: 49 additions & 2 deletions gatewayservice/gateway-service.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ const request = require('supertest');
const axios = require('axios');
const jwt = require('jsonwebtoken');
const app = require('./gateway-service');
const nodemailer = require('nodemailer');

afterAll(async () => {
app.close();
Expand All @@ -12,8 +13,6 @@ jest.mock('jsonwebtoken');

jest.mock('axios');



describe('Gateway Service with mocked micro services', () => {

// Mock responses from external services
Expand All @@ -24,6 +23,10 @@ describe('Gateway Service with mocked micro services', () => {
return Promise.resolve({ data: { username: 'newuser' } });
} else if(url.endsWith('/record')){
return Promise.resolve({data : {user:'testuser'}})
} else if(url.endsWith('/forgetPassword')){
return Promise.resolve({data : { token: 'mockedToken', username : 'testuser', email:"[email protected]"}})
} else if(url.endsWith('/changePassword')){
return Promise.resolve({data : {token: 'mockedToken', username : 'testuser', email:"[email protected]"}})
}
});

Expand Down Expand Up @@ -60,6 +63,14 @@ describe('Gateway Service with mocked micro services', () => {
callback(null, "decoded");
});


//Mock nodemailer
jest.mock('nodemailer', () => ({
createTransport: jest.fn().mockReturnValue({
sendMail: jest.fn(),
}),
}));

// Test /login endpoint
it('should forward login request to auth service', async () => {
const response = await request(app)
Expand Down Expand Up @@ -146,6 +157,42 @@ describe('Gateway Service with mocked micro services', () => {

});

//Test /forgetPassword
it('should forward the request and send an email', async () => {
const response = await request(app)
.post('/forgetPassword')
.send({ email: '[email protected]', username: 'testuser'});
expect(response.statusCode).toBe(200);
expect(response.text).toBe('Email sent successfully');
})

//Test tokenFromCode/:code
it('should find a token', async () => {
//First generate the code:token

const fixedTimestamp = 1683078000000;
jest.spyOn(Date, 'now').mockReturnValue(fixedTimestamp);

await request(app)
.post('/forgetPassword')
.send({ email: '[email protected]', username: 'testuser'});
const response = await request(app).get('/tokenFromCode/000000');

expect(response.statusCode).toBe(200);
expect(response.body).toHaveProperty('token', "mockedToken");
})

//Test /changePassword
it('should forward the request', async () => {
const response = await request(app)
.post('/changePassword')
.send({ username: 'testuser', password: 'newpassword' })
.set('token', 'valorDelToken');

expect(response.statusCode).toBe(200);
expect(response.body.username).toBe('testuser');
})

});

function checkRecord(response){
Expand Down
147 changes: 147 additions & 0 deletions gatewayservice/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,153 @@ paths:
type: string
description: Error information.
example: Internal Server Error
/forgetPassword:
post:
summary: Sends a forget password alert to the server
operationId: forgetPassword
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: User email
example: [email protected]
username:
type: string
description: User name
example: student
responses:
'200':
description: Email sent successfully
content:
application/json:
schema:
type: string
example: "Email sent successfully"
'400':
description: Failed to find user
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error information.
example: No user found, review credentials
'500':
description: Internal server error.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error information.
example: Internal Server Error
/tokenFromCode{code}:
get:
summary: Get a token from a 6 digit code
parameters:
- name: code
in: path
required: true
schema:
type: string
responses:
'200':
description: Code found returns token
content:
application/json:
schema:
type: object
properties:
token:
type: string
'400':
description: Invalid code
content:
application/json:
schema:
type: string
example: "Invalid code"
'500':
description: Internal server error.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error information.
example: Internal Server Error
/changePassword:
post:
summary: Changes the password of the authorized user
parameters:
- name: token
in: header
schema:
type: string
operationId: changePassword
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
email:
type: string
description: User email
example: [email protected]
username:
type: string
description: User name
example: student
password:
type: string
description: User password
example: password123
repeatPassword:
type: string
description: Userpassword
example: password123
responses:
'200':
description: Email sent successfully
content:
application/json:
schema:
$ref: '#/components/schemas/LoginResponse'
'400':
description: Failed to find user
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error information.
example: No user found, review credentials
'500':
description: Internal server error.
content:
application/json:
schema:
type: object
properties:
error:
type: string
description: Error information.
example: Internal Server Error
/login:
post:
summary: Log in to the system.
Expand Down
9 changes: 9 additions & 0 deletions gatewayservice/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion gatewayservice/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
},
Expand Down
Loading

0 comments on commit 5f33898

Please sign in to comment.