Add forget password management
This commit is contained in:
parent
2ee3d87f5a
commit
2e2513f533
8 changed files with 124 additions and 14 deletions
2
app.js
2
app.js
|
@ -11,6 +11,7 @@ let config = process.env.NODE_ENV === "test" ? {} : require("./config/config.jso
|
||||||
let indexRouter = require("./routes/index");
|
let indexRouter = require("./routes/index");
|
||||||
let registerRouter = require("./routes/register");
|
let registerRouter = require("./routes/register");
|
||||||
let loginRouter = require("./routes/login");
|
let loginRouter = require("./routes/login");
|
||||||
|
let forgetRouter = require("./routes/forget");
|
||||||
let logoutRouter = require("./routes/logout");
|
let logoutRouter = require("./routes/logout");
|
||||||
let orderRouter = require("./routes/order");
|
let orderRouter = require("./routes/order");
|
||||||
let ordersRouter = require("./routes/orders");
|
let ordersRouter = require("./routes/orders");
|
||||||
|
@ -66,6 +67,7 @@ app.use((req, res, next) => {
|
||||||
app.use("/", indexRouter);
|
app.use("/", indexRouter);
|
||||||
app.use("/register", registerRouter);
|
app.use("/register", registerRouter);
|
||||||
app.use("/login", loginRouter);
|
app.use("/login", loginRouter);
|
||||||
|
app.use("/forget", forgetRouter);
|
||||||
app.use("/logout", logoutRouter);
|
app.use("/logout", logoutRouter);
|
||||||
app.use("/order", orderRouter);
|
app.use("/order", orderRouter);
|
||||||
app.use("/orders", ordersRouter);
|
app.use("/orders", ordersRouter);
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
"title": "Profile",
|
"title": "Profile",
|
||||||
"infos": "Infos",
|
"infos": "Infos",
|
||||||
"emailCheck": "Email verification",
|
"emailCheck": "Email verification",
|
||||||
"emailCheckMessage": "We need to validate your email address, please click on the link below to validate it\n\n%s"
|
"emailCheckMessage": "We need to validate your email address, please click on the link below to validate it\n\n%s",
|
||||||
|
"forgetPasswordMessage": "A request to change your password has been made on your account, if it comes from clicking on the link below, otherwise ignore this email.\n\n%s"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Administration",
|
"title": "Administration",
|
||||||
|
@ -79,5 +80,6 @@
|
||||||
"save": "Save",
|
"save": "Save",
|
||||||
"sandwich": "Sandwich",
|
"sandwich": "Sandwich",
|
||||||
"contact": "Contact",
|
"contact": "Contact",
|
||||||
"messageSend": "The message has been sent"
|
"messageSend": "The message has been sent",
|
||||||
|
"forgetPassword": "Forgot your password"
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,8 @@
|
||||||
"title": "Profil",
|
"title": "Profil",
|
||||||
"infos": "Infos",
|
"infos": "Infos",
|
||||||
"emailCheck": "Vérification e-mail",
|
"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"
|
"emailCheckMessage": "Nous avons besoin de valider votre adresse email, merci de clicker sur le lien si dessous pour la valider.\n\n%s",
|
||||||
|
"forgetPasswordMessage": "Une demande de changement de mot de passe a été faite sur votre compte, si cela proviens bine de vous clicquer sur le lien ci-dessous, sinon ingorer cette email.\n\n%s"
|
||||||
},
|
},
|
||||||
"admin": {
|
"admin": {
|
||||||
"title": "Administration",
|
"title": "Administration",
|
||||||
|
@ -79,5 +80,7 @@
|
||||||
"save": "Enregistrer",
|
"save": "Enregistrer",
|
||||||
"sandwich": "Sandwich",
|
"sandwich": "Sandwich",
|
||||||
"contact": "Contact",
|
"contact": "Contact",
|
||||||
"messageSend": "Le message a bien été envoyé"
|
"messageSend": "Le message a bien été envoyé",
|
||||||
|
"forgetPassword": "Mot de passe oublié",
|
||||||
|
"send": "send"
|
||||||
}
|
}
|
|
@ -60,6 +60,13 @@ module.exports = (sequelize, DataTypes) => {
|
||||||
digest("base64"));
|
digest("base64"));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
passwordToken: {
|
||||||
|
type: DataTypes.STRING,
|
||||||
|
unique: true
|
||||||
|
},
|
||||||
|
passwordTokenDate: {
|
||||||
|
type: DataTypes.DATE
|
||||||
|
},
|
||||||
permissions: { // 1 = sandwich page, 2 = order page, 3 = admin
|
permissions: { // 1 = sandwich page, 2 = order page, 3 = admin
|
||||||
type: DataTypes.INTEGER,
|
type: DataTypes.INTEGER,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
|
|
71
routes/forget.js
Normal file
71
routes/forget.js
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
const express = require("express");
|
||||||
|
const router = express.Router();
|
||||||
|
const error = require("./utils/error");
|
||||||
|
const models = require("../models");
|
||||||
|
const crypto = require("crypto");
|
||||||
|
const Message = require("emailjs").Message;
|
||||||
|
|
||||||
|
|
||||||
|
async function checkToken(req, res, token) {
|
||||||
|
let user = await models.User.findOne({where: {passwordToken: token}});
|
||||||
|
if (!user)
|
||||||
|
return error(req, res, "Can't reset password", 400, "Invalid token");
|
||||||
|
else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime())/1000 > 3600))
|
||||||
|
return error(req, res, "Can't reset password", 400, "Token expired");
|
||||||
|
else
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
router.get("/", async (req, res) => {
|
||||||
|
if (req.session.user)
|
||||||
|
res.redirect("/");
|
||||||
|
else
|
||||||
|
if (!req.query.token)
|
||||||
|
res.render("forget", {title: "SOD - Forget password"});
|
||||||
|
else {
|
||||||
|
if (await checkToken(req, res, req.query.token))
|
||||||
|
res.render("forget", {title: "SOD - Change password", token: req.query.token})
|
||||||
|
}
|
||||||
|
}).post("/", async (req, res) => {
|
||||||
|
if (req.body.email && !req.body.password && !req.body.token) {
|
||||||
|
let user = await models.User.findOne({where: {email: req.body.email}});
|
||||||
|
let config = req.app.get("config");
|
||||||
|
|
||||||
|
if (!user)
|
||||||
|
return error(req, res, "Can't reset password", 400, "Invalid email");
|
||||||
|
|
||||||
|
let token = crypto.randomBytes(16).toString("hex");
|
||||||
|
while (await models.User.findOne({where: {passwordToken: token}}))
|
||||||
|
token = crypto.randomBytes(16).toString("hex");
|
||||||
|
|
||||||
|
req.app.get("mailClient").send( new Message({
|
||||||
|
text: res.__("profile.forgetPasswordMessage", `${req.protocol}://${req.hostname}/forget?token=${token}`),
|
||||||
|
from: config.email.from,
|
||||||
|
to: user.email,
|
||||||
|
subject: res.__("forgetPassword")
|
||||||
|
}), async (err, message) => {
|
||||||
|
if (err)
|
||||||
|
return error(req, res, "Fail to send message !", 500,
|
||||||
|
req.app.get("env") !== "production" ? err : undefined);
|
||||||
|
else {
|
||||||
|
user.passwordToken = token;
|
||||||
|
user.passwordTokenDate = new Date();
|
||||||
|
await user.save();
|
||||||
|
res.redirect("/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else if (req.body.password && req.body.token && !req.body.email) {
|
||||||
|
let user = await checkToken(res, res, req.body.token);
|
||||||
|
if (user) {
|
||||||
|
user.passwordToken = null;
|
||||||
|
user.passwordTokenDate = null;
|
||||||
|
user.passwordHash = req.body.password;
|
||||||
|
await user.save();
|
||||||
|
res.redirect("/login");
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
return error(req, res, "Can't change password", 400, "Invalid args");
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
20
views/forget.pug
Normal file
20
views/forget.pug
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
extends layout
|
||||||
|
|
||||||
|
block content
|
||||||
|
div.card
|
||||||
|
h1=__("forgetPassword")
|
||||||
|
if (!token)
|
||||||
|
form(action="/forget" method="POST")
|
||||||
|
div.field
|
||||||
|
label(for="email")=__("email")
|
||||||
|
input#email(type="email" name="email" required)
|
||||||
|
div.field
|
||||||
|
+submit(value=__("send"))
|
||||||
|
else
|
||||||
|
form(action="/forget" method="POST")
|
||||||
|
input(type="hidden" name="token" value=token)
|
||||||
|
div.field
|
||||||
|
label(for="password")=__("password")
|
||||||
|
input#password(type="password" name="password" required)
|
||||||
|
div.field
|
||||||
|
+submit(value=__("send"))
|
|
@ -88,7 +88,7 @@ html
|
||||||
label(for="messageContact")=__("layout.message")
|
label(for="messageContact")=__("layout.message")
|
||||||
textarea#messageContact(name="message" required)
|
textarea#messageContact(name="message" required)
|
||||||
div.field
|
div.field
|
||||||
+submit(value=__("layout.send"))
|
+submit(value=__("send"))
|
||||||
|
|
||||||
script(src="/javascripts/layout.js")
|
script(src="/javascripts/layout.js")
|
||||||
if !test
|
if !test
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
extends layout
|
extends layout
|
||||||
|
|
||||||
block content
|
block content
|
||||||
form.card(action="/login" method="POST")
|
div.card
|
||||||
h1=__("login.title")
|
form(action="/login" method="POST")
|
||||||
|
h1=__("login.title")
|
||||||
|
div.field
|
||||||
|
label(for="username")=__("username")+":"
|
||||||
|
input#username(type="text" name="username" required)
|
||||||
|
div.field
|
||||||
|
label(for="password")=__("password")+":"
|
||||||
|
input#password(type="password" name="password" required)
|
||||||
|
div.field
|
||||||
|
+submit(value=__("login.submit"))
|
||||||
|
|
||||||
div.field
|
div.field
|
||||||
label(for="username")=__("username")+":"
|
a(href="/forget")
|
||||||
input#username(type="text" name="username" required)
|
input(type="button" value=__("forgetPassword"))
|
||||||
div.field
|
|
||||||
label(for="password")=__("password")+":"
|
|
||||||
input#password(type="password" name="password" required)
|
|
||||||
div.field
|
|
||||||
+submit(value=__("login.submit"))
|
|
||||||
|
|
Reference in a new issue