From a8772f7da8a6a57dc691baa0c9a1278f20efdc49 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Wed, 1 Jan 2025 12:15:48 +0530 Subject: [PATCH 01/13] Fix issue #428: Otp column missing issue resolved --- config/dbQuery.sql | 3 ++- login-system/otp.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 249104c..df33e16 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -14,7 +14,8 @@ 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) -- Add the otp column to store OTP values ); -- Create the info_table diff --git a/login-system/otp.js b/login-system/otp.js index 9a63a30..2ff5639 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -26,6 +26,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 = ?"; @@ -43,7 +44,7 @@ const sendOtp = async (req, res) => { 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" }); From 6d95ecf21ee4024a08094b7edea60c90b8850e1b Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Thu, 2 Jan 2025 18:45:20 +0530 Subject: [PATCH 02/13] otp function enhanced --- config/dbQuery.sql | 6 ++++-- login-system/otp.js | 17 ++++++++++++++--- package-lock.json | 10 ++++++++++ package.json | 1 + 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 249104c..c66c69b 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -14,7 +14,8 @@ 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, + ); -- Create the info_table @@ -34,7 +35,8 @@ CREATE TABLE stk_holder ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, col_name VARCHAR(180) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, - password VARCHAR(80) NOT NULL UNIQUE + password VARCHAR(80) NOT NULL UNIQUE, + otp_expiry BIGINT NULL -- Column for storing OTP expiration (Unix timestamp) ); -- Create the criteria table diff --git a/login-system/otp.js b/login-system/otp.js index 9a63a30..6d1ed09 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 () => { @@ -38,9 +40,18 @@ 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 = ?"; - await connection.query(otpQuery, [verifyCode, 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 expirationTime = Date.now() + 2 * 60 * 1000; + + + const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; + await connection.query(otpQuery, [verifyCode,expirationTime, 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}`); 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": { From 3215fa23a9971a5954d1b2b1ba75ba61685c2f17 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Thu, 2 Jan 2025 18:55:38 +0530 Subject: [PATCH 03/13] Insert Query issue resolved --- config/dbQuery.sql | 2 +- login-system/login.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index df33e16..3a9ed01 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -15,7 +15,7 @@ CREATE TABLE user_table ( username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, - otp VARCHAR(6) -- Add the otp column to store OTP values + otp VARCHAR(6) DEFAULT NULL-- Add the otp column to store OTP values ); -- Create the info_table diff --git a/login-system/login.js b/login-system/login.js index f53b5c7..2656f52 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)'; await connection.query(sqlInsert, [username, email, hashpassword]); console.log('Created a new User'); const sub = 'Signup-Research Nexas'; From 8cf956a44696dc6b3fc40b48c7e9d992518c729c Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Fri, 3 Jan 2025 18:50:51 +0530 Subject: [PATCH 04/13] Improves the Otp Genration function --- config/dbQuery.sql | 3 ++- login-system/login.js | 18 ++++++++++++++--- login-system/otp.js | 33 +++++++++++++++++++++++++++++-- public/password_reset.html | 40 +++++++++++++++++++++++++++++++++----- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 6a045dc..6020722 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -15,7 +15,8 @@ CREATE TABLE user_table ( username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, - otp VARCHAR(6) DEFAULT NULL-- Add the otp column to store OTP values + otp VARCHAR(6) DEFAULT NULL,-- Add the otp column to store OTP values + otp_expiry BIGINT DEFAULT NULL -- Column for storing OTP expiration (Unix timestamp) ); -- Create the info_table diff --git a/login-system/login.js b/login-system/login.js index 2656f52..8d81cba 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, ?, ?, ?, null)'; + 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,25 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; + const otpExpiry = result[0].otp_expiry; + if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); } + // Check OTP expiry + if (Date.now() > otpExpiry) { + // Expired: Clear OTP and expiry in the database + const clearOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ?'; + await connection.query(clearOtpQuery, [email]); + + return res.status(400).json({ success: false, message: 'OTP has expired' }); + } + 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 cec15cb..20ebe88 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -30,6 +30,18 @@ const sendOtp = async (req, res) => { connection = await connectToDB(); console.log("Connected to the database"); + // Clear expired OTPs for this user + const clearExpiredOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE otp_expiry < ?'; + await connection.query(clearExpiredOtpQuery, [Date.now()]); + + // // Check if a valid OTP already exists + // const checkExistingOtpQuery = "SELECT otp_expiry FROM user_table WHERE email = ? AND otp_expiry > ?"; + // const [existingOtp] = await connection.query(checkExistingOtpQuery, [email, Date.now()]); + + // if (existingOtp.length > 0) { + // return res.status(400).send({ message: "An OTP is already active. Please wait for it to expire." }); + // } + // Search for the user in the database const sqlSearch = "SELECT * FROM user_table WHERE email = ?"; const [result] = await connection.query(sqlSearch, [email]); @@ -47,13 +59,30 @@ const sendOtp = async (req, res) => { specialChars: true, // Include special characters digits: true // Include digits });; - console.log(verifyCode); - const expirationTime = Date.now() + 2 * 60 * 1000; + console.log(verifyCode); + const expirationTime = Date.now() + 2 * 60 * 1000; // 2 minutes const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; await connection.query(otpQuery, [verifyCode,expirationTime, email]); + // Schedule immediate cleanup after 2 minutes + setTimeout(async () => { + let timeoutConnection; + try { + timeoutConnection = await connectToDB(); + await timeoutConnection.query( + 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ? AND otp_expiry < ?', + [email, Date.now()] + ); + console.log(`Expired OTP cleared for ${email}`); + } catch (err) { + console.error(`Error clearing OTP for ${email}:`, err); + } finally { + if (timeoutConnection) timeoutConnection.release(); + } + }, 2 * 60 * 1000); + // 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}`); diff --git a/public/password_reset.html b/public/password_reset.html index 1f8d3a4..72dc3c2 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -70,6 +70,7 @@

