diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 249104c..1345cde 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -14,7 +14,9 @@ CREATE TABLE user_table ( userid INT AUTO_INCREMENT UNIQUE PRIMARY KEY, username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, - password VARCHAR(140) NOT NULL UNIQUE + password VARCHAR(140) NOT NULL UNIQUE, + otp VARCHAR(6) DEFAULT NULL, + otp_created_at DATETIME DEFAULT NULL ); -- Create the info_table @@ -73,3 +75,15 @@ CREATE TABLE upload_file_db ( FOREIGN KEY (fac_mail) REFERENCES faculty(email) ON DELETE CASCADE, FOREIGN KEY (userid) REFERENCES info_table(id) ON DELETE CASCADE ); + + +DELIMITER // +create event if not exists deleteOTP on schedule every 2 minute +do +begin + DELETE FROM user_table + WHERE otp IS NOT NULL + AND TIMESTAMPDIFF(MINUTE, otp_created_at, NOW()) >= 2; +END // +DELIMITER ; +set global event_scheduler=on; diff --git a/login-system/dbServer.js b/login-system/dbServer.js index 6eb7366..bb37f12 100644 --- a/login-system/dbServer.js +++ b/login-system/dbServer.js @@ -129,7 +129,7 @@ app.post("/login", signin); app.post("/stk_holder_signin", stk_signin); app.post("/fac_login", fac_login); //login for faculty app.post("/sendotp", sendOtp) -app.post("/resetpassword", reset); +app.post("/reset", reset); // approval by stakeholder app.get("/approval", approve); diff --git a/login-system/login.js b/login-system/login.js index f53b5c7..bd07450 100644 --- a/login-system/login.js +++ b/login-system/login.js @@ -50,7 +50,7 @@ const signup = async (req, res) => { return res.status(409).send('Username Already in Use'); } } else { - const sqlInsert = 'INSERT INTO user_table VALUES (0, ?, ?, ?)'; + const sqlInsert = 'INSERT INTO user_table VALUES (0, ?, ?, ?, null, null)'; await connection.query(sqlInsert, [username, email, hashpassword]); console.log('Created a new User'); const sub = 'Signup-Research Nexas'; @@ -119,13 +119,19 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; + // const otpExpiry = result[0].otp_created_at; + if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); } + // At this point, the OTP is valid, and the SQL event will handle expiration. + // Proceed with resetting the password and clearing the OTP. + const hashpassword = await bcrypt.hash(password, 10); - const resetQuery = 'UPDATE user_table SET otp = ?, password = ? WHERE email = ?'; - await connection.query(resetQuery, ['', hashpassword, email]); + const resetQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL, password = ? WHERE email = ?'; + await connection.query(resetQuery, [hashpassword, email]); + console.log('Password reset successfully'); return res.json({ success: true, message: 'Password reset successfully' }); } finally { connection.release(); diff --git a/login-system/otp.js b/login-system/otp.js index 9a63a30..defc520 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -5,6 +5,8 @@ const rateLimit = require('express-rate-limit'); require("dotenv").config(); const db = require('../config/mysql_connection'); const nodemailer = require("nodemailer"); +const otpGenerator = require('otp-generator'); // Import otp-generator + // Connecting to the database using async/await for connection management const connectToDB = async () => { @@ -26,6 +28,7 @@ const sendOtp = async (req, res) => { let connection; try { connection = await connectToDB(); + console.log("Connected to the database"); // Search for the user in the database const sqlSearch = "SELECT * FROM user_table WHERE email = ?"; @@ -38,12 +41,19 @@ const sendOtp = async (req, res) => { } // Generate OTP and save it to the database - const verifyCode = Math.floor(100000 + Math.random() * 900000).toString(); - const otpQuery = "UPDATE user_table SET otp = ? WHERE email = ?"; + const verifyCode = otpGenerator.generate(6, { + upperCaseAlphabets: true, // Include uppercase letters + lowerCaseAlphabets: true, // Include lowercase letters + specialChars: true, // Include special characters + digits: true // Include digits + });; + console.log(verifyCode); + + const otpQuery = "UPDATE user_table SET otp = ?, otp_created_at = CURRENT_TIMESTAMP WHERE email = ?"; await connection.query(otpQuery, [verifyCode, email]); - + // Send OTP via notification (could be an email or any other method) - // notify(req, res, email, "Email Verification", `This is your OTP to verify your email: ${verifyCode}`); + notify(req, res, email, "Email Verification", `This is your OTP to verify your email: ${verifyCode}`); return res.send({ message: "OTP sent successfully" }); diff --git a/package-lock.json b/package-lock.json index 7b25741..f57b573 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "multer": "^1.4.5-lts.1", "mysql2": "^3.12.0", "nodemailer": "^6.9.16", + "otp-generator": "^4.0.1", "sih_project_2": "file:" }, "devDependencies": { @@ -1992,6 +1993,15 @@ "node": ">= 0.8.0" } }, + "node_modules/otp-generator": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/otp-generator/-/otp-generator-4.0.1.tgz", + "integrity": "sha512-2TJ52vUftA0+J3eque4wwVtpaL4/NdIXDL0gFWFJFVUAZwAN7+9tltMhL7GCNYaHJtuONoier8Hayyj4HLbSag==", + "license": "MIT", + "engines": { + "node": ">=14.10.0" + } + }, "node_modules/pac-proxy-agent": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.1.tgz", diff --git a/package.json b/package.json index 7bbc369..a0a6684 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "multer": "^1.4.5-lts.1", "mysql2": "^3.12.0", "nodemailer": "^6.9.16", + "otp-generator": "^4.0.1", "sih_project_2": "file:" }, "devDependencies": { diff --git a/public/password_reset.html b/public/password_reset.html index d647608..50e23dc 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -68,9 +68,11 @@

