From 52225828d053cb4c3be03e1072a724bade713629 Mon Sep 17 00:00:00 2001 From: "nabanita.jana" Date: Mon, 25 Aug 2025 11:45:23 +0530 Subject: [PATCH] OTP binding --- .gitignore | 1 + src/app.js | 1 + src/controllers/neft.controller.js | 2 + src/controllers/otp.controller.js | 98 ++++++++++++++++++++++++++++++ src/otpgenerator.js | 12 ++++ src/routes/index.js | 2 + src/routes/otp.route.js | 13 ++++ src/util/sms_template.js | 23 +++++++ 8 files changed, 152 insertions(+) create mode 100644 src/controllers/otp.controller.js create mode 100644 src/otpgenerator.js create mode 100644 src/routes/otp.route.js create mode 100644 src/util/sms_template.js diff --git a/.gitignore b/.gitignore index 713d500..16208e3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules/ +.vscode/ .env diff --git a/src/app.js b/src/app.js index 3c86b46..c2cd73c 100644 --- a/src/app.js +++ b/src/app.js @@ -17,3 +17,4 @@ app.use((err, _req, res, _next) => { }); module.exports = app; + diff --git a/src/controllers/neft.controller.js b/src/controllers/neft.controller.js index 091b7a3..8cc47dc 100644 --- a/src/controllers/neft.controller.js +++ b/src/controllers/neft.controller.js @@ -30,6 +30,8 @@ async function send( 'API call failed: ' + (error.response?.data?.message || error.message) ); } + + } module.exports = { send }; diff --git a/src/controllers/otp.controller.js b/src/controllers/otp.controller.js new file mode 100644 index 0000000..b3037b5 --- /dev/null +++ b/src/controllers/otp.controller.js @@ -0,0 +1,98 @@ + +const { setJson, getJson } = require('../config/redis'); +const { generateOTP } = require('../otpgenerator'); +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 } = req.body; + + if (!mobileNumber || !type) { + return res.status(400).json({ error: 'Mobile number and type are required' }); + } + + try { + const otp = generateOTP(6); + let message; + + // Pick template based on type + switch (type) { + case 'IMPS': + message = templates.IMPS(otp); + break; + case 'NEFT': + message = templates.NEFT(otp, amount, beneficiary); + break; + case 'RTGS': + message = templates.RTGS(otp, amount, beneficiary); + break; + case 'BENEFICIARY_ADD': + message = templates.BENEFICIARY_ADD(otp, beneficiary, ifsc); + break; + case 'BENEFICIARY_SUCCESS': + message = templates.BENEFICIARY_SUCCESS(beneficiary); + break; + case 'NOTIFICATION': + message = templates.NOTIFICATION(acctFrom, acctTo, amount, ref, date); + break; + case 'FORGOT_PASSWORD': + message = templates.FORGOT_PASSWORD(otp); + break; + default: + return res.status(400).json({ error: 'Invalid OTP type' }); + } + + // Call SMS API + 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) + if (message.includes('OTP')) { + await setJson(`otp:${mobileNumber}`, otp, 300); + } + + logger.info(`Sent OTP [${otp}] for type [${type}] to ${mobileNumber}`); + } + + 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 + + if (!mobileNumber || !otp) { + return res.status(400).json({ error: 'Phone number and OTP are required' }); + } + + try { + 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' }); + } + + return res.status(200).json({ message: 'OTP verified successfully' }); + } catch (err) { + logger.error(err, 'Error verifying OTP'); + return res.status(500).json({ error: 'Internal server error' }); + } +} + +module.exports = { SendOtp, VerifyOtp }; diff --git a/src/otpgenerator.js b/src/otpgenerator.js new file mode 100644 index 0000000..b66a46b --- /dev/null +++ b/src/otpgenerator.js @@ -0,0 +1,12 @@ + +function generateOTP(length) { + const digits = '0123456789'; + let otp = ''; + otp += digits[Math.floor(Math.random() * 9) + 1]; // first digit cannot be zero + for (let i = 1; i < length; i++) { + otp += digits[Math.floor(Math.random() * digits.length)]; + } + return otp; +} + +module.exports = { generateOTP }; diff --git a/src/routes/index.js b/src/routes/index.js index 9599fbd..749ec5c 100644 --- a/src/routes/index.js +++ b/src/routes/index.js @@ -8,6 +8,7 @@ const beneficiaryRoute = require('./beneficiary.route'); const neftRoute = require('./neft.route'); const rtgsRoute = require('./rtgs.route'); const { npciResponse } = require('../controllers/npci.controller'); +const otp = require('./otp.route'); const router = express.Router(); @@ -19,5 +20,6 @@ router.use('/payment/neft', authenticate, neftRoute); router.use('/payment/rtgs', authenticate, rtgsRoute); router.use('/beneficiary', authenticate, beneficiaryRoute); router.use('/npci/beneficiary-response', npciResponse); +router.use('/otp', otp); module.exports = router; diff --git a/src/routes/otp.route.js b/src/routes/otp.route.js new file mode 100644 index 0000000..fdf2a7d --- /dev/null +++ b/src/routes/otp.route.js @@ -0,0 +1,13 @@ + +const express = require('express'); +const otpController = require('../controllers/otp.controller'); + +const router = express.Router(); + +// Send OTP (POST request with body) +router.post('/send', otpController.SendOtp); + +// Verify OTP (GET request with query params ?mobileNumber=xxx&otp=123456) +router.post('/verify', otpController.VerifyOtp); + +module.exports = router; diff --git a/src/util/sms_template.js b/src/util/sms_template.js new file mode 100644 index 0000000..9afb6e3 --- /dev/null +++ b/src/util/sms_template.js @@ -0,0 +1,23 @@ +const templates = { + IMPS: (otp) => `Dear Customer, Please complete the fund transfer with OTP ${otp} -KCCB`, + + NEFT: (otp, amount, beneficiary) => + `Dear Customer, Please complete the NEFT of Rs.${amount} to ${beneficiary} with OTP:${otp} -KCCB`, + + RTGS: (otp, amount, beneficiary) => + `Dear Customer, Please complete the RTGS of Rs.${amount} to ${beneficiary} with OTP:${otp} -KCCB`, + + BENEFICIARY_ADD: (otp, beneficiary, ifsc) => + `Dear Customer, You have added beneficiary ${beneficiary} ${ifsc} for NEFT/RTGS. Please endorse the beneficiary with OTP ${otp} -KCCB`, + + BENEFICIARY_SUCCESS: (beneficiary) => + `Dear Customer, Your Beneficiary: ${beneficiary} for Net Banking is added successfully -KCCB`, + + NOTIFICATION: (acctFrom, acctTo, amount, ref, date) => + `Your A/c ${acctFrom} is debited for Rs. ${amount} to the credit of A/c ${acctTo} thru Net Banking - ref: ${ref} - ${date} - Kangra Central Co-Operative Bank -KCCB`, + + FORGOT_PASSWORD: (otp) => + `Dear Customer, Forgot Password OTP is ${otp} -KCCB`, +}; + +module.exports = templates; \ No newline at end of file