Skip to content
This repository was archived by the owner on Oct 30, 2022. It is now read-only.

Commit ba47389

Browse files
Forgot password and Reset password feature (#112)
* add controller for forgot password and reset password * add password change specific route * add instance method * add route for password change specific routers * Update pwd.controllers.js updated controller, and removed comments * Update server.js removed comments * Update pwd.route.js Added middleware for rate limiting * Create ratelimiter.middleware.js Added a middleware which returns the rate limit function, configuration change can be addressed in a single location
1 parent 4dc8754 commit ba47389

File tree

5 files changed

+152
-27
lines changed

5 files changed

+152
-27
lines changed
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
const asyncHandler = require('express-async-handler');
2+
const User = require('../models/user.modal');
3+
const nodemailer = require('nodemailer');
4+
const jwt = require('jsonwebtoken');
5+
const bcrypt = require('bcryptjs');
6+
7+
module.exports.forgotPwdController = asyncHandler(async (req, res, next) => {
8+
const { email } = req.body;
9+
const user = await User.findOne({ email });
10+
11+
if (!user) {
12+
res.status(400).send({ status: 'user not found' });
13+
throw new Error('User not found');
14+
}
15+
16+
const token = await user.createPWDresetToken();
17+
const resetURL = `${process.env.FRONTEND_URL}/_reset_password/${token}`;
18+
19+
var transporter = nodemailer.createTransport({
20+
service: 'gmail',
21+
auth: {
22+
user: process.env.OUR_EMAIL,
23+
pass: process.env.EMAIL_PASS,
24+
},
25+
from: 'codesync.live',
26+
});
27+
28+
var mailOptions = {
29+
from: process.env.OUR_EMAIL,
30+
to: user.email,
31+
cc: 'codedeeper.work@gmail.com',
32+
subject: 'Codedeeper password reset Token',
33+
html: `<p>Hello , ${user.name} here is your token link. <a href="${resetURL}">Click Here</a> to reset the password</p>`,
34+
text: `<p>Hello , ${user.name} here is your token link. <a href="${resetURL}">Click Here</a> to reset the password</p>`,
35+
};
36+
37+
transporter.sendMail(mailOptions, function (error, info) {
38+
if (error) {
39+
console.log(error);
40+
res.status(200).send({
41+
status: 'failed',
42+
});
43+
} else {
44+
console.log('Email sent: ' + info.response);
45+
if (process.env.NODE_ENV == 'development') {
46+
res.status(200).send({
47+
status: 'success',
48+
resetURL,
49+
});
50+
} else {
51+
res.status(200).send({status:"mail sent successfully"});
52+
}
53+
}
54+
});
55+
});
56+
57+
module.exports.resetPasswordController = asyncHandler(async (req, res) => {
58+
const reset_token = req.params.JWT_TOKEN;
59+
try {
60+
const payload = jwt.verify(reset_token, process.env.JWT_SECRET_KEY);
61+
const { password, confirmpassword } = req.body;
62+
if (!password || !confirmpassword)
63+
throw new Error('Password should be provided!');
64+
65+
if (password !== confirmpassword) throw new Error("Password doesn't match");
66+
67+
const user = await User.findById(payload.id);
68+
if (!user) throw new Error('No user exists with this id');
69+
70+
if (user.passwordChangedAt && user.passwordChangedAt > payload.iat * 1000)
71+
throw new Error(
72+
'Please raise a new Reset Request,this token was used earlier'
73+
);
74+
75+
const newPassword = await bcrypt.hash(password, 12);
76+
user.set({ password: newPassword, passwordChangedAt: new Date() });
77+
await user.save();
78+
79+
return res.status(200).send({
80+
status: 'password changed successfully',
81+
});
82+
} catch (err) {
83+
res.status(400).send({
84+
err: err.message,
85+
});
86+
}
87+
});
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const rateLimit = require('express-rate-limit');
2+
3+
const rateLimiter = ({ windowMs, max, message }) => {
4+
return rateLimit({ windowMs, max, message });
5+
};
6+
module.exports = rateLimiter;

server/models/user.modal.js

Lines changed: 36 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,39 @@
1-
const mongoose = require("mongoose");
1+
const mongoose = require('mongoose');
2+
const jwt = require('jsonwebtoken');
23

3-
const User = mongoose.model("User", {
4-
name: {
5-
type: "String",
6-
required: true,
7-
},
8-
email: {
9-
type: "String",
10-
required: true,
11-
},
12-
password: {
13-
type: "String",
14-
required: true,
15-
},
16-
id: {
17-
type: "String",
18-
},
19-
googleLogin: {
20-
type: "Boolean",
21-
default: false,
22-
},
23-
imageUrl: {
24-
type: "String",
25-
26-
}
27-
});
4+
const userSchema = new mongoose.Schema({
5+
name: {
6+
type: String,
7+
required: true,
8+
},
9+
email: {
10+
type: String,
11+
required: true,
12+
},
13+
password: {
14+
type: String,
15+
required: true,
16+
},
17+
passwordChangedAt: Date,
18+
id: {
19+
type: String,
20+
},
21+
googleLogin: {
22+
type: Boolean,
23+
default: false,
24+
},
25+
imageUrl: {
26+
type: String,
27+
},
28+
});
2829

30+
userSchema.methods.createPWDresetToken = async function () {
31+
return jwt.sign(
32+
{ email: this.email, id: this._id },
33+
process.env.JWT_SECRET_KEY,
34+
{ expiresIn: 600 }
35+
);
36+
};
37+
38+
const User = mongoose.model('User', userSchema);
2939
module.exports = User;

server/routes/pwd.route.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
const express = require('express');
2+
const rateLimiter = require('../middleware/ratelimiter.middleware');
3+
4+
const forgotPasswordRateLimit = rateLimiter({
5+
windowMs: 10 * 60 * 1000,
6+
max: 1,
7+
message: 'Too many requests, please try again later for resetting password.',
8+
});
9+
10+
const {
11+
forgotPwdController,
12+
resetPasswordController,
13+
} = require('../controllers/pwd.controllers');
14+
15+
const router = express.Router();
16+
17+
router.get('/_reset_password/:JWT_TOKEN', resetPasswordController);
18+
router.post('/_forgot_password', forgotPasswordRateLimit, forgotPwdController);
19+
20+
module.exports = router;

server/server.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ app.use(express.json());
3535
app.get("/", (req, res) => {
3636
res.send("API IS RUNNING")
3737
})
38+
39+
app.use('/api',require('./routes/pwd.route'))
3840
app.use('/api/room/', require('./routes/room.route'));
3941
app.use('/api/user/', require('./routes/user.route'));
4042

@@ -163,4 +165,4 @@ app.post('/sendMail', (req, res) => {
163165
// }
164166
server.listen(port, () => {
165167
console.log(`Example app listening at http://localhost:${port}`)
166-
})
168+
})

0 commit comments

Comments
 (0)