Enter Invalid email domain. Please use Gmail, Outlook, Yahoo, Protonmail, Icloud, or Tutanota. + - + + @@ -115,9 +117,33 @@

Enter const lowercaseCriteria = document.getElementById("lowercase"); const numberCriteria = document.getElementById("number"); const specialCriteria = document.getElementById("special"); + const otpTimer = document.getElementById('otp-timer'); + const timerElement = document.getElementById('timer'); const allowedDomains = ["gmail.com", "outlook.com", "yahoo.com", "protonmail.com", "icloud.com", "tutanota.com"]; let emailValidated = false; + let timerInterval; + let timeRemaining = 120; // 2 minutes + + // Function to start the OTP timer + function startOtpTimer() { + otpTimer.style.display = 'inline'; // Show the timer + validateEmailBtn.disabled = true; // Disable the "Send Validation Code" button + timerElement.textContent = timeRemaining; // Display the initial timer value + + // Update the timer every second + timerInterval = setInterval(() => { + timeRemaining--; + timerElement.textContent = timeRemaining; + + if (timeRemaining <= 0) { + clearInterval(timerInterval); // Stop the timer when it reaches 0 + validateEmailBtn.disabled = false; // Enable the button + otpTimer.style.display = 'none'; // Hide the timer message + timeRemaining = 120; // Reset the timer + } + }, 1000); + } // Validate email and send code validateEmailBtn.addEventListener('click', async function () { @@ -145,6 +171,9 @@

Enter resetPasswordBtn.disabled = false; alert("A validation code has been sent to your email!"); + // Start the timer + startOtpTimer(); + // Enable validation code input } else { @@ -162,7 +191,7 @@

Enter const password = passwordInput.value; const otp = validationCodeInput.value; - const response = await fetch('/resetpassword', { + const response = await fetch('/reset', { method: 'POST', headers: { 'Content-Type': 'application/json', @@ -173,11 +202,13 @@

Enter console.log(response); if(!response.ok){ - + alert('Otp is invalid'); + console.log('Otp is invalid'); + }else{ + alert('Password reset successfully!'); + console.log('Password reset successfully!'); + window.location.href = 'login.html'; } - - alert('Password reset successfully!'); - window.location.href = 'login.html'; }); // Password criteria validation