From a122882764175d69e9d8899776385d2ac611a713 Mon Sep 17 00:00:00 2001 From: asif Date: Thu, 11 Sep 2025 12:07:44 +0530 Subject: [PATCH] added setting password feature fo migrated users --- src/controllers/auth.controller.js | 56 ++++++++++---- src/controllers/otp.controller.js | 113 ++++++++++++++++++++++++++--- src/routes/otp.route.js | 7 +- src/services/auth.service.js | 25 ++++--- 4 files changed, 165 insertions(+), 36 deletions(-) diff --git a/src/controllers/auth.controller.js b/src/controllers/auth.controller.js index 44e874b..ee1c7d4 100644 --- a/src/controllers/auth.controller.js +++ b/src/controllers/auth.controller.js @@ -2,7 +2,7 @@ const authService = require('../services/auth.service'); const { generateToken } = require('../util/jwt'); const { logger } = require('../util/logger'); const db = require('../config/db'); -const dayjs = require("dayjs"); +const dayjs = require('dayjs'); const { comparePassword } = require('../util/hash'); async function login(req, res) { @@ -15,17 +15,21 @@ async function login(req, res) { } const currentTime = new Date().toISOString(); try { + const isMigratedUser = await authService.isMigratedUser(customerNo); + if (isMigratedUser) + return res.status(401).json({ error: 'MIGRATED_USER_HAS_NO_PASSWORD' }); const user = await authService.validateUser(customerNo, password); if (!user || !password) return res.status(401).json({ error: 'INVALID_CREDENTIALS' }); - if (user?.password_hash === 'o') - return res.status(401).json({ error: 'MIGRATED_USER_HAS_NO_PASSWORD' }); + const FirstTimeLogin = await authService.CheckFirstTimeLogin(customerNo); // For registration : if try to login first time after 7 days. - if (FirstTimeLogin && dayjs(user.created_at).diff(currentTime, "day") > 8) - return res.status(401).json({ error: 'Password Expired.Please Contact with Administrator' }); + if (FirstTimeLogin && dayjs(user.created_at).diff(currentTime, 'day') > 8) + return res + .status(401) + .json({ error: 'Password Expired.Please Contact with Administrator' }); - const token = generateToken(user.customer_no, '9d'); + const token = generateToken(user.customer_no); const loginPswExpiry = user.password_hash_expiry; const rights = { ibAccess: user.ib_access_level, @@ -124,12 +128,21 @@ async function changeLoginPassword(req, res) { const { OldLPsw, newLPsw, confirmLPsw } = req.body; const isMatch = await comparePassword(OldLPsw, user.password_hash); if (!isMatch) - return res.status(500).json({ error: 'Please Enter Correct Old Login Password' }); + return res + .status(500) + .json({ error: 'Please Enter Correct Old Login Password' }); if (newLPsw !== confirmLPsw) - return res.status(500).json({ error: 'New Password and Confirm Password not Match' }) - const isMatchWithOldPassword = await comparePassword(newLPsw, user.password_hash); + return res + .status(500) + .json({ error: 'New Password and Confirm Password not Match' }); + const isMatchWithOldPassword = await comparePassword( + newLPsw, + user.password_hash + ); if (isMatchWithOldPassword) - return res.status(500).json({ error: 'New Password will be different from Previous Password' }) + return res.status(500).json({ + error: 'New Password will be different from Previous Password', + }); authService.changeLoginPassword(customerNo, newLPsw); return res.json({ message: 'New Login Password changed successfully' }); } catch (error) { @@ -146,14 +159,27 @@ async function changeTransPassword(req, res) { const { OldTPsw, newTPsw, confirmTPsw } = req.body; const isMatch = await comparePassword(OldTPsw, user.transaction_password); if (!isMatch) - return res.status(500).json({ error: 'Please Enter Correct Old Transaction Password' }); + return res + .status(500) + .json({ error: 'Please Enter Correct Old Transaction Password' }); if (newTPsw !== confirmTPsw) - return res.status(500).json({ error: 'New Transaction Password and Confirm Transaction Password not Match' }) - const isMatchWithOldPassword = await comparePassword(newTPsw, user.transaction_password); + return res.status(500).json({ + error: + 'New Transaction Password and Confirm Transaction Password not Match', + }); + const isMatchWithOldPassword = await comparePassword( + newTPsw, + user.transaction_password + ); if (isMatchWithOldPassword) - return res.status(500).json({ error: 'New Transaction Password will be different from Previous Transaction Password' }) + return res.status(500).json({ + error: + 'New Transaction Password will be different from Previous Transaction Password', + }); authService.changeTransPassword(customerNo, newTPsw); - return res.json({ message: 'New Transaction Password changed successfully' }); + return res.json({ + message: 'New Transaction Password changed successfully', + }); } catch (error) { logger.error(error); return res.status(500).json({ error: 'SOMETHING_WENT_WRONG' }); diff --git a/src/controllers/otp.controller.js b/src/controllers/otp.controller.js index c885d50..acc3687 100644 --- a/src/controllers/otp.controller.js +++ b/src/controllers/otp.controller.js @@ -1,16 +1,31 @@ - const { setJson, getJson } = require('../config/redis'); const { generateOTP } = require('../otpgenerator'); +const { generateToken } = require('../util/jwt'); +const authService = require('../services/auth.service.js'); +const customerController = require('../controllers/customer_details.controller.js'); const { logger } = require('../util/logger'); const axios = require('axios'); const templates = require('../util/sms_template'); // Send OTP async function SendOtp(req, res) { - const { mobileNumber, type, amount, beneficiary, ifsc, acctFrom, acctTo, ref, date, userOtp } = req.body; + const { + mobileNumber, + type, + amount, + beneficiary, + ifsc, + acctFrom, + acctTo, + ref, + date, + userOtp, + } = req.body; if (!mobileNumber || !type) { - return res.status(400).json({ error: 'Mobile number and type are required' }); + return res + .status(400) + .json({ error: 'Mobile number and type are required' }); } try { @@ -71,10 +86,13 @@ async function SendOtp(req, res) { } // Call SMS API - const response = await axios.post('http://localhost:9999/api/SendtoMessage', { - mobileNumber, - stMessage: message, - }); + const response = await axios.post( + 'http://localhost:9999/api/SendtoMessage', + { + mobileNumber, + stMessage: message, + } + ); if (response.data) { // Save OTP only if it's OTP based (skip notifications without OTP) @@ -86,18 +104,16 @@ async function SendOtp(req, res) { } return res.status(200).json({ message: 'Message sent successfully' }); - } catch (err) { logger.error(err, 'Error sending OTP'); return res.status(500).json({ error: 'Internal server error' }); } } - // Verify OTP async function VerifyOtp(req, res) { const { mobileNumber } = req.query; - const { otp } = req.body + const { otp } = req.body; if (!mobileNumber || !otp) { return res.status(400).json({ error: 'Phone number and OTP are required' }); @@ -121,4 +137,79 @@ async function VerifyOtp(req, res) { } } -module.exports = { SendOtp, VerifyOtp }; +async function sendForSetPassword(req, res) { + try { + const { customerNo } = req.query; + if (!customerNo) + return res.status(400).json({ error: 'CUSTOMER_NO_REQUIRED' }); + // check if user is registered for in mobile banking data + const user = await authService.findUserByCustomerNo(customerNo); + if (!user) return res.status(404).json({ error: 'USER_NOT_FOUND' }); + // if present then get his phone number from CBS + const userDetails = await customerController.getDetails(customerNo); + const singleUserDetail = userDetails[0]; + singleUserDetail.mobileno = '7004774978'; + if (!singleUserDetail?.mobileno) + return res.status(400).json({ error: 'USER_PHONE_NOT_FOUND' }); + + const mobileNumber = singleUserDetail.mobileno; + const otp = generateOTP(6); + const message = templates.CHANGE_LPWORD(otp); + const response = await axios.post( + 'http://localhost:9999/api/SendtoMessage', + { + mobileNumber, + stMessage: message, + } + ); + await setJson(`otp:${mobileNumber}`, otp, 300); + return res.status(200).json({ message: 'OTP_SENT' }); + } catch (err) { + logger.error(err, 'Error sending OTP'); + return res.status(500).json({ error: 'INTERNAL_SERVER_ERROR' }); + } +} + +async function verifyForSetPassword(req, res) { + try { + const { customerNo, otp } = req.query; + if (!customerNo || !otp) + return res.status(400).json({ error: 'CUSTOMER_NO_REQUIRED' }); + // check if user is registered for mobile banking database + const user = await authService.findUserByCustomerNo(customerNo); + if (!user) return res.status(404).json({ error: 'USER_NOT_FOUND' }); + // if present then get his phone number from CBS + const userDetails = await customerController.getDetails(customerNo); + // temp check + const singleUserDetail = userDetails[0]; + singleUserDetail.mobileno = '7004774978'; + if (!singleUserDetail?.mobileno) + return res.status(400).json({ error: 'USER_PHONE_NOT_FOUND' }); + + const mobileNumber = singleUserDetail.mobileno; + const storedOtp = await getJson(`otp:${mobileNumber}`); + + if (!storedOtp) { + return res.status(400).json({ error: 'OTP expired or not found' }); + } + + if (parseInt(otp, 10) !== parseInt(storedOtp, 10)) { + return res.status(400).json({ error: 'Invalid OTP' }); + } + + const token = generateToken(customerNo, 'user', '5m'); + return res + .status(200) + .json({ message: 'OTP verified successfully', token: token }); + } catch (err) { + logger.error(err, 'Error sending OTP'); + return res.status(500).json({ error: 'INTERNAL_SERVER_ERROR' }); + } +} + +module.exports = { + SendOtp, + VerifyOtp, + sendForSetPassword, + verifyForSetPassword, +}; diff --git a/src/routes/otp.route.js b/src/routes/otp.route.js index fdf2a7d..336cbec 100644 --- a/src/routes/otp.route.js +++ b/src/routes/otp.route.js @@ -1,4 +1,3 @@ - const express = require('express'); const otpController = require('../controllers/otp.controller'); @@ -10,4 +9,10 @@ router.post('/send', otpController.SendOtp); // Verify OTP (GET request with query params ?mobileNumber=xxx&otp=123456) router.post('/verify', otpController.VerifyOtp); +//send otp for setting password +router.get('/send/set-password', otpController.sendForSetPassword); + +//verify otp for setting password +router.get('/verify/set-password', otpController.verifyForSetPassword); + module.exports = router; diff --git a/src/services/auth.service.js b/src/services/auth.service.js index 52e448c..a466b37 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -1,6 +1,6 @@ const db = require('../config/db'); const { comparePassword, hashPassword } = require('../util/hash'); -const dayjs =require("dayjs"); +const dayjs = require('dayjs'); async function findUserByCustomerNo(customerNo) { const result = await db.query('SELECT * FROM users WHERE customer_no = $1', [ @@ -24,6 +24,12 @@ async function CheckFirstTimeLogin(customerNo) { return is_first_time_login; } +async function isMigratedUser(customerNo) { + const user = await findUserByCustomerNo(customerNo); + if (user?.password_hash === 'o') return true; + return false; +} + async function validateTpin(customerNo, tpin) { const user = await findUserByCustomerNo(customerNo); if (!user?.tpin) return null; @@ -49,11 +55,11 @@ async function setTpin(customerNo, tpin) { async function setLoginPassword(customerNo, login_psw) { const hashedLoginPassword = await hashPassword(login_psw); const currentTime = dayjs().toISOString(); - const password_expiry = dayjs().add(90,"day").toISOString(); + const password_expiry = dayjs().add(90, 'day').toISOString(); try { await db.query( 'UPDATE users SET password_hash = $1 ,is_first_login = false,updated_at = $3,password_hash_expiry =$4 WHERE customer_no = $2', - [hashedLoginPassword, customerNo ,currentTime ,password_expiry] + [hashedLoginPassword, customerNo, currentTime, password_expiry] ); } catch (error) { throw new Error( @@ -73,11 +79,11 @@ async function validateTransactionPassword(customerNo, tpassword) { async function setTransactionPassword(customerNo, trans_psw) { const hashedTransPassword = await hashPassword(trans_psw); const currentTime = dayjs().toISOString(); - const password_expiry = dayjs().add(90,"day").toISOString(); + const password_expiry = dayjs().add(90, 'day').toISOString(); try { await db.query( 'UPDATE users SET transaction_password = $1 ,updated_at = $3,transaction_password_expiry =$4 WHERE customer_no = $2', - [hashedTransPassword, customerNo , currentTime ,password_expiry] + [hashedTransPassword, customerNo, currentTime, password_expiry] ); } catch (error) { throw new Error( @@ -89,11 +95,11 @@ async function setTransactionPassword(customerNo, trans_psw) { async function changeLoginPassword(customerNo, login_psw) { const hashedLoginPassword = await hashPassword(login_psw); const currentTime = dayjs().toISOString(); - const password_expiry = dayjs().add(90,"day").toISOString(); + const password_expiry = dayjs().add(90, 'day').toISOString(); try { await db.query( 'UPDATE users SET password_hash = $1 ,updated_at = $3,password_hash_expiry =$4 WHERE customer_no = $2', - [hashedLoginPassword, customerNo , currentTime ,password_expiry] + [hashedLoginPassword, customerNo, currentTime, password_expiry] ); } catch (error) { throw new Error( @@ -105,11 +111,11 @@ async function changeLoginPassword(customerNo, login_psw) { async function changeTransPassword(customerNo, trans_psw) { const hashedTransPassword = await hashPassword(trans_psw); const currentTime = dayjs().toISOString(); - const password_expiry = dayjs().add(90,"day").toISOString(); + const password_expiry = dayjs().add(90, 'day').toISOString(); try { await db.query( 'UPDATE users SET transaction_password = $1 ,updated_at = $3,transaction_password_expiry =$4 WHERE customer_no = $2', - [hashedTransPassword, customerNo , currentTime ,password_expiry] + [hashedTransPassword, customerNo, currentTime, password_expiry] ); } catch (error) { throw new Error( @@ -129,4 +135,5 @@ module.exports = { setTransactionPassword, changeLoginPassword, changeTransPassword, + isMigratedUser, };