Enter + @@ -115,9 +116,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 +170,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 +190,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 +201,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 From f1e523e21a7bfb703d8104bdec4faff0cefe47b5 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Wed, 8 Jan 2025 21:16:33 +0530 Subject: [PATCH 05/13] OTP function enhancement with SQL events --- config/dbQuery.sql | 18 +++++++++++++++++- login-system/dbServer.js | 2 +- login-system/login.js | 12 +++--------- login-system/otp.js | 35 ++--------------------------------- public/password_reset.html | 3 ++- 5 files changed, 25 insertions(+), 45 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 6020722..4a9b8a2 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -16,7 +16,7 @@ CREATE TABLE user_table ( email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, otp VARCHAR(6) DEFAULT NULL,-- Add the otp column to store OTP values - otp_expiry BIGINT DEFAULT NULL -- Column for storing OTP expiration (Unix timestamp) + otp_created_at TIMESTAMP DEFAULT NULL -- Add timestamp to track OTP creation ); -- Create the info_table @@ -76,3 +76,19 @@ 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 ); + +-- Create a MySQL Event to handle OTP expiration +DELIMITER $$ + +CREATE EVENT IF NOT EXISTS otp_expiry_event +ON SCHEDULE EVERY 1 MINUTE -- Runs every minute +DO +BEGIN + -- Delete expired OTPs (older than 5 minutes) from user_table + DELETE FROM user_table + WHERE otp IS NOT NULL + AND otp_created_at IS NOT NULL + AND TIMESTAMPDIFF(MINUTE, otp_created_at, CURRENT_TIMESTAMP) > 2; +END$$ + +DELIMITER ; \ No newline at end of file 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 8d81cba..cd2576f 100644 --- a/login-system/login.js +++ b/login-system/login.js @@ -119,20 +119,14 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; - const otpExpiry = result[0].otp_expiry; + const otpExpiry = result[0].otp_created_at; if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); } - // Check OTP expiry - if (Date.now() > otpExpiry) { - // Expired: Clear OTP and expiry in the database - const clearOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ?'; - await connection.query(clearOtpQuery, [email]); - - return res.status(400).json({ success: false, message: 'OTP has expired' }); - } + // 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 = NULL, otp_expiry = NULL, password = ? WHERE email = ?'; diff --git a/login-system/otp.js b/login-system/otp.js index 20ebe88..ea849a8 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -30,18 +30,6 @@ const sendOtp = async (req, res) => { connection = await connectToDB(); console.log("Connected to the database"); - // Clear expired OTPs for this user - const clearExpiredOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE otp_expiry < ?'; - await connection.query(clearExpiredOtpQuery, [Date.now()]); - - // // Check if a valid OTP already exists - // const checkExistingOtpQuery = "SELECT otp_expiry FROM user_table WHERE email = ? AND otp_expiry > ?"; - // const [existingOtp] = await connection.query(checkExistingOtpQuery, [email, Date.now()]); - - // if (existingOtp.length > 0) { - // return res.status(400).send({ message: "An OTP is already active. Please wait for it to expire." }); - // } - // Search for the user in the database const sqlSearch = "SELECT * FROM user_table WHERE email = ?"; const [result] = await connection.query(sqlSearch, [email]); @@ -60,28 +48,9 @@ const sendOtp = async (req, res) => { digits: true // Include digits });; console.log(verifyCode); - const expirationTime = Date.now() + 2 * 60 * 1000; // 2 minutes - - const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; - await connection.query(otpQuery, [verifyCode,expirationTime, email]); - - // Schedule immediate cleanup after 2 minutes - setTimeout(async () => { - let timeoutConnection; - try { - timeoutConnection = await connectToDB(); - await timeoutConnection.query( - 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ? AND otp_expiry < ?', - [email, Date.now()] - ); - console.log(`Expired OTP cleared for ${email}`); - } catch (err) { - console.error(`Error clearing OTP for ${email}:`, err); - } finally { - if (timeoutConnection) timeoutConnection.release(); - } - }, 2 * 60 * 1000); + const otpQuery = "UPDATE user_table SET otp = ? 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}`); diff --git a/public/password_reset.html b/public/password_reset.html index 72dc3c2..aa2d042 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -68,10 +68,11 @@

Enter Invalid email domain. Please use Gmail, Outlook, Yahoo, Protonmail, Icloud, or Tutanota. + - + From 21fdee1a99e710529bd79b2f8ca46a968848d76a Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Thu, 2 Jan 2025 18:45:20 +0530 Subject: [PATCH 06/13] otp function enhanced --- config/dbQuery.sql | 3 ++- login-system/otp.js | 17 ++++++++++++++--- package-lock.json | 10 ++++++++++ package.json | 1 + 4 files changed, 27 insertions(+), 4 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 3a9ed01..6a045dc 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -35,7 +35,8 @@ CREATE TABLE stk_holder ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, col_name VARCHAR(180) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, - password VARCHAR(80) NOT NULL UNIQUE + password VARCHAR(80) NOT NULL UNIQUE, + otp_expiry BIGINT NULL -- Column for storing OTP expiration (Unix timestamp) ); -- Create the criteria table diff --git a/login-system/otp.js b/login-system/otp.js index 2ff5639..cec15cb 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 () => { @@ -39,9 +41,18 @@ 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 = ?"; - await connection.query(otpQuery, [verifyCode, 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 expirationTime = Date.now() + 2 * 60 * 1000; + + + const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; + await connection.query(otpQuery, [verifyCode,expirationTime, 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}`); 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": { From 515059ca40770f3a34feada0e34aaace6741e3f2 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Fri, 3 Jan 2025 18:50:51 +0530 Subject: [PATCH 07/13] Improves the Otp Genration function --- config/dbQuery.sql | 3 ++- login-system/login.js | 18 ++++++++++++++--- login-system/otp.js | 33 +++++++++++++++++++++++++++++-- public/password_reset.html | 40 +++++++++++++++++++++++++++++++++----- 4 files changed, 83 insertions(+), 11 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 6a045dc..6020722 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -15,7 +15,8 @@ CREATE TABLE user_table ( username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, - otp VARCHAR(6) DEFAULT NULL-- Add the otp column to store OTP values + otp VARCHAR(6) DEFAULT NULL,-- Add the otp column to store OTP values + otp_expiry BIGINT DEFAULT NULL -- Column for storing OTP expiration (Unix timestamp) ); -- Create the info_table diff --git a/login-system/login.js b/login-system/login.js index 2656f52..8d81cba 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, ?, ?, ?, null)'; + 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,25 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; + const otpExpiry = result[0].otp_expiry; + if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); } + // Check OTP expiry + if (Date.now() > otpExpiry) { + // Expired: Clear OTP and expiry in the database + const clearOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ?'; + await connection.query(clearOtpQuery, [email]); + + return res.status(400).json({ success: false, message: 'OTP has expired' }); + } + 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 cec15cb..20ebe88 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -30,6 +30,18 @@ const sendOtp = async (req, res) => { connection = await connectToDB(); console.log("Connected to the database"); + // Clear expired OTPs for this user + const clearExpiredOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE otp_expiry < ?'; + await connection.query(clearExpiredOtpQuery, [Date.now()]); + + // // Check if a valid OTP already exists + // const checkExistingOtpQuery = "SELECT otp_expiry FROM user_table WHERE email = ? AND otp_expiry > ?"; + // const [existingOtp] = await connection.query(checkExistingOtpQuery, [email, Date.now()]); + + // if (existingOtp.length > 0) { + // return res.status(400).send({ message: "An OTP is already active. Please wait for it to expire." }); + // } + // Search for the user in the database const sqlSearch = "SELECT * FROM user_table WHERE email = ?"; const [result] = await connection.query(sqlSearch, [email]); @@ -47,13 +59,30 @@ const sendOtp = async (req, res) => { specialChars: true, // Include special characters digits: true // Include digits });; - console.log(verifyCode); - const expirationTime = Date.now() + 2 * 60 * 1000; + console.log(verifyCode); + const expirationTime = Date.now() + 2 * 60 * 1000; // 2 minutes const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; await connection.query(otpQuery, [verifyCode,expirationTime, email]); + // Schedule immediate cleanup after 2 minutes + setTimeout(async () => { + let timeoutConnection; + try { + timeoutConnection = await connectToDB(); + await timeoutConnection.query( + 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ? AND otp_expiry < ?', + [email, Date.now()] + ); + console.log(`Expired OTP cleared for ${email}`); + } catch (err) { + console.error(`Error clearing OTP for ${email}:`, err); + } finally { + if (timeoutConnection) timeoutConnection.release(); + } + }, 2 * 60 * 1000); + // 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}`); diff --git a/public/password_reset.html b/public/password_reset.html index 1f8d3a4..72dc3c2 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -70,6 +70,7 @@

Enter + @@ -115,9 +116,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 +170,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 +190,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 +201,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 From 05605f0c9fad5c5a391f76285b33e3be74f8cbb5 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Wed, 8 Jan 2025 21:16:33 +0530 Subject: [PATCH 08/13] OTP function enhancement with SQL events --- config/dbQuery.sql | 18 +++++++++++++++++- login-system/dbServer.js | 2 +- login-system/login.js | 12 +++--------- login-system/otp.js | 35 ++--------------------------------- public/password_reset.html | 3 ++- 5 files changed, 25 insertions(+), 45 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 6020722..4a9b8a2 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -16,7 +16,7 @@ CREATE TABLE user_table ( email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, otp VARCHAR(6) DEFAULT NULL,-- Add the otp column to store OTP values - otp_expiry BIGINT DEFAULT NULL -- Column for storing OTP expiration (Unix timestamp) + otp_created_at TIMESTAMP DEFAULT NULL -- Add timestamp to track OTP creation ); -- Create the info_table @@ -76,3 +76,19 @@ 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 ); + +-- Create a MySQL Event to handle OTP expiration +DELIMITER $$ + +CREATE EVENT IF NOT EXISTS otp_expiry_event +ON SCHEDULE EVERY 1 MINUTE -- Runs every minute +DO +BEGIN + -- Delete expired OTPs (older than 5 minutes) from user_table + DELETE FROM user_table + WHERE otp IS NOT NULL + AND otp_created_at IS NOT NULL + AND TIMESTAMPDIFF(MINUTE, otp_created_at, CURRENT_TIMESTAMP) > 2; +END$$ + +DELIMITER ; \ No newline at end of file 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 8d81cba..cd2576f 100644 --- a/login-system/login.js +++ b/login-system/login.js @@ -119,20 +119,14 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; - const otpExpiry = result[0].otp_expiry; + const otpExpiry = result[0].otp_created_at; if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); } - // Check OTP expiry - if (Date.now() > otpExpiry) { - // Expired: Clear OTP and expiry in the database - const clearOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ?'; - await connection.query(clearOtpQuery, [email]); - - return res.status(400).json({ success: false, message: 'OTP has expired' }); - } + // 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 = NULL, otp_expiry = NULL, password = ? WHERE email = ?'; diff --git a/login-system/otp.js b/login-system/otp.js index 20ebe88..ea849a8 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -30,18 +30,6 @@ const sendOtp = async (req, res) => { connection = await connectToDB(); console.log("Connected to the database"); - // Clear expired OTPs for this user - const clearExpiredOtpQuery = 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE otp_expiry < ?'; - await connection.query(clearExpiredOtpQuery, [Date.now()]); - - // // Check if a valid OTP already exists - // const checkExistingOtpQuery = "SELECT otp_expiry FROM user_table WHERE email = ? AND otp_expiry > ?"; - // const [existingOtp] = await connection.query(checkExistingOtpQuery, [email, Date.now()]); - - // if (existingOtp.length > 0) { - // return res.status(400).send({ message: "An OTP is already active. Please wait for it to expire." }); - // } - // Search for the user in the database const sqlSearch = "SELECT * FROM user_table WHERE email = ?"; const [result] = await connection.query(sqlSearch, [email]); @@ -60,28 +48,9 @@ const sendOtp = async (req, res) => { digits: true // Include digits });; console.log(verifyCode); - const expirationTime = Date.now() + 2 * 60 * 1000; // 2 minutes - - const otpQuery = "UPDATE user_table SET otp = ?, otp_expiry = ? WHERE email = ?"; - await connection.query(otpQuery, [verifyCode,expirationTime, email]); - - // Schedule immediate cleanup after 2 minutes - setTimeout(async () => { - let timeoutConnection; - try { - timeoutConnection = await connectToDB(); - await timeoutConnection.query( - 'UPDATE user_table SET otp = NULL, otp_expiry = NULL WHERE email = ? AND otp_expiry < ?', - [email, Date.now()] - ); - console.log(`Expired OTP cleared for ${email}`); - } catch (err) { - console.error(`Error clearing OTP for ${email}:`, err); - } finally { - if (timeoutConnection) timeoutConnection.release(); - } - }, 2 * 60 * 1000); + const otpQuery = "UPDATE user_table SET otp = ? 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}`); diff --git a/public/password_reset.html b/public/password_reset.html index 72dc3c2..aa2d042 100644 --- a/public/password_reset.html +++ b/public/password_reset.html @@ -68,10 +68,11 @@

Enter Invalid email domain. Please use Gmail, Outlook, Yahoo, Protonmail, Icloud, or Tutanota. + - + From 0c5dd4b1bcbfdca09abf0cb38a5589570ba827ac Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Wed, 8 Jan 2025 21:26:36 +0530 Subject: [PATCH 09/13] Merge Issue resolved --- login-system/login.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/login-system/login.js b/login-system/login.js index cd2576f..bd07450 100644 --- a/login-system/login.js +++ b/login-system/login.js @@ -119,7 +119,7 @@ const reset = async (req, res) => { } const userOtp = result[0].otp; - const otpExpiry = result[0].otp_created_at; + // const otpExpiry = result[0].otp_created_at; if (otp !== userOtp || !userOtp) { return res.status(400).json({ success: false, message: 'Invalid OTP' }); From 410bc2b75e1ca7f2f8f9f1237d682dc2f5d97de5 Mon Sep 17 00:00:00 2001 From: prajwal2431 Date: Wed, 8 Jan 2025 22:13:03 +0530 Subject: [PATCH 10/13] Minor issue --- config/dbQuery.sql | 15 ++++++++------- login-system/otp.js | 2 +- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 4a9b8a2..076e1d5 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -77,18 +77,19 @@ CREATE TABLE upload_file_db ( FOREIGN KEY (userid) REFERENCES info_table(id) ON DELETE CASCADE ); --- Create a MySQL Event to handle OTP expiration + DELIMITER $$ CREATE EVENT IF NOT EXISTS otp_expiry_event -ON SCHEDULE EVERY 1 MINUTE -- Runs every minute +ON SCHEDULE EVERY 1 MINUTE DO BEGIN - -- Delete expired OTPs (older than 5 minutes) from user_table - DELETE FROM user_table - WHERE otp IS NOT NULL - AND otp_created_at IS NOT NULL - AND TIMESTAMPDIFF(MINUTE, otp_created_at, CURRENT_TIMESTAMP) > 2; + -- Set OTP to NULL if it is older than 2 minutes + UPDATE user_table + SET otp = NULL, + otp_created_at = NULL + WHERE otp IS NOT NULL + AND TIMESTAMPDIFF(MINUTE, otp_created_at, CURRENT_TIMESTAMP) > 2; END$$ DELIMITER ; \ No newline at end of file diff --git a/login-system/otp.js b/login-system/otp.js index ea849a8..defc520 100644 --- a/login-system/otp.js +++ b/login-system/otp.js @@ -49,7 +49,7 @@ const sendOtp = async (req, res) => { });; console.log(verifyCode); - const otpQuery = "UPDATE user_table SET otp = ? WHERE email = ?"; + 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) From bc3cbac134b6e1f8522fe79058b8ca3d2e29b94d Mon Sep 17 00:00:00 2001 From: Harsh Dev Pathak <118347330+Harshdev098@users.noreply.github.com> Date: Sat, 11 Jan 2025 22:09:21 +0530 Subject: [PATCH 11/13] Update dbQuery.sql --- config/dbQuery.sql | 29 +++++++++++------------------ 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 076e1d5..21ef509 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -15,8 +15,7 @@ CREATE TABLE user_table ( username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, - otp VARCHAR(6) DEFAULT NULL,-- Add the otp column to store OTP values - otp_created_at TIMESTAMP DEFAULT NULL -- Add timestamp to track OTP creation + otp VARCHAR(6) DEFAULT NULL ); -- Create the info_table @@ -36,8 +35,7 @@ CREATE TABLE stk_holder ( id INT NOT NULL AUTO_INCREMENT PRIMARY KEY, col_name VARCHAR(180) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, - password VARCHAR(80) NOT NULL UNIQUE, - otp_expiry BIGINT NULL -- Column for storing OTP expiration (Unix timestamp) + password VARCHAR(80) NOT NULL UNIQUE ); -- Create the criteria table @@ -78,18 +76,13 @@ CREATE TABLE upload_file_db ( ); -DELIMITER $$ - -CREATE EVENT IF NOT EXISTS otp_expiry_event -ON SCHEDULE EVERY 1 MINUTE -DO -BEGIN - -- Set OTP to NULL if it is older than 2 minutes - UPDATE user_table - SET otp = NULL, - otp_created_at = NULL +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, CURRENT_TIMESTAMP) > 2; -END$$ - -DELIMITER ; \ No newline at end of file + AND TIMESTAMPDIFF(MINUTE, otp_generated_time, NOW()) >= 2; +END // +DELIMITER ; +set global event_scheduler=on; From 974346d74239bc752597304b02b1d677072f22f9 Mon Sep 17 00:00:00 2001 From: Harsh Dev Pathak <118347330+Harshdev098@users.noreply.github.com> Date: Sun, 12 Jan 2025 23:40:43 +0530 Subject: [PATCH 12/13] Update dbQuery.sql --- config/dbQuery.sql | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index 21ef509..f641bcd 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -15,7 +15,8 @@ CREATE TABLE user_table ( username VARCHAR(60) NOT NULL, email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, - otp VARCHAR(6) DEFAULT NULL + otp VARCHAR(6) DEFAULT NULL, + otp_created_at DATETIME ); -- Create the info_table @@ -82,7 +83,7 @@ do begin DELETE FROM user_table WHERE otp IS NOT NULL - AND TIMESTAMPDIFF(MINUTE, otp_generated_time, NOW()) >= 2; + AND TIMESTAMPDIFF(MINUTE, otp_created_at, NOW()) >= 2; END // DELIMITER ; set global event_scheduler=on; From ba2eee085101ae206baee56f5f7da5abfe14af2d Mon Sep 17 00:00:00 2001 From: Harsh Dev Pathak <118347330+Harshdev098@users.noreply.github.com> Date: Sun, 12 Jan 2025 23:41:20 +0530 Subject: [PATCH 13/13] Update dbQuery.sql --- config/dbQuery.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/dbQuery.sql b/config/dbQuery.sql index f641bcd..1345cde 100644 --- a/config/dbQuery.sql +++ b/config/dbQuery.sql @@ -16,7 +16,7 @@ CREATE TABLE user_table ( email VARCHAR(80) NOT NULL UNIQUE, password VARCHAR(140) NOT NULL UNIQUE, otp VARCHAR(6) DEFAULT NULL, - otp_created_at DATETIME + otp_created_at DATETIME DEFAULT NULL ); -- Create the info_table