Your One-Time Password (OTP) is:
From 8a79d40a389d93d0d71af8d47828b36c40a7054e Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:49:36 +0530 Subject: [PATCH 04/10] Update config.js --- app/db/config.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/app/db/config.js b/app/db/config.js index a16a359..b8bdb29 100644 --- a/app/db/config.js +++ b/app/db/config.js @@ -4,10 +4,15 @@ const dotenv = require('dotenv'); dotenv.config(); +let existingConnection; + const connectDB = async () => { try { - await mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); - logger.info('🚀 Connected to MongoDB'); + if (!existingConnection) { + existingConnection = await mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); + logger.info('🚀 Connected to MongoDB'); + } + return existingConnection; } catch (error) { console.error(error); logger.error(error); From b230dd63ba3904f20fc86aeb9ffe9f82705757c5 Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:49:42 +0530 Subject: [PATCH 05/10] Update index.js --- app/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/index.js b/app/index.js index 59d1f86..33becac 100644 --- a/app/index.js +++ b/app/index.js @@ -2,7 +2,7 @@ const express = require('express'); const cors = require('cors'); const dotenv = require('dotenv'); const connectDB = require('./db/config'); -const middleware = require('./middleware/middleware'); +const {middleware, validateSpamMiddleware} = require('./middleware/middleware'); const { isValidEmail } = require('./utils/validator'); const otpRoutes = require('./routes/otpRoutes'); const logger = require('./utils/logger'); @@ -21,7 +21,7 @@ app.get('/', (req, res) => { res.send('Welcome to OTP service'); }); -app.use('/api', middleware, otpRoutes); +app.use('/api', validateSpamMiddleware, middleware, otpRoutes); app.get('/api/cron', (req, res) => { try { From f06b2f85b72841868fae24abb95a1c55ee9d1df7 Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:49:47 +0530 Subject: [PATCH 06/10] Update middleware.js --- app/middleware/middleware.js | 44 +++++++++++++++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/app/middleware/middleware.js b/app/middleware/middleware.js index 0c139b3..9de0912 100644 --- a/app/middleware/middleware.js +++ b/app/middleware/middleware.js @@ -1,5 +1,44 @@ const { isValidEmail } = require("../utils/validator"); const logger = require("../utils/logger"); +const Blocklist = require("../models/blockListModel"); + +const spma_words = process.env.BLOCK_KEYWORDS_RULES.split(',') || []; + +const getIp = async (req) => { + try { + const ipDetails = await fetch("https://ipapi.co/json/"); + const ipDetailsJson = await ipDetails.json(); + return ipDetailsJson.ip; + } catch (error) { + return null; + } +} + +const validateSpamMiddleware = async (req, res, next) => { + const bodyValues = Object.values(req.body); + const bodyText = bodyValues.join(' '); + const ip = await getIp(req); + + const blocklist = await Blocklist.findOne({ + $or: [ + { email: req.body.email ? req.body.email : null }, + { ip: ip } + ] + }, { email: 1, ip: 1, _id: 0 }); + + if (blocklist) { + logger.error('Spam detected'); + return res.status(400).json({ error: 'Spam detected' }); + } + + if (spma_words.some(word => bodyText.includes(word))) { + await Blocklist.create({ ip: ip, email: req.body.email ? req.body.email : null }); + logger.error('Spam detected'); + return res.status(400).json({ error: 'Spam detected' }); + } + + next(); +} const validateEmail = (req, res, next) => { const { email } = req.body; @@ -33,4 +72,7 @@ const middleware = (req, res, next) => { } }; -module.exports = middleware; \ No newline at end of file +module.exports = { + middleware, + validateSpamMiddleware, +} \ No newline at end of file From cc93cce6dba345fe924057fd497705b13c4d0fdb Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:49:53 +0530 Subject: [PATCH 07/10] Create blockListModel.js --- app/models/blockListModel.js | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 app/models/blockListModel.js diff --git a/app/models/blockListModel.js b/app/models/blockListModel.js new file mode 100644 index 0000000..5232268 --- /dev/null +++ b/app/models/blockListModel.js @@ -0,0 +1,20 @@ +const mongoose = require('mongoose'); + +const blocklistSchema = new mongoose.Schema({ + ip: { + type: String, + required: [true, 'IP address is required'], + }, + email: { + type: String, + required: [true, 'Email is required'], + }, + createdAt: { + type: Date, + default: Date.now, + }, +}); + +const Blocklist = mongoose.model('Blocklist', blocklistSchema); + +module.exports = Blocklist; \ No newline at end of file From c279fc02baa3595d39db8068f8a0f7b68bbdeadb Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:50:02 +0530 Subject: [PATCH 08/10] Update otpModel.js --- app/models/otpModel.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/models/otpModel.js b/app/models/otpModel.js index 5bc9751..1844fed 100644 --- a/app/models/otpModel.js +++ b/app/models/otpModel.js @@ -10,6 +10,10 @@ const otpSchema = new mongoose.Schema({ type: String, required: true, }, + attempts: { + type: Number, + default: 0, + }, createdAt: { type: Date, default: Date.now, @@ -18,4 +22,5 @@ const otpSchema = new mongoose.Schema({ const Otp = mongoose.model('Otp', otpSchema); -module.exports = Otp; \ No newline at end of file +module.exports = Otp; + From 062387b2c967e404729d1944e7b3557a399bc13a Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:50:06 +0530 Subject: [PATCH 09/10] Update otpRoutes.js --- app/routes/otpRoutes.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/app/routes/otpRoutes.js b/app/routes/otpRoutes.js index cdeb1e7..ba83427 100644 --- a/app/routes/otpRoutes.js +++ b/app/routes/otpRoutes.js @@ -9,6 +9,9 @@ router.post('/otp/generate', async (req, res) => { try { const { email, type = 'numeric', organization = 'Saurav Hathi', subject = 'One-Time Password (OTP)' } = req.body; + // SPAM_WORDS = madarchod,chutiya,bsdk,bsdk,mc,bc,bhoslund,land,behenchod,motherfucker + const spma_words = process.env.SPAM_WORDS + const otp = await otpController.generateOtp(email, type); await sendMailController(email, otp, organization, subject); From 32780a5ed85d6e7d07e1aa132485155af6559adc Mon Sep 17 00:00:00 2001 From: Saurav Hathi <61316762+sauravhathi@users.noreply.github.com> Date: Wed, 24 Jan 2024 05:50:15 +0530 Subject: [PATCH 10/10] Update README.md --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index fb83a59..e341eb4 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ The OTP (One-Time Password) Free Service is a Node.js-based service that allows - [Configuration](#configuration) - [Environment Variables](#environment-variables) - [Scheduled OTP Cleanup](#scheduled-otp-cleanup) +- [Spam Detection](#spam-detection) - [Donation](#donation) - [License](#license) @@ -25,6 +26,7 @@ The OTP (One-Time Password) Free Service is a Node.js-based service that allows | Send OTPs via email | Send OTPs to users via email for authentication or verification. | | Verify OTPs for user authentication | Verify OTPs provided by users for secure authentication. | | Automatic cleanup of expired OTPs | Automatically remove expired OTPs from the database based on a configured cron schedule. | +| Spam detection | Detect spam requests and block them from being processed. | Customizable OTP validity period and size | Adjust the validity period and size (length) of OTPs to match your security requirements. | | Rate limiting for OTP generation | Implement rate limiting to prevent abuse and ensure the service is used responsibly. | | Multiple email service providers supported | Choose from multiple email service providers (e.g., Gmail, Outlook) to send OTP emails. | @@ -124,11 +126,16 @@ You can customize the OTP service by modifying the environment variables in the | `ALLOWED_DOMAINS` | Comma-separated list of allowed email domains. | | `GMAIL_USER` | Gmail username (used for sending emails). | | `GMAIL_PASS` | Gmail password (used for sending emails). | +| `BLOCK_KEYWORDS_RULES` | Comma-separated list of blocked keywords. | ## Scheduled OTP Cleanup The service automatically clears expired OTPs based on the configured cron schedule. By default, it runs daily at midnight to remove expired OTPs. +## Spam Detection + +The service uses a spam detection mechanism to prevent abuse. It checks the request body for spam keywords and blocks the request if any are found. You can configure the spam keywords by setting the `SPAM_WORDS` environment variable. + ## Donation If you find this project useful and want to support its development, consider buying us a coffee! Your support is greatly appreciated.