Fix file paths and add password reset functionality
This commit is contained in:
parent
12597ad774
commit
fea986a841
@ -2,7 +2,7 @@ const { tokenModel } = require("../database/model/tokenModel.js");
|
|||||||
const { userModel } = require("../database/model/userModel");
|
const { userModel } = require("../database/model/userModel");
|
||||||
const { hash, compareHash } = require("./bcrypt.js");
|
const { hash, compareHash } = require("./bcrypt.js");
|
||||||
const { generateUUID } = require("./generateUUID.js");
|
const { generateUUID } = require("./generateUUID.js");
|
||||||
const { isValid } = require("./isValid");
|
const { isValid , resetIsValid } = require("./isValid");
|
||||||
|
|
||||||
async function getTokenByToken(token) {
|
async function getTokenByToken(token) {
|
||||||
const splitAuthToken = token.split("-");
|
const splitAuthToken = token.split("-");
|
||||||
@ -53,7 +53,7 @@ async function addToken(userId, permission, isKey ,expiry) {
|
|||||||
async function addPasswordResetToken(data , token){
|
async function addPasswordResetToken(data , token){
|
||||||
let hashtoken = await hash(token);
|
let hashtoken = await hash(token);
|
||||||
let currentDate = new Date();
|
let currentDate = new Date();
|
||||||
let tokenToLive = new Date(currentDate.getTime() + 15 * 60000);
|
let tokenToLive = new Date(currentDate.getTime() + 5 * 60000);
|
||||||
|
|
||||||
let tokenRes = await tokenModel.create({
|
let tokenRes = await tokenModel.create({
|
||||||
userid: data.id,
|
userid: data.id,
|
||||||
@ -62,7 +62,7 @@ async function addPasswordResetToken(data , token){
|
|||||||
isKey: "isNotKey",
|
isKey: "isNotKey",
|
||||||
expiration: tokenToLive,
|
expiration: tokenToLive,
|
||||||
});
|
});
|
||||||
return true;
|
return tokenRes.id
|
||||||
}
|
}
|
||||||
|
|
||||||
async function checkToken(id) {
|
async function checkToken(id) {
|
||||||
@ -77,6 +77,31 @@ async function checkToken(id) {
|
|||||||
return tokenRes;
|
return tokenRes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function checkTokenByrowID(token) {
|
||||||
|
if (!token) return false;
|
||||||
|
//split
|
||||||
|
const splitAuthToken = token.split("-");
|
||||||
|
const rowid = splitAuthToken[0];
|
||||||
|
const suppliedToken = splitAuthToken.slice(1).join("-");
|
||||||
|
|
||||||
|
let tokenRes = await tokenModel.findByPk(rowid);
|
||||||
|
//console.log(tokenRes);
|
||||||
|
|
||||||
|
if (!tokenRes) return false;
|
||||||
|
|
||||||
|
if (!compareHash(suppliedToken, tokenRes.token)) return false;
|
||||||
|
|
||||||
|
|
||||||
module.exports = { addToken, getTokenByToken , checkToken , addPasswordResetToken};
|
//pass tokemRes.expiration to isValid
|
||||||
|
if (!isValid(tokenRes.expiration)) {
|
||||||
|
//add boolean to token table
|
||||||
|
tokenRes.destroy();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return tokenRes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { addToken, getTokenByToken , checkToken , addPasswordResetToken , checkTokenByrowID};
|
||||||
|
@ -11,4 +11,16 @@ function isValid(time) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { isValid };
|
//5 minutes
|
||||||
|
function resetIsValid(time) {
|
||||||
|
if (
|
||||||
|
Math.floor(new Date(time).getTime() / 1000) <
|
||||||
|
Math.floor(new Date().getTime() / 1000)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { isValid , resetIsValid };
|
||||||
|
@ -84,7 +84,7 @@ async function sendResetPasswordEmail(email, resetToken) {
|
|||||||
subject: "Reset Password",
|
subject: "Reset Password",
|
||||||
html: `
|
html: `
|
||||||
<h1>Reset Password</h1>
|
<h1>Reset Password</h1>
|
||||||
<p><strong>Reset Password Link:</strong> <a href="localhost/api/v0/auth/resetpassword/${resetToken}">Reset Password Link </p>
|
<p><strong>Reset Password Link:</strong> <a href="localhost/resetpassword/${resetToken}">Reset Password Link </p>
|
||||||
<p><strong>From:</strong> Eco Saver</p>
|
<p><strong>From:</strong> Eco Saver</p>
|
||||||
<p>Kindly click on the link to reset your password!</p>
|
<p>Kindly click on the link to reset your password!</p>
|
||||||
<p>Regards,</p>
|
<p>Regards,</p>
|
||||||
|
@ -163,6 +163,23 @@ async function checkEmailDetails(email) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function resetPass(userid , data ){
|
||||||
|
let hashed = await hash(data.password);
|
||||||
|
let updateUser = await userModel.update(
|
||||||
|
{
|
||||||
|
password: hashed,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
where: {
|
||||||
|
id: userid,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (!updateUser) return false;
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getUserByID,
|
getUserByID,
|
||||||
@ -171,5 +188,7 @@ module.exports = {
|
|||||||
loginUser,
|
loginUser,
|
||||||
updateProfile,
|
updateProfile,
|
||||||
checkEmail,
|
checkEmail,
|
||||||
checkEmailDetails
|
checkEmailDetails,
|
||||||
|
resetPass,
|
||||||
|
|
||||||
};
|
};
|
@ -3,13 +3,17 @@ const {
|
|||||||
loginUser,
|
loginUser,
|
||||||
checkEmail,
|
checkEmail,
|
||||||
checkEmailDetails,
|
checkEmailDetails,
|
||||||
|
resetPass,
|
||||||
} = require("../functions/user");
|
} = require("../functions/user");
|
||||||
const { sendContactEmail } = require("../functions/nodeMail");
|
const { sendContactEmail } = require("../functions/nodeMail");
|
||||||
const { generateUUID } = require("../functions/generateUUID");
|
const { generateUUID } = require("../functions/generateUUID");
|
||||||
const { addPasswordResetToken } = require("../functions/api");
|
const { addPasswordResetToken } = require("../functions/api");
|
||||||
const { sendResetPasswordEmail } = require("../functions/nodeMail");
|
const { sendResetPasswordEmail } = require("../functions/nodeMail");
|
||||||
|
const { checkTokenByrowID } = require("../functions/api");
|
||||||
|
|
||||||
|
|
||||||
const express = require("express");
|
const express = require("express");
|
||||||
|
const { render } = require("ejs");
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
// /user/register
|
// /user/register
|
||||||
@ -91,13 +95,16 @@ router.post("/checkemail", async (req, res, next) => {
|
|||||||
let data = await checkEmailDetails(req.body.email);
|
let data = await checkEmailDetails(req.body.email);
|
||||||
//console.log(data);
|
//console.log(data);
|
||||||
//token generation and insert into token table
|
//token generation and insert into token table
|
||||||
const token = await generateUUID();
|
let token = await generateUUID();
|
||||||
|
|
||||||
let tokenRes = await addPasswordResetToken(data, token);
|
let tokenRes = await addPasswordResetToken(data, token);
|
||||||
|
|
||||||
//email user with temp token link
|
//email user with temp token link
|
||||||
if (!tokenRes) return false;
|
if (!tokenRes) return false;
|
||||||
|
|
||||||
|
//apend table id to token
|
||||||
|
token = tokenRes + "-" + token;
|
||||||
|
|
||||||
//email logic to send reset password link
|
//email logic to send reset password link
|
||||||
sendResetPasswordEmail(req.body.email, token);
|
sendResetPasswordEmail(req.body.email, token);
|
||||||
|
|
||||||
@ -111,15 +118,33 @@ router.post("/checkemail", async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/resetpassword/:token", async (req, res, next) => {
|
|
||||||
//pass token to reset password page
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
//reset password
|
//reset password
|
||||||
router.post("/resetpassword", async (req, res, next) => {
|
router.post("/resetpassword/:token", async (req, res, next) => {
|
||||||
|
console.log(req.body);
|
||||||
|
console.log(req.params.token);
|
||||||
|
|
||||||
|
//if token is valid
|
||||||
|
let tokenRes = await checkTokenByrowID(req.params.token);
|
||||||
|
|
||||||
|
if (!tokenRes) {
|
||||||
|
let error = new Error("Token not found");
|
||||||
|
error.status = 400;
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
//token is valid and reset password
|
||||||
|
else{
|
||||||
|
let Res = await resetPass(tokenRes.userid, req.body);
|
||||||
|
if (!Res) return false;
|
||||||
|
else{
|
||||||
|
res.json({
|
||||||
|
message: "Password reset successfully",
|
||||||
|
});
|
||||||
|
tokenRes.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
const { checkTokenByrowID } = require("../functions/api");
|
||||||
|
|
||||||
var router = require("express").Router();
|
var router = require("express").Router();
|
||||||
|
|
||||||
@ -33,7 +34,7 @@ router.get("/forgotpassword", function (req, res, next) {
|
|||||||
res.render("forgotpassword");
|
res.render("forgotpassword");
|
||||||
});
|
});
|
||||||
|
|
||||||
//resetted password page
|
//resetting password page
|
||||||
router.get("/resetpassword", function (req, res, next) {
|
router.get("/resetpassword", function (req, res, next) {
|
||||||
res.render("resetpassword");
|
res.render("resetpassword");
|
||||||
});
|
});
|
||||||
@ -63,4 +64,31 @@ router.get("/sensor-data", function (req, res, next) {
|
|||||||
res.render("sensor-data");
|
res.render("sensor-data");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//reset password page
|
||||||
|
router.get("/resetpassword/:token", async (req, res, next) => {
|
||||||
|
try{
|
||||||
|
//pass token to reset password page
|
||||||
|
//console.log(req.params.token);
|
||||||
|
|
||||||
|
//check if token is valid
|
||||||
|
let tokenRes = await checkTokenByrowID(req.params.token);
|
||||||
|
|
||||||
|
if (!tokenRes) {
|
||||||
|
let error = new Error("Token not found");
|
||||||
|
error.status = 400;
|
||||||
|
return next(error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let token = req.params.token;
|
||||||
|
console.log(token);
|
||||||
|
res.render("resetpassword", { token: token });
|
||||||
|
}
|
||||||
|
|
||||||
|
}catch(error){
|
||||||
|
console.error(error);
|
||||||
|
next(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
@ -81,7 +81,7 @@
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
<script src="js/search.js"></script>
|
<script src="/js/search.js"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
@ -7,6 +7,8 @@
|
|||||||
<div class="error-contents">
|
<div class="error-contents">
|
||||||
<h3>Please check your email for the reset password link</h3>
|
<h3>Please check your email for the reset password link</h3>
|
||||||
</div>
|
</div>
|
||||||
|
<br>
|
||||||
|
<br>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<a>Dont have an account?</a> <a href="/login">Sign Up</a>
|
<a>Dont have an account?</a> <a href="/login">Sign Up</a>
|
||||||
|
@ -6,14 +6,14 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
<link rel="shortcut icon" type="images/logo.ico" href="images/logo.ico" />
|
<link rel="shortcut icon" type="images/logo.ico" href="/images/logo.ico" />
|
||||||
<!-- Bootstrap core CSS -->
|
<!-- Bootstrap core CSS -->
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
|
||||||
|
|
||||||
|
|
||||||
<!-- Custom styles for this template -->
|
<!-- Custom styles for this template -->
|
||||||
<link rel="stylesheet" href="css/sp.css" />
|
<link rel="stylesheet" href="/css/sp.css" />
|
||||||
|
|
||||||
|
|
||||||
<!-- jQuery library -->
|
<!-- jQuery library -->
|
||||||
@ -30,7 +30,7 @@
|
|||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.min.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.2.0/socket.io.min.js"></script>
|
||||||
|
|
||||||
<!-- jquery app.js -->
|
<!-- jquery app.js -->
|
||||||
<script src="js/app.js"></script>
|
<script src="/js/app.js"></script>
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@ -66,7 +66,7 @@
|
|||||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="/">
|
||||||
<img src="images/logo.png" alt="logo" />
|
<img src="/images/logo.png" alt="logo" />
|
||||||
</a>
|
</a>
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
||||||
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
@ -5,9 +5,12 @@
|
|||||||
<section class="wrapper">
|
<section class="wrapper">
|
||||||
<div class="form">
|
<div class="form">
|
||||||
<header>Reset Password</header>
|
<header>Reset Password</header>
|
||||||
<form action="auth/resetPassword" >
|
<div class="card-header shadow actionMessage" style="display:none"></div>
|
||||||
<input type="password" name="password" placeholder="password" required>
|
<!-- <form action="auth/resetpassword/<%= token.token%>" method="post" onsubmit="formAJAX(this)"> -->
|
||||||
<input type="cpassword" name="cpassword" placeholder="cpassword" required>
|
<form action="auth/resetpassword/<%= token%>" method="post" onsubmit="formAJAX(this)" evalAJAX="app.auth.logInRedirect();">
|
||||||
|
<input type="password" id="password" name="password" placeholder="Password" required />
|
||||||
|
<input type="password" id="confirmPassword" name="confirmPassword" placeholder="Confirm Password"
|
||||||
|
required />
|
||||||
<input type="submit" value="Reset Password" />
|
<input type="submit" value="Reset Password" />
|
||||||
</form>
|
</form>
|
||||||
<br>
|
<br>
|
||||||
@ -15,12 +18,29 @@
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<table class="footer">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<p>© 2024 EcoSaver</p>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
</body>
|
<script>
|
||||||
|
//both password fields must match
|
||||||
|
var password = document.getElementById("password");
|
||||||
|
var confirm_password = document.getElementById("confirmPassword");
|
||||||
|
|
||||||
|
function validatePassword() {
|
||||||
|
var passwordValue = password.value;
|
||||||
|
|
||||||
|
// Strong password regex pattern
|
||||||
|
var strongPasswordPattern = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/;
|
||||||
|
|
||||||
|
if (passwordValue != confirm_password.value) {
|
||||||
|
confirm_password.setCustomValidity("Passwords Don't Match");
|
||||||
|
} else if (!strongPasswordPattern.test(passwordValue)) {
|
||||||
|
confirm_password.setCustomValidity("Password must be at least 8 characters long and include at least one letter, one number, and one special character.");
|
||||||
|
} else {
|
||||||
|
confirm_password.setCustomValidity('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
password.onchange = validatePassword;
|
||||||
|
confirm_password.onkeyup = validatePassword;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
@ -4,7 +4,6 @@
|
|||||||
//app.auth.redirectIfLoggedIn();
|
//app.auth.redirectIfLoggedIn();
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<body>
|
|
||||||
<section class="wrapper">
|
<section class="wrapper">
|
||||||
<div class="form signup iot-card">
|
<div class="form signup iot-card">
|
||||||
<!--<div class="form signup card" -->
|
<!--<div class="form signup card" -->
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
<meta http-equiv="cleartype" content="on" />
|
<meta http-equiv="cleartype" content="on" />
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<link rel="shortcut icon" type="images/logo.ico" href="images/logo.ico" />
|
<link rel="shortcut icon" type="images/logo.ico" href="/images/logo.ico" />
|
||||||
|
|
||||||
|
|
||||||
<!-- Bootstrap core CSS -->
|
<!-- Bootstrap core CSS -->
|
||||||
@ -17,8 +17,8 @@
|
|||||||
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous" />
|
||||||
|
|
||||||
<!-- Custom styles for this template -->
|
<!-- Custom styles for this template -->
|
||||||
<link href="css/all.css" rel="stylesheet" />
|
<link href="/css/all.css" rel="stylesheet" />
|
||||||
<link href="css/style.css" rel="stylesheet" />
|
<link href="/css/style.css" rel="stylesheet" />
|
||||||
<!-- weird api page cdn -->
|
<!-- weird api page cdn -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
@ -46,10 +46,10 @@
|
|||||||
<!-- <script src="https://cdn.jsdelivr.net/npm/jquery.fancytable/dist/fancyTable.min.js"></script> -->
|
<!-- <script src="https://cdn.jsdelivr.net/npm/jquery.fancytable/dist/fancyTable.min.js"></script> -->
|
||||||
|
|
||||||
<!-- jq-repeat -->
|
<!-- jq-repeat -->
|
||||||
<script src="js/jq-repeat.js"></script>
|
<script src="/js/jq-repeat.js"></script>
|
||||||
|
|
||||||
<!-- jquery public app.js -->
|
<!-- jquery public app.js -->
|
||||||
<script src="js/app.js"></script>
|
<script src="/js/app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<!-- javascript function to check if user is auth -->
|
<!-- javascript function to check if user is auth -->
|
||||||
<script>
|
<script>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-light top-nav fixed-top">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<a class="navbar-brand" href="/">
|
<a class="navbar-brand" href="/">
|
||||||
<img src="images/logo.png" alt="logo" />
|
<img src="/images/logo.png" alt="logo" />
|
||||||
</a>
|
</a>
|
||||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarResponsive"
|
||||||
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user