From 2ee3d87f5a0c73890b769c0142bdfe2e183b598b Mon Sep 17 00:00:00 2001 From: flifloo Date: Tue, 25 Aug 2020 15:40:06 +0200 Subject: [PATCH] Add email verification --- app.js | 2 ++ locales/en.json | 4 +++- locales/fr.json | 4 +++- models/user.js | 9 +++++++++ routes/check.js | 21 +++++++++++++++++++++ routes/profile.js | 7 +++++++ routes/utils/emailCheck.js | 28 ++++++++++++++++++++++++++++ routes/utils/userCreate.js | 7 +++++++ views/profile.pug | 5 +++++ 9 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 routes/check.js create mode 100644 routes/utils/emailCheck.js diff --git a/app.js b/app.js index 76b5f68..60073c1 100644 --- a/app.js +++ b/app.js @@ -16,6 +16,7 @@ let orderRouter = require("./routes/order"); let ordersRouter = require("./routes/orders"); let sandwichesRouter = require("./routes/sandwiches"); let profileRouter = require("./routes/profile"); +let checkRouter = require("./routes/check"); let adminRouter = require("./routes/admin"); let contactRouter = require("./routes/contact"); @@ -70,6 +71,7 @@ app.use("/order", orderRouter); app.use("/orders", ordersRouter); app.use("/sandwiches", sandwichesRouter); app.use("/profile", profileRouter); +app.use("/check", checkRouter); app.use("/admin", adminRouter); app.use("/contact", contactRouter); diff --git a/locales/en.json b/locales/en.json index 20fcab2..545779e 100644 --- a/locales/en.json +++ b/locales/en.json @@ -40,7 +40,9 @@ }, "profile": { "title": "Profile", - "infos": "Infos" + "infos": "Infos", + "emailCheck": "Email verification", + "emailCheckMessage": "We need to validate your email address, please click on the link below to validate it\n\n%s" }, "admin": { "title": "Administration", diff --git a/locales/fr.json b/locales/fr.json index 82ed843..cd839ac 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -40,7 +40,9 @@ }, "profile": { "title": "Profil", - "infos": "Infos" + "infos": "Infos", + "emailCheck": "Vérification e-mail", + "emailCheckMessage": "Nous avons besoin de valider votre adresse email, merci de clicker sur le lien si dessous pour la valider\n\n%s" }, "admin": { "title": "Administration", diff --git a/models/user.js b/models/user.js index 8f321a4..0254de9 100644 --- a/models/user.js +++ b/models/user.js @@ -29,6 +29,15 @@ module.exports = (sequelize, DataTypes) => { }, unique: true }, + emailVerified : { + type: DataTypes.BOOLEAN, + defaultValue: false, + allowNull: false + }, + emailToken: { + type: DataTypes.STRING, + unique: true + }, firstName: { type: DataTypes.STRING, allowNull: false, diff --git a/routes/check.js b/routes/check.js new file mode 100644 index 0000000..9a20e8f --- /dev/null +++ b/routes/check.js @@ -0,0 +1,21 @@ +const express = require("express"); +const router = express.Router(); +const error = require("./utils/error"); +const models = require("../models"); + +router.get("/", async (req, res) => { + if (!req.query.token) + return error(req, res, "Can't verify email", 400, "Missing args"); + + let user = await models.User.findOne({where: {emailToken: req.query.token}}); + if (!user) + return error(req, res, "Can't verify email", 400, "Invalid token"); + + user.emailToken = null; + user.emailVerified = true; + await user.save(); + req.session.user = user; + req.session.save(() => res.redirect("/profile")); +}); + +module.exports = router; diff --git a/routes/profile.js b/routes/profile.js index 862d4a9..28058a8 100644 --- a/routes/profile.js +++ b/routes/profile.js @@ -3,6 +3,8 @@ let router = express.Router(); let sessionCheck = require("../middlewares/sessionCheck"); let models = require("../models"); let userUpdate = require("./utils/userUpdate"); +let emailCheck = require("./utils/emailCheck"); +let error = require("./utils/error"); router.get("/", sessionCheck(0), async (req, res) => { res.render("profile", { @@ -22,6 +24,11 @@ router.get("/", sessionCheck(0), async (req, res) => { req.session.user = user; res.redirect("/profile"); } +}).get("/resend", sessionCheck(0), async (req, res) => { + if (!req.session.user.emailVerified) + await emailCheck(req, res, await models.User.findByPk(req.session.user.username), () => res.redirect("/profile")); + else + return error(req, res, "Can't' resend email", 400, "Email already verified"); }); module.exports = router; diff --git a/routes/utils/emailCheck.js b/routes/utils/emailCheck.js new file mode 100644 index 0000000..b77b683 --- /dev/null +++ b/routes/utils/emailCheck.js @@ -0,0 +1,28 @@ +let crypto = require("crypto"); +let models = require("../../models"); +let Message = require("emailjs").Message; +let error = require("./error"); + + +module.exports = async (req, res, user, callBack) => { + let token = crypto.randomBytes(16).toString("hex"); + let config = req.app.get("config"); + + while (await models.User.findOne({where: {emailToken: token}})) + token = crypto.randomBytes(16).toString("hex"); + user.emailToken = token; + await user.save(); + + req.app.get("mailClient").send( new Message({ + text: res.__("profile.emailCheckMessage", `${req.protocol}://${req.hostname}/check?token=${token}`), + from: config.email.from, + to: user.email, + subject: res.__("profile.emailCheck") + }), (err, message) => { + if (err) + return error(req, res, "Fail to send message !", 500, + req.app.get("env") !== "production" ? err : undefined); + else + callBack(); + }); +}; diff --git a/routes/utils/userCreate.js b/routes/utils/userCreate.js index 6800e47..745deeb 100644 --- a/routes/utils/userCreate.js +++ b/routes/utils/userCreate.js @@ -1,5 +1,6 @@ let models = require("../../models"); let error = require("../utils/error"); +let emailCheck = require("./emailCheck"); module.exports = async (req, res) => { @@ -38,6 +39,12 @@ module.exports = async (req, res) => { UserUsername: null }})) await c.setUser(user); + + if (!req.app.locals.test) { + new Promise(async done => await emailCheck(req, res, user, done)); + await user.reload(); + } + return user; } catch (e) { error(req, res, "Registration fail !"); diff --git a/views/profile.pug b/views/profile.pug index e743d7c..ee77330 100644 --- a/views/profile.pug +++ b/views/profile.pug @@ -30,6 +30,11 @@ block content each department in departments option(value=department.name) + if (!user.emailVerified) + div.field + a(href="/profile/resend") + input(type="button" value=__("profile.emailCheck")) + div.card#userOrderList h1=__("orders") each order in orders