diff --git a/models/user.js b/models/user.js index d84a83c..82657b0 100644 --- a/models/user.js +++ b/models/user.js @@ -57,6 +57,13 @@ module.exports = (sequelize, DataTypes) => { this.setDataValue("passwordHash", hash(value, this.email)); } }, + passwordToken: { + type: DataTypes.STRING, + unique: true + }, + passwordTokenDate: { + type: DataTypes.DATE + }, permissions: { type: DataTypes.INTEGER, defaultValue: 0, diff --git a/routes/email.js b/routes/email.js index 6ff63fd..0597f15 100644 --- a/routes/email.js +++ b/routes/email.js @@ -2,11 +2,13 @@ const express = require("express"); const router = express.Router(); const models = require("../models"); const error = require("./utils/error"); +const sessionCheck = require("./utils/sessionCheck"); + router.get("/check", async (req, res) => { if (!req.query.token) return error(req, res, "Missing argument", 400); - let user = await models.User.findOne({where: {"emailToken": req.query.token}}); + let user = await models.User.findOne({where: {emailToken: req.query.token}}); if (user) { user.emailVerified = true; if (user.email.endsWith("@etu.univ-lyon1.fr")) @@ -16,8 +18,21 @@ router.get("/check", async (req, res) => { await user.save(); res.redirect("/"); } else - return error(req, res, "Invalid token", 4000); + return error(req, res, "Invalid token", 400); }); +router.get("/forget", sessionCheck(-1), async (req, res) => { + if (!req.query.token) + res.render("forget", {title: "L'ETU"}); + else { + let user = await models.User.findOne({where: {passwordToken: data.token}}); + if (!user) + return error(req, res, "Invalid token", 400); + else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600)) + return error(req, res, "Token expired", 400); + else + res.render("forget", {title: "L'ETU - Forget password"}); + } +}); module.exports = router; diff --git a/routes/login.js b/routes/login.js index 0c34534..cb6319a 100644 --- a/routes/login.js +++ b/routes/login.js @@ -1,7 +1,8 @@ let express = require("express"); let router = express.Router(); +const sessionCheck = require("./utils/sessionCheck"); -router.get("/", (req, res) => { +router.get("/",sessionCheck(-1), (req, res) => { res.render("login", { title: "L'ETU" }); }); diff --git a/routes/utils/sessionCheck.js b/routes/utils/sessionCheck.js index a85ad8f..7d5d7c9 100644 --- a/routes/utils/sessionCheck.js +++ b/routes/utils/sessionCheck.js @@ -2,12 +2,14 @@ let error = require("./error"); function sessionCheck(permission) { return (req, res, next) => { - if (!req.session.user) { + if (permission === -1 && req.session.user) { + res.redirect(req.session.lastUrl); + } if (!req.session.user) { req.session.lastUrl = req.originalUrl; req.session.save(() => res.redirect("/login")); - } else if (req.session.user.permissions < permission) + } else if (req.session.user.permissions < permission) { return error(req, res, "Permission denied !", 403); - else + } else next(); } } diff --git a/sockets/email/checkResend.js b/sockets/email/checkResend.js index c6004cb..07d85c5 100644 --- a/sockets/email/checkResend.js +++ b/sockets/email/checkResend.js @@ -1,9 +1,9 @@ -const modules = require("../../models"); +const models = require("../../models"); const emailCheck = require("../utils/emailCheck"); module.exports = socket => { return async (data) => { - let user = await modules.User.findByPk(data.email); + let user = await models.User.findByPk(data.email); if (!user) socket.emit("checkResend", {error: {message: "not_found"}}); else if (user.emailVerified) diff --git a/sockets/email/forgotPassword.js b/sockets/email/forgotPassword.js new file mode 100644 index 0000000..d415c15 --- /dev/null +++ b/sockets/email/forgotPassword.js @@ -0,0 +1,13 @@ +const models = require("../../models"); +const emailPassword = require("../utils/emailPassword"); + + +module.exports = socket => { + return async (data) => { + let user = await models.User.findByPk(data.email); + if (!user) + socket.emit("forgotPassword", {error: {message: "not_found"}}); + else + await emailPassword(socket, user, null); + } +} diff --git a/sockets/email/setPassword.js b/sockets/email/setPassword.js new file mode 100644 index 0000000..809de18 --- /dev/null +++ b/sockets/email/setPassword.js @@ -0,0 +1,19 @@ +const models = require("../../models"); + + +module.exports = socket => { + return async (data) => { + let user = await models.User.findOne({where: {passwordToken: data.token}}); + if (!user) + socket.emit("setPassword", {error: {message: "invalid_token"}}) + else if (user.passwordTokenDate && ((new Date().getTime() - user.passwordTokenDate.getTime()) / 1000 > 3600)) + socket.emit("setPassword", {error: {message: "expired_token"}}); + else { + user.passwordToken = null; + user.passwordTokenDate = null; + user.passwordHash = data.password; + await user.save(); + socket.emit("setPassword", true); + } + } +} diff --git a/sockets/index.js b/sockets/index.js index c4b3d28..ff1a0c6 100644 --- a/sockets/index.js +++ b/sockets/index.js @@ -1,6 +1,13 @@ module.exports = socket => { console.log("New connection !"); - socket.on("login", require("./login")(socket)); - socket.on("register", require("./register")(socket)); + if (!socket.request.session.user) { + socket.on("login", require("./login")(socket)); + socket.on("register", require("./register")(socket)); + socket.on("checkResend", require("./email/checkResend")(socket)); + socket.on("forgotPassword", require("./email/forgotPassword")(socket)); + socket.on("setPassword", require("./email/setPassword")(socket)); + } else { + socket.on("profileEdit", require("./profile/edit")(socket)); + } socket.emit("connected"); } diff --git a/sockets/login.js b/sockets/login.js index 67e01a1..e1a7341 100644 --- a/sockets/login.js +++ b/sockets/login.js @@ -1,8 +1,8 @@ -const modules = require("../models"); +const models = require("../models"); module.exports = socket => { return async (data) => { - let user = await modules.User.findByPk(data.email); + let user = await models.User.findByPk(data.email); if (!user) socket.emit("login", {error: {message: "not_found"}}); else if (!user.checkPassword(data.password)) diff --git a/sockets/profile/edit.js b/sockets/profile/edit.js new file mode 100644 index 0000000..36d3f2f --- /dev/null +++ b/sockets/profile/edit.js @@ -0,0 +1,22 @@ +const models = require("../../models"); + +module.exports = socket => { + return async (data) => { + let user = await models.User.findByPk(data.email); + if (!user) + socket.emit("profileEdit", {error: {message: "not_found"}}); + else if (!user.checkPassword(data.oldPassword)) + socket.emit("profileEdit", {error: {message: "invalid_password"}}) + else { + if (data.firstName !== user.firstName) + user.firstName = data.firstName; + if (data.lastName !== user.lastName) + user.lastName = data.lastName; + if (data.password && !user.checkPassword(data.password)) + user.passwordHash = data.password + socket.request.session.user = user; + socket.request.session.save(); + socket.emit("profileEdit", user) + } + } +} diff --git a/sockets/register.js b/sockets/register.js index c051f4b..bcbf398 100644 --- a/sockets/register.js +++ b/sockets/register.js @@ -1,9 +1,9 @@ -const modules = require("../models"); +const models = require("../models"); const emailCheck = require("./utils/emailCheck"); module.exports = socket => { return async (data) => { - if (await modules.User.findByPk(data.email)) + if (await models.User.findByPk(data.email)) socket.emit("register", {error: {message: "email_used"}}); else if ((!data.email.endsWith("@univ-lyon1.fr")) && (!data.email.endsWith("@etu.univ-lyon1.fr"))) socket.emit("register", {error: {message: "invalid_email"}}); diff --git a/sockets/utils/emailPassword.js b/sockets/utils/emailPassword.js new file mode 100644 index 0000000..3bc7132 --- /dev/null +++ b/sockets/utils/emailPassword.js @@ -0,0 +1,27 @@ +let crypto = require("crypto"); +let models = require("../../models"); +let Message = require("emailjs").Message; +const config = require("../../config/config.json"); + + +module.exports = async (socket, user, callBack) => { + let token = crypto.randomBytes(16).toString("hex"); + while (await models.User.findOne({where: {passwordToken: token}})) + token = crypto.randomBytes(16).toString("hex"); + + socket.server.mailClient.send( new Message({ + text: `${config.email.mailPath}/email/forget?token=${token}`, + from: config.email.from, + to: user.email, + subject: "forgot password" + }), async (err, message) => { + if (err) + socket.emit("forgotPassword", {error: {message: "fail_send_mail"}}) + else { + user.passwordToken = token; + user.passwordTokenDate = new Date(); + await user.save(); + socket.emit("forgotPassword", true); + } + }); +};