Skip to content

Commit d0b4e74

Browse files
committed
authentication complete: integrate fronted and backend
1 parent cd0a497 commit d0b4e74

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

55 files changed

+13634
-1486
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
11
/node_modules
22
/config
3-
.env
3+
.env
4+
dist
5+
.cache

app.js

+10-4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ const compression = require("compression");
55
const cors = require("cors");
66
const logger = require("morgan");
77
const bodyParser = require("body-parser");
8+
const cookieParser = require('cookie-parser');
9+
const path = require('path');
810
const session = require("express-session");
911
const upload = require('express-fileupload');
1012
const getRoutes = require("./backend/routes/getRoutes");
@@ -19,8 +21,9 @@ app.use(upload({createParentPath:true}));
1921
app.use(compression());
2022
app.use(express.json());
2123
app.use(bodyParser.json());
22-
app.use(bodyParser.urlencoded({ extended: true }));
23-
app.use(express.static(__dirname + "/client"));
24+
app.use(cookieParser());
25+
// app.use(express.static(__dirname + "/client"));
26+
app.use(express.static(path.join(__dirname,"client/dist")));
2427
app.use(logger("dev"));
2528
app.set("views", __dirname + "/client/views");
2629
app.set("view engine", "ejs");
@@ -37,8 +40,11 @@ app.use(
3740
);
3841

3942
app.use("/post", postRoutes)
40-
app.use("/", getRoutes);
41-
43+
app.use("/api", getRoutes);
44+
//frontend routes
45+
app.get("*",(req,res)=>{
46+
res.sendFile(path.join(__dirname,'client/dist/index.html'));
47+
})
4248
app.set("port", process.env.PORT || 4000);
4349
app.listen(app.get("port"), () => {
4450
console.log("App started running at " + app.get("port"));
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
const config = require('config');
2+
const User = require('../../models/userModal');
3+
const jwt = require('jsonwebtoken');
4+
module.exports = async (req,res) => {
5+
const token = req.cookies['token'];
6+
if(!token)return res.status(401).send({errorMsg:'Unauthorized!'});
7+
try{
8+
const decoded = jwt.verify(token,config.get('jwtSecret'));
9+
let user = await User.findById(decoded.id).exec();
10+
let userData = {
11+
userName:user.name,
12+
userId:user._id,
13+
emailVerified:user.emailVerified,
14+
phoneNumberVerified:user.phoneNumberVerified
15+
}
16+
res.set('Cache-Control','no-store');
17+
req.session.userId = user._id;
18+
return res.status(200).send({...userData});
19+
}
20+
catch(e){
21+
console.log(e);
22+
return res.status(400).send({errorMsg:'Invalid Token!'});
23+
}
24+
25+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
module.exports = (req, res) => {
2+
req.session.destroy(function (err) {
3+
if (!err) {
4+
console.log("destroying");
5+
res.cookie("token", '' , {
6+
expires: new Date(0),
7+
httpOnly: false,
8+
});
9+
res.cookie("userName", '' , {
10+
expires: new Date(0),
11+
httpOnly: false,
12+
});
13+
res.cookie("userId", '' , {
14+
expires: new Date(0),
15+
httpOnly: false,
16+
});
17+
res.cookie("emailVerified", '' , {
18+
expires: new Date(0),
19+
httpOnly: false,
20+
});
21+
res.cookie("phoneNumberVerified", '' , {
22+
expires: new Date(0),
23+
httpOnly: false,
24+
});
25+
res.set("Cache-Control","no-store");
26+
res.status(200).send({ msg: "Logout success" });
27+
}
28+
});
29+
};
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,24 @@
1-
const crypto = require("crypto");
21
const User = require("../../models/userModal");
3-
const sendEmail = require("../../utils/smtpTransport");
4-
const encrypt = (text) => {
5-
var cipher = crypto.createCipher(
6-
process.env.ENCRYPTION_ALGO,
7-
process.env.CRYPTOJS_SECRET
8-
);
9-
var encrypted = cipher.update(text, "utf8", "hex") + cipher.final("hex");
10-
return encrypted;
11-
};
2+
const sendEmail = require("../../utils/sendVerificationEmail");
3+
const jwt = require('jsonwebtoken');
4+
const config = require('config');
125
const sendVerificationEmail = async (req, res) => {
13-
const id = req.session.userId;
14-
//check if email is already verified
6+
const token = req.cookies['token'];
7+
const decoded = jwt.verify(token,config.get('jwtSecret'));
8+
const id = decoded.id;
9+
console.log(id);
1510
const user = await User.findById(id).exec();
1611
if (user.emailVerified)
17-
return res.status(400).send({ error: "Your email is already verified" });
18-
//encrypt the id and current time
19-
var encryptedID = encrypt(id);
20-
var encryptedTime = encrypt((Date.now()).toString());
21-
//construct link with the encrypted ID and current time
22-
//a = id && b = time, used bad naming so that verification link do not get very obivious to user or third party
23-
const link = `${process.env.PROTOCOL}://${process.env.HOST}/verifyEmail?a=${encryptedID}&b=${encryptedTime}`;
24-
//create the email
25-
const mailOptions = {
26-
to: user.email,
27-
subject: "Please confirm your Email Address",
28-
html: `<img src="https://media-exp1.licdn.com/dms/image/sync/C4E22AQG4zTDlyguaNQ/feedshare-shrink_800/0/1602572271436?e=1623888000&v=beta&t=Aq2jU_LLoM8lK5Mq7TgYxdf-9tkVZJs3Bc2m0HK68tw" /><br><br>Hello,<br> Please Click on the link to verify your email.<br><a href=${link}>Click here to verify</a><br>The above link is valid for ${process.env.EMAIL_LINK_VALIDITY} minutes only`,
29-
};
30-
try {
31-
//send email to the user
32-
let response = await sendEmail(mailOptions);
12+
return res.redirect('/home');
13+
try{
14+
const response = await sendEmail(id,user.email);
3315
console.log(response);
34-
//render verifyEmail page to inform user that an email has been sent at his registered mobile number now
35-
return res.render("verifyEmailMsg");
36-
} catch (err) {
16+
res.set("Cache-Control","no-store");
17+
return res.status(200).send({msg:"success"});
18+
}
19+
catch(err){
3720
console.log(err);
38-
return res.status(500).send(err);
21+
return res.status(500).send({errorMsg:"Can't sent Otp! Something went wrong"});
3922
}
4023
};
4124
module.exports = sendVerificationEmail;

backend/controllers/getControllers/verifyEmail.js

+10-8
Original file line numberDiff line numberDiff line change
@@ -31,22 +31,24 @@ const verifyEmail = async (req, res) => {
3131
if (timeElapsed < process.env.EMAIL_LINK_VALIDITY) {
3232
//email link is clicked in valid time duration
3333
user.emailVerified = true;
34-
user.save();
34+
await user.save();
3535
console.log("email verified");
36-
res.redirect("home");
36+
res.cookie("emailVerified", user.emailVerified, {
37+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
38+
httpOnly: false,
39+
});
40+
res.redirect("/dashboard");
3741
} else {
3842
//link not clicked in valid time duration
39-
res.render("sentEmailLinkAgain");
43+
res.status(400).send({errorMsg:"Invalid Link"});
44+
// res.render("sentEmailLinkAgain");
4045
}
4146
} else {
42-
res.status(400).send({ error: "Invalid request!" });
47+
res.status(400).send({ errorMsg: "Invalid request!" });
4348
}
4449
} else {
4550
//domain didn't matched
46-
//now we need to reset req.session.host, req.session.protocol
47-
req.session.protocol = null;
48-
req.session.host = null;
49-
res.status(400).send({ error: "Invalid request!" });
51+
res.status(400).send({ errorMsg: "Invalid request!" });
5052
}
5153
};
5254
module.exports = verifyEmail;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
const crypto = require("crypto");
2+
const User = require("../../models/userModal");
3+
const decrypt = (cipher) => {
4+
const decipher = crypto.createDecipher(
5+
process.env.ENCRYPTION_ALGO,
6+
process.env.CRYPTOJS_SECRET
7+
);
8+
var decrypted =
9+
decipher.update(cipher, "hex", "utf8") + decipher.final("utf8");
10+
return decrypted;
11+
};
12+
const verifyResetPasswordLink = async (req, res) => {
13+
const host = req.get("host");
14+
if (
15+
`${req.protocol}://${host}` ==
16+
`${process.env.PROTOCOL}://${process.env.HOST}`
17+
) {
18+
//domain matched
19+
const encryptedID = req.query.a; //since a = id
20+
const encryptedTime = req.query.b; //since b = time
21+
//decrypt ID and Time
22+
const decryptedID = decrypt(encryptedID);
23+
const decryptedTime = decrypt(encryptedTime);
24+
console.log("decryptedID : ",decryptedID," decryptedTime : ",decryptedTime);
25+
let user;
26+
try{
27+
user = await User.findById(decryptedID).exec();
28+
}catch(err){
29+
return res.status(500).send({errorMsg:"Internal Server Error"})
30+
}
31+
if (user) {
32+
const timeElapsed = (Date.now() - decryptedTime) / (1000 * 60); //in minutes;
33+
console.log(user);
34+
if (timeElapsed < process.env.EMAIL_LINK_VALIDITY) {
35+
//email link is clicked in valid time duration
36+
res.send({msg:"success"});
37+
} else {
38+
//link not clicked in valid time duration
39+
console.log("the link is click after it gets disabled");
40+
res.status(400).send({errorMsg:"Invalid Link"});
41+
// res.render("sentEmailLinkAgain");
42+
}
43+
} else {
44+
console.log("invalid userId while verify reset password link");
45+
res.status(400).send({ errorMsg: "Invalid request!" });
46+
}
47+
} else {
48+
//domain didn't matched
49+
console.log("domain didn't matched");
50+
res.status(400).send({ errorMsg: "Invalid request!" });
51+
}
52+
};
53+
module.exports = verifyResetPasswordLink;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
const crypto = require("crypto");
2+
const User = require("../../models/userModal");
3+
const bcrypt = require("bcryptjs");
4+
const decrypt = (cipher) => {
5+
const decipher = crypto.createDecipher(
6+
process.env.ENCRYPTION_ALGO,
7+
process.env.CRYPTOJS_SECRET
8+
);
9+
var decrypted =
10+
decipher.update(cipher, "hex", "utf8") + decipher.final("utf8");
11+
return decrypted;
12+
};
13+
const changePassword = async (req, res) => {
14+
const { password, confirmPassword } = req.body;
15+
if (!password || !confirmPassword)
16+
return res.status(400).send({ errorMsg: "Both the fields are required!" });
17+
//both password and confirmPassword supplied in the body;
18+
if (password != confirmPassword)
19+
return res.status(401).send({ errorMsg: "Passwords don't match!" });
20+
//passwords matched
21+
const encryptedID = req.query.a; //since a = id
22+
const encryptedTime = req.query.b; //since b = time
23+
console.log(encryptedID);
24+
console.log(encryptedTime);
25+
//decrypt ID and Time
26+
const decryptedID = decrypt(encryptedID);
27+
const decryptedTime = decrypt(encryptedTime);
28+
let user;
29+
try {
30+
user = await User.findById(decryptedID).exec();
31+
} catch (err) {
32+
return res.status(500).send({ error: "Internal Server Error" });
33+
}
34+
if (!user)
35+
return res
36+
.status(400)
37+
.send({ error: "This link is not valid now! Please get a new link." });
38+
//valid userId;
39+
const timeElapsed = (Date.now() - decryptedTime) / (1000 * 60); //in minutes;
40+
if (timeElapsed > process.env.EMAIL_LINK_VALIDITY)
41+
return res
42+
.status(400)
43+
.send({ error: "This link is not valid now! Please get a new link." });
44+
//password is changed in valid time duration
45+
bcrypt.genSalt(10, (err, salt) => {
46+
bcrypt.hash(password, salt, async (err, hash) => {
47+
if (err) res.status(500).send({ error: "Internal Server Error" });
48+
user.password = hash;
49+
try {
50+
await user.save();
51+
return res.send({ msg: "success" });
52+
} catch (err) {
53+
return res.status(500).send({ error: "Internal Server Error" });
54+
}
55+
});
56+
});
57+
};
58+
module.exports = changePassword;
+47-18
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,61 @@
11
const User = require("../../models/userModal");
2-
const config = require('config');
2+
const config = require("config");
33
const bcrypt = require("bcryptjs");
44
const jwt = require("jsonwebtoken");
55
const login = async (req, res) => {
66
const { email, password } = req.body;
77
if (!email || !password) {
88
console.log({ email, password }, "email or password empty!");
9-
return res.status(400).send({ error: "Email and password are required!" });
9+
return res
10+
.status(400)
11+
.send({ errorMsg: "Email and password are required!" });
1012
}
1113
const user = await User.findOne().findByEmail(email).exec();
12-
console.log("find user : ",user,"user password : ",user.password);
1314
if (!user) {
1415
console.log("Invalid email!");
15-
return res.status(400).send({ error: "Invalid email!" });
16+
return res.status(400).send({ errorMsg: "This email is not registered!" });
1617
}
17-
bcrypt.compare(password, user.password).then(isMatch => {
18-
if (!isMatch) return res.send({ errorMsg: "Please Check your Password" });
19-
jwt.sign({ id: user._id }, config.get("jwtSecret"), { expiresIn: 60 * 60 }, (err, token) => {
20-
if (err) return res.status(500).send(err);
21-
res.cookie("token", token, {
22-
maxAge: 60 * 60,
23-
httpOnly: true,
24-
});
25-
req.session.userId = user._id;
26-
console.log("req.session.userId : ",user._id);
27-
req.session.mobileNumber = user.callingPhoneNumber;
28-
return res.redirect('/home');
29-
});
18+
bcrypt.compare(password, user.password).then((isMatch) => {
19+
console.log(isMatch);
20+
if (!isMatch) return res.status(401).send({ errorMsg: "Please Check your Password!" });
21+
jwt.sign(
22+
{ id: user._id },
23+
config.get("jwtSecret"),
24+
{ expiresIn: "6h" },
25+
(err, token) => {
26+
if (err)
27+
return res
28+
.status(500)
29+
.send({ errorMsg: "Status Code:500, Internal Server Error!" });
30+
res.cookie("token", token, {
31+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
32+
httpOnly: false,
33+
});
34+
res.cookie("userName", user.name, {
35+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
36+
httpOnly: false,
37+
});
38+
res.cookie("userId", user._id, {
39+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
40+
httpOnly: false,
41+
});
42+
res.cookie("emailVerified", user.emailVerified, {
43+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
44+
httpOnly: false,
45+
});
46+
res.cookie("phoneNumberVerified", user.phoneNumberVeried, {
47+
expires: new Date(Date.now() + 1000 * 60 * 60 * 5),
48+
httpOnly: false,
49+
});
50+
return res.status(200).send({
51+
token,
52+
emailVerified: user.emailVerified,
53+
phoneNumberVerified: user.phoneNumberVerified,
54+
userName: user.name,
55+
userId: user._id
56+
});
57+
}
58+
);
3059
});
3160
};
32-
module.exports = login;
61+
module.exports = login;

0 commit comments

Comments
 (0)