From 9f6c2f9cc1154ae96b0b02523ddf8c007b8d64d5 Mon Sep 17 00:00:00 2001 From: "tomosa.sarkar" Date: Tue, 2 Sep 2025 12:41:39 +0530 Subject: [PATCH] feat: user can change login password feat: user can change transaction password wip : Admin feature rights -InProgress --- .gitignore | 2 + .vscode/settings.json | 1 + package-lock.json | 7 +++ package.json | 1 + src/controllers/admin_auth.controller.js | 67 ++++++++++++++++++++++-- src/controllers/auth.controller.js | 55 ++++++++++++++++++- src/controllers/otp.controller.js | 5 +- src/routes/admin_auth.route.js | 1 + src/routes/auth.route.js | 9 ++-- src/services/auth.service.js | 43 +++++++++++++-- src/util/sms_template.js | 3 ++ 11 files changed, 181 insertions(+), 13 deletions(-) diff --git a/.gitignore b/.gitignore index 713d500..a4713c3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ node_modules/ +.vscode/ .env +logs/requests.log diff --git a/.vscode/settings.json b/.vscode/settings.json index 3c51a6b..029c1b9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "cSpell.words": [ + "otpgenerator", "tpassword", "tpin" ] diff --git a/package-lock.json b/package-lock.json index 2e75d14..d38797a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,6 +12,7 @@ "axios": "^1.9.0", "bcrypt": "^6.0.0", "cors": "^2.8.5", + "dayjs": "^1.11.18", "dotenv": "^16.5.0", "express": "^5.1.0", "jsonwebtoken": "^9.0.2", @@ -842,6 +843,12 @@ "node": "*" } }, + "node_modules/dayjs": { + "version": "1.11.18", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.18.tgz", + "integrity": "sha512-zFBQ7WFRvVRhKcWoUh+ZA1g2HVgUbsZm9sbddh8EC5iv93sui8DVVz1Npvz+r6meo9VKfa8NyLWBsQK1VvIKPA==", + "license": "MIT" + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", diff --git a/package.json b/package.json index bb10d6d..308780e 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "axios": "^1.9.0", "bcrypt": "^6.0.0", "cors": "^2.8.5", + "dayjs": "^1.11.18", "dotenv": "^16.5.0", "express": "^5.1.0", "jsonwebtoken": "^9.0.2", diff --git a/src/controllers/admin_auth.controller.js b/src/controllers/admin_auth.controller.js index 08cdbcc..58250ec 100644 --- a/src/controllers/admin_auth.controller.js +++ b/src/controllers/admin_auth.controller.js @@ -1,8 +1,11 @@ const adminAuthService = require('../services/admin.auth.service'); +const authService = require('../services/auth.service'); const { generateToken } = require('../util/jwt'); const { logger } = require('../util/logger'); +const { hashPassword } = require('../util/hash'); const db = require('../config/db'); -// const authenticate = require('../middlewares/auth.middleware'); +const { generateOTP } = require('../otpgenerator'); + async function login(req, res) { const { userName, password } = req.body; @@ -56,7 +59,65 @@ async function getUserDetails(req, res) { return res.json(userDetails); } catch (error) { logger.error('while fetching customer details', error); - res.status(500).json({ error: 'invalid CIF number'}); + res.status(500).json({ error: 'invalid CIF number' }); } } -module.exports = { login, fetchAdminDetails, getUserDetails }; +async function getUserRights(req, res) { + // const { CIF } = req.query; + // if (!CIF) { + // res.status(400).json({ + // error: 'CIF number is required', + // }); + // } + // try { + // const userDetails = await adminAuthService.getCustomerDetails(CIF); + // if (!userDetails) + // return res.status(401).json({ error: 'invalid CIF number' }); + // return res.json(userDetails); + // } catch (error) { + // logger.error('while fetching customer details', error); + // res.status(500).json({ error: 'invalid CIF number'}); + // } +} +async function UserRights(req, res) { + const { CIF, ib_access_level, mb_access_level } = req.body; + const first_time_pass = generateOTP(6); + if (!CIF) { + res.status(400).json({ + error: 'CIF number is required', + }); + } + const currentTime = new Date().toISOString(); + const user = await authService.findUserByCustomerNo(CIF); + const password = await hashPassword(first_time_pass); + if (user) { + try { + await db.query('UPDATE users SET customer_no = $1,password_hash=$2,updated_at=$5,ib_access_level=$3,mb_access_level=$4 WHERE customer_no = $1', [ + CIF, + password, + ib_access_level, + mb_access_level, + currentTime, + ]); + res.json({otp:`${first_time_pass}`}); + } catch (err) { + console.log(err); + logger.error(err, 'Right Update failed'); + res.status(500).json({ error: 'something went wrong' }); + } + } + if (!user) { + try { + await db.query('INSERT INTO users (customer_no, password_hash,ib_access_level,mb_access_level) VALUES ($1, $2, $3, $4)', + [CIF, password, ib_access_level, mb_access_level] + ); + res.json({message:'User created and Rights Updated.'}); + } catch (err) { + console.log(err); + logger.error(err, 'Right Update failed'); + res.status(500).json({ error: 'something went wrong' }); + } + } +} + +module.exports = { login, fetchAdminDetails, getUserDetails,UserRights}; diff --git a/src/controllers/auth.controller.js b/src/controllers/auth.controller.js index 94e23f8..061e159 100644 --- a/src/controllers/auth.controller.js +++ b/src/controllers/auth.controller.js @@ -2,6 +2,8 @@ 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 { comparePassword } = require('../util/hash'); async function login(req, res) { const { customerNo, password } = req.body; @@ -18,11 +20,15 @@ async function login(req, res) { return res.status(401).json({ error: 'invalid credentials' }); const token = generateToken(user.customer_no, '1d'); 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' }); + const loginPswExpiry = user.password_hash_expiry; await db.query('UPDATE users SET last_login = $1 WHERE customer_no = $2', [ currentTime, customerNo, ]); - res.json({ token, FirstTimeLogin }); + res.json({ token, FirstTimeLogin, loginPswExpiry }); } catch (err) { logger.error(err, 'login failed'); res.status(500).json({ error: 'something went wrong' }); @@ -88,6 +94,7 @@ async function setLoginPassword(req, res) { return res.status(500).json({ error: 'SOMETHING_WENT_WRONG' }); } } + async function setTransactionPassword(req, res) { const customerNo = req.user; try { @@ -102,6 +109,50 @@ async function setTransactionPassword(req, res) { } } +async function changeLoginPassword(req,res){ + const customerNo = req.user; + try { + const user = await authService.findUserByCustomerNo(customerNo); + if (!user) return res.status(404).json({ error: 'USER_NOT_FOUND' }); + const { OldLPsw ,newLPsw ,confirmLPsw } = req.body; + const isMatch = await comparePassword(OldLPsw, user.password_hash); + if(!isMatch) + return res.json({error: 'Please Enter Correct Old Login Password'}); + if(newLPsw !== confirmLPsw) + return res.json ({error: 'New Password and Confirm Password not Match'}) + const isMatchWithOldPassword = await comparePassword(newLPsw, user.password_hash); + if(isMatchWithOldPassword) + return res.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) { + logger.error(error); + return res.status(500).json({ error: 'SOMETHING_WENT_WRONG' }); + } +} + +async function changeTransPassword(req,res){ + const customerNo = req.user; + try { + const user = await authService.findUserByCustomerNo(customerNo); + if (!user) return res.status(404).json({ error: 'USER_NOT_FOUND' }); + const { OldTPsw ,newTPsw ,confirmTPsw } = req.body; + const isMatch = await comparePassword(OldTPsw, user.transaction_password); + if(!isMatch) + return res.json({error: 'Please Enter Correct Old Transaction Password'}); + if(newTPsw !== confirmTPsw) + return res.json ({error: 'New Transaction Password and Confirm Transaction Password not Match'}) + const isMatchWithOldPassword = await comparePassword(newTPsw, user.transaction_password); + if(isMatchWithOldPassword) + return res.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' }); + } catch (error) { + logger.error(error); + return res.status(500).json({ error: 'SOMETHING_WENT_WRONG' }); + } +} + module.exports = { login, tpin, @@ -109,4 +160,6 @@ module.exports = { setLoginPassword, setTransactionPassword, fetchUserDetails, + changeLoginPassword, + changeTransPassword, }; diff --git a/src/controllers/otp.controller.js b/src/controllers/otp.controller.js index b3037b5..6536686 100644 --- a/src/controllers/otp.controller.js +++ b/src/controllers/otp.controller.js @@ -40,6 +40,9 @@ async function SendOtp(req, res) { case 'FORGOT_PASSWORD': message = templates.FORGOT_PASSWORD(otp); break; + case 'REGISTRATION': + message = templates.REGISTRATION(otp); + break; default: return res.status(400).json({ error: 'Invalid OTP type' }); } @@ -71,7 +74,7 @@ async function SendOtp(req, res) { // 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' }); diff --git a/src/routes/admin_auth.route.js b/src/routes/admin_auth.route.js index 0125f7e..d4a9a58 100644 --- a/src/routes/admin_auth.route.js +++ b/src/routes/admin_auth.route.js @@ -7,4 +7,5 @@ const router = express.Router(); router.post('/login', adminAuthController.login); router.get('/admin_details', adminAuthenticate, adminAuthController.fetchAdminDetails); router.get('/fetch/customer_details',adminAuthenticate,adminAuthController.getUserDetails); +router.post('/user/rights',adminAuthenticate,adminAuthController.UserRights); module.exports = router; diff --git a/src/routes/auth.route.js b/src/routes/auth.route.js index 2ab5178..01df214 100644 --- a/src/routes/auth.route.js +++ b/src/routes/auth.route.js @@ -9,10 +9,9 @@ router.get('/user_details', authenticate, authController.fetchUserDetails); router.get('/tpin', authenticate, authController.tpin); router.post('/tpin', authenticate, authController.setTpin); router.post('/login_password', authenticate, authController.setLoginPassword); -router.post( - '/transaction_password', - authenticate, - authController.setTransactionPassword -); +router.post('/transaction_password',authenticate,authController.setTransactionPassword); +router.post('/change/login_password',authenticate,authController.changeLoginPassword); +router.post('/change/transaction_password',authenticate,authController.changeTransPassword); + module.exports = router; diff --git a/src/services/auth.service.js b/src/services/auth.service.js index b5cfe71..3ec7f00 100644 --- a/src/services/auth.service.js +++ b/src/services/auth.service.js @@ -1,5 +1,6 @@ const db = require('../config/db'); const { comparePassword, hashPassword } = require('../util/hash'); +const dayjs =require("dayjs"); async function findUserByCustomerNo(customerNo) { const result = await db.query('SELECT * FROM users WHERE customer_no = $1', [ @@ -69,14 +70,48 @@ async function validateTransactionPassword(customerNo, tpassword) { // Set transaction password async function setTransactionPassword(customerNo, trans_psw) { const hashedTransPassword = await hashPassword(trans_psw); + const currentTime = dayjs().toISOString(); + const password_expiry = dayjs().add(90,"day").toISOString(); try { await db.query( - 'UPDATE users SET transaction_password = $1 WHERE customer_no = $2', - [hashedTransPassword, customerNo] + 'UPDATE users SET transaction_password = $1 ,updated_at = $3,transaction_password_expiry =$4 WHERE customer_no = $2', + [hashedTransPassword, customerNo , currentTime ,password_expiry] ); } catch (error) { throw new Error( - `error occured while while setting new Transaction Password ${error.message}` + `error occurred while while setting new Transaction Password ${error.message}` + ); + } +} + +async function changeLoginPassword(customerNo, login_psw) { + const hashedLoginPassword = await hashPassword(login_psw); + const currentTime = dayjs().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] + ); + } catch (error) { + throw new Error( + `error occured while while setting new Login Password ${error.message}` + ); + } +} + +async function changeTransPassword(customerNo, trans_psw) { + const hashedTransPassword = await hashPassword(trans_psw); + const currentTime = dayjs().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] + ); + } catch (error) { + throw new Error( + `error occurred while while setting new Login Password ${error.message}` ); } } @@ -90,4 +125,6 @@ module.exports = { setLoginPassword, validateTransactionPassword, setTransactionPassword, + changeLoginPassword, + changeTransPassword, }; diff --git a/src/util/sms_template.js b/src/util/sms_template.js index 9afb6e3..1587358 100644 --- a/src/util/sms_template.js +++ b/src/util/sms_template.js @@ -18,6 +18,9 @@ const templates = { FORGOT_PASSWORD: (otp) => `Dear Customer, Forgot Password OTP is ${otp} -KCCB`, + + REGISTRATION: (otp) => + `Dear Customer, Your CIF is enable.First time login password: ${otp} (valid for 7 days).Please login and change your password -KCCB`, }; module.exports = templates; \ No newline at end of file