diff --git a/.env.example b/.env.example deleted file mode 100644 index 98bff27..0000000 --- a/.env.example +++ /dev/null @@ -1,7 +0,0 @@ -PORT = -MONGODB_URI = -OTP_VALIDITY_PERIOD_MINUTES = 2 -OTP_SIZE = 4 -CRYPTO_KEY = hger4917qlpxfjnv -# every 2 minutes -CRON_SCHEDULE = */2 * * * * \ No newline at end of file diff --git a/.env.local b/.env.local new file mode 100644 index 0000000..0e5ca61 --- /dev/null +++ b/.env.local @@ -0,0 +1,9 @@ +PORT = 5001 +MONGODB_URI = +OTP_VALIDITY_PERIOD_MINUTES = 2 +OTP_SIZE = 6 +# every 2 minutes +CRON_SCHEDULE = */2 * * * * +# ALLOWED_DOMAINS = gmail.com, lpu.in, outlook.com, yahoo.com +GMAIL_PASS = +GMAIL_USER = \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 12fd568..fe16655 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,6 @@ COPY package*.json ./ RUN yarn install -EXPOSE 3000 +EXPOSE 5001 CMD ["yarn","start"] \ No newline at end of file diff --git a/README.md b/README.md index 5a1538e..fb83a59 100644 --- a/README.md +++ b/README.md @@ -1,117 +1,137 @@ -# 📱 OTP Service +# OTP Service -This is a free OTP (One-Time Password) service built with Node.js, Express.js, Mongoose, and node-cron for handling OTP generation, verification, and automatic expiration. +The OTP (One-Time Password) Free Service is a Node.js-based service that allows you to generate and verify one-time passwords (OTP) via email. This service is useful for adding an extra layer of security to your applications by enabling two-factor authentication (2FA) or passwordless login. -## Features - -✨ Generate a one-time password (OTP) for a given email. - -🔐 Verify an OTP for a given email. +## Table of Contents -⏰ Automatic OTP expiration and cleanup using cron jobs. +- [Features](#features) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Installation](#installation) +- [Usage](#usage) + - [Generating an OTP](#generating-an-otp) + - [Verifying an OTP](#verifying-an-otp) +- [Configuration](#configuration) + - [Environment Variables](#environment-variables) +- [Scheduled OTP Cleanup](#scheduled-otp-cleanup) +- [Donation](#donation) +- [License](#license) -⚙️ Configurable OTP size and validity period. - -🚀 Error handling for invalid OTPs and expired OTPs. +## Features -## Demo +| Feature | Description | +| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Generate numeric, alphanumeric, or alphabet-based OTPs | Generate one-time passwords with various character types: numeric, alphanumeric, or alphabet-based. | +| 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. | +| 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. | +| Flexible configuration via environment variables | Customize the service's behavior by configuring environment variables. | +| Easy-to-use API with JSON input/output | Interact with the service through a user-friendly JSON API for OTP generation and verification. | -You can interact with the API using the following endpoints: +## Getting Started -| Endpoint | Description | -| ------------------------------ | ----------------------------------------- | -| `POST https://otp-4e71.onrender.com/api/otp` | Generate a one-time password (OTP) for a given email. | -| `POST https://otp-4e71.onrender.com/api/otp/verify` | Verify an OTP for a given email. | +### Prerequisites -## Email Integration +Before you begin, ensure you have met the following requirements: -To send emails for OTP delivery, you can use the [sauravhathi/mailer](https://github.com/sauravhathi/mailer) repository. It provides a straightforward way to send emails as part of your OTP delivery process. +| Prerequisite | Description | +| --------------------- | ---------------------------------------------------------------- | +| Node.js and npm | Install Node.js and npm on your development machine. | +| MongoDB database | Set up a MongoDB database (local or cloud-hosted, e.g., MongoDB Atlas) for storing OTP data. | -## Installation +### Installation 1. Clone the repository: - ```bash + ```shell git clone https://github.com/sauravhathi/otp-service.git + ``` + +2. Navigate to the project directory: + + ```shell cd otp-service ``` -2. Install dependencies: +3. Install the dependencies: - ```bash + ```shell npm install + ``` - # or +4. Configure your environment variables by creating a `.env` file in the project root directory. You can use the provided `.env.example` as a template. - yarn +5. Start the service: + + ```shell + npm start ``` -3. Set up your environment variables by creating a `.env` file in the project root directory and configuring the following variables: +The service should now be running on the specified port (default is 3000). - ```env - MONGODB_URI= - OTP_VALIDITY_PERIOD_MINUTES=2 - OTP_SIZE=4 - CRON_SCHEDULE=*/2 * * * * - ``` +## Usage - - `MONGODB_URI`: MongoDB connection URI. - - `OTP_VALIDITY_PERIOD_MINUTES`: Validity period for OTPs in minutes. - - `OTP_SIZE`: Size of the OTP (number of digits). - - `CRON_SCHEDULE`: Cron schedule for automatic OTP cleanup. +### Generating an OTP -4. Start the server: +To generate an OTP for a user, make a POST request to the `/api/otp/generate` endpoint with the user's email address in the request body. You can also specify the OTP type, organization name, and email subject. - ```bash - npm dev +Example request: - # or +```json +POST /api/otp/generate +{ + "email": "user@example.com", + "type": "numeric", + "organization": "MyApp", + "subject": "OTP Verification" +} +``` - yarn dev - ``` +The service will send an email containing the OTP to the user's email address. + +### Verifying an OTP + +To verify an OTP for user authentication, make a POST request to the `/api/otp/verify` endpoint with the user's email address and the OTP in the request body. + +Example request: + +```json +POST /api/otp/verify +{ + "email": "user@example.com", + "otp": "123456" +} +``` + +The service will respond with a success message if the OTP is valid. + +## Configuration + +You can customize the OTP service by modifying the environment variables in the `.env` file. Here are some key configuration options: + +### Environment Variables + +| Variable | Description | +| ---------------------------- | --------------------------------------------------------------------------------------------- | +| `PORT` | The port on which the service listens. | +| `MONGODB_URI` | The MongoDB connection string. | +| `OTP_VALIDITY_PERIOD_MINUTES` | The validity period of OTPs in minutes. | +| `OTP_SIZE` | The size (length) of OTPs. | +| `CRON_SCHEDULE` | The cron schedule for OTP cleanup. | +| `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). | + +## 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. + +## Donation -## API Endpoints - -### Generate OTP 🚀 - -- **Endpoint**: POST `/api/otp` -- **Request Body**: - ```json - { - "email": "user@example.com" - } - ``` -- **Response**: - ```json - { - "otp": 1234 - } - ``` - -### Verify OTP 🔐 - -- **Endpoint**: POST `/api/otp/verify` -- **Request Body**: - ```json - { - "email": "user@example.com", - "otp": 1234 - } - ``` -- **Response**: - ```json - { - "message": "OTP is valid" - } - ``` - -## Scheduled OTP Cleanup ⏰ - -The service automatically clears expired OTPs based on the configured cron schedule. - -## Donate ☕ - -If you find this project useful and want to support its development, consider buying us a coffee! +If you find this project useful and want to support its development, consider buying us a coffee! Your support is greatly appreciated. support @@ -121,4 +141,4 @@ Donate: `saurav.34@paytm` ## License -This project is licensed under the MIT License. See the [LICENSE](https://github.com/sauravhathi/otp-service/blob/master/LICENSE) file for details. +This project is licensed under the MIT License. See the [LICENSE](https://github.com/sauravhathi/otp-service/blob/master/LICENSE) file for details. \ No newline at end of file diff --git a/app.log b/app.log index a16bd34..9eedc59 100644 --- a/app.log +++ b/app.log @@ -1,57 +1,52 @@ -2023-09-08T20:23:08.097Z [INFO] Generated OTP 9201 for sauravhathi680@gmail.com -2023-09-08T20:23:08.098Z [INFO] Generated OTP 9201 for sauravhathi680@gmail.com -2023-09-08T20:24:00.572Z [INFO] Cleared expired OTPs -2023-09-08T20:24:42.175Z [INFO] OTP already exists for sauravhathi680@gmail.com -2023-09-08T20:25:30.186Z [INFO] Generated OTP 1160 for sauravhathi680@gmail.com -2023-09-08T20:25:38.808Z [INFO] OTP 1160 already exists for sauravhathi680@gmail.com -2023-09-08T20:26:00.766Z [INFO] Cleared expired OTPs -2023-09-08T20:26:07.884Z [INFO] Verified OTP 1160 for sauravhathi680@gmail.com -2023-09-08T20:34:00.376Z [INFO] Cleared expired OTPs -2023-09-08T20:36:00.301Z [INFO] Cleared expired OTPs -2023-09-08T20:38:01.213Z [INFO] Cleared expired OTPs -2023-09-08T20:40:00.475Z [INFO] Cleared expired OTPs -2023-09-08T20:44:01.777Z [INFO] Cleared expired OTPs -2023-09-08T20:48:00.091Z [INFO] Cleared expired OTPs -2023-09-08T20:50:00.704Z [INFO] Cleared expired OTPs -2023-09-08T20:55:22.544Z [INFO] Generated OTP 2632 for sauravhathi680@gmail.com -2023-09-08T20:55:22.544Z [ERROR] Failed to generate OTP -2023-09-08T20:56:00.982Z [INFO] Cleared expired OTPs -2023-09-08T20:56:36.909Z [INFO] OTP 2632 already exists for sauravhathi680@gmail.com -2023-09-08T20:56:36.910Z [ERROR] Failed to generate OTP -2023-09-08T20:57:06.269Z [INFO] OTP 2632 already exists for sauravhathi680@gmail.com -2023-09-08T20:58:05.560Z [INFO] Generated OTP 6147 for sauravhathi680@gmail.com -2023-09-08T20:58:52.982Z [INFO] OTP 6147 already exists for sauravhathi680@gmail.com -2023-09-08T20:59:35.779Z [INFO] OTP 6147 already exists for sauravhathi680@gmail.com -2023-09-08T21:00:00.678Z [INFO] Cleared expired OTPs -2023-09-08T21:00:34.087Z [INFO] Generated OTP 1667 for sauravhathi680@gmail.com -2023-09-08T21:01:44.632Z [INFO] OTP 1667 already exists for sauravhathi680@gmail.com -2023-09-08T21:02:00.080Z [INFO] Cleared expired OTPs -2023-09-08T21:02:33.874Z [INFO] Verified OTP 1667 for sauravhathi680@gmail.com -2023-09-08T21:02:35.796Z [ERROR] Failed to verify OTP -2023-09-08T21:02:35.796Z [ERROR] Failed to verify OTP -2023-09-08T21:02:37.204Z [ERROR] Failed to verify OTP -2023-09-08T21:02:37.204Z [ERROR] Failed to verify OTP -2023-09-08T21:02:39.594Z [ERROR] Failed to verify OTP -2023-09-08T21:02:39.594Z [ERROR] Failed to verify OTP -2023-09-08T21:02:40.498Z [ERROR] Failed to verify OTP -2023-09-08T21:02:40.498Z [ERROR] Failed to verify OTP -2023-09-08T21:04:00.952Z [INFO] Cleared expired OTPs -2023-09-08T21:06:00.389Z [INFO] Cleared expired OTPs -2023-09-08T21:06:22.456Z [INFO] Generated OTP 7413 for sauravhathi680@gmail.com -2023-09-08T21:06:23.922Z [INFO] OTP 7413 already exists for sauravhathi680@gmail.com -2023-09-08T21:06:33.094Z [INFO] Verified OTP 7413 for sauravhathi680@gmail.com -2023-09-08T21:06:34.283Z [ERROR] Failed to verify OTP -2023-09-08T21:06:34.284Z [ERROR] Failed to verify OTP -2023-09-08T21:06:35.995Z [ERROR] Failed to verify OTP -2023-09-08T21:06:35.995Z [ERROR] Failed to verify OTP -2023-09-08T21:06:40.173Z [ERROR] Failed to verify OTP -2023-09-08T21:06:40.174Z [ERROR] Failed to verify OTP -2023-09-08T21:06:41.063Z [ERROR] Failed to verify OTP -2023-09-08T21:06:41.064Z [ERROR] Failed to verify OTP -2023-09-08T21:06:47.303Z [ERROR] Failed to verify OTP -2023-09-08T21:06:47.304Z [ERROR] Failed to verify OTP -2023-09-08T21:08:00.179Z [INFO] Cleared expired OTPs -2023-09-08T21:10:00.952Z [INFO] Cleared expired OTPs -2023-09-08T21:12:00.814Z [INFO] Cleared expired OTPs -2023-09-08T21:12:16.766Z [INFO] Generated OTP 2889 for sauravhathi680@gmail.com -2023-09-08T21:12:23.838Z [INFO] Verified OTP 2889 for sauravhathi680@gmail.com +2023-09-20T17:59:19.717Z [INFO] 🚀 Connected to MongoDB +2023-09-20T17:59:46.260Z [INFO] Generated OTP c4jgOD for nalered528@apxby.com +2023-09-20T18:00:00.347Z [INFO] Cleared expired OTPs +2023-09-20T18:00:22.764Z [INFO] Verified OTP c4jgOD for nalered528@apxby.com +2023-09-20T18:00:34.105Z [ERROR] Failed to verify OTP +2023-09-20T18:00:34.105Z [ERROR] Failed to verify OTP +2023-09-20T18:00:49.043Z [ERROR] Failed to verify OTP +2023-09-20T18:00:49.043Z [ERROR] Failed to verify OTP +2023-09-20T18:02:01.122Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:04:01.020Z [INFO] Cleared expired OTPs +2023-09-20T18:04:57.261Z [ERROR] Failed to verify OTP +2023-09-20T18:05:13.345Z [ERROR] Invalid email +2023-09-20T18:06:00.849Z [INFO] Cleared expired OTPs +2023-09-20T18:08:00.793Z [INFO] Cleared expired OTPs +2023-09-20T18:10:01.741Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:10:02.048Z [INFO] Cleared expired OTPs +2023-09-20T18:10:21.838Z [ERROR] Invalid email +2023-09-20T18:10:33.677Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:10:45.114Z [ERROR] Invalid email +2023-09-20T18:10:53.137Z [INFO] Generated OTP 419296 for nalered528@apxby.com +2023-09-20T18:11:40.410Z [INFO] Verified OTP 419296 for nalered528@apxby.com +2023-09-20T18:15:58.337Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:16:00.586Z [INFO] Cleared expired OTPs +2023-09-20T18:16:03.438Z [ERROR] Failed to verify OTP +2023-09-20T18:16:44.116Z [INFO] Generated OTP wmnfo3 for nalered528@apxby.com +2023-09-20T18:16:48.152Z [ERROR] Failed to generate OTP +2023-09-20T18:17:00.798Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:17:07.099Z [INFO] OTP wmnfo3 already exists for nalered528@apxby.com +2023-09-20T18:17:12.005Z [INFO] Sent OTP to nalered528@apxby.com +2023-09-20T18:18:00.482Z [INFO] Cleared expired OTPs +2023-09-20T18:18:04.535Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:07.599Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:14.106Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:21.298Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:41.704Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:44.845Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:46.575Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:53.926Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:18:59.746Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:15.902Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:19.385Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:30.121Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:35.206Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:36.746Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:41.205Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:19:44.676Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:20:01.308Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:20:07.173Z [INFO] 🚀 Connected to MongoDB +2023-09-20T18:20:12.947Z [INFO] Generated OTP Y4BW8T for nalered528@apxby.com +2023-09-20T18:20:16.609Z [INFO] Sent OTP to nalered528@apxby.com +2023-09-20T18:20:39.518Z [INFO] Verified OTP Y4BW8T for nalered528@apxby.com +2023-09-20T18:20:43.905Z [ERROR] Failed to verify OTP diff --git a/app/controllers/otpController.js b/app/controllers/otpController.js index a37c421..b4a0a35 100644 --- a/app/controllers/otpController.js +++ b/app/controllers/otpController.js @@ -1,21 +1,11 @@ const Otp = require('../models/otpModel'); +const generateOTP = require('../utils/generateOTP'); const logger = require('../utils/logger'); const validityPeriodMinutes = parseInt(process.env.OTP_VALIDITY_PERIOD_MINUTES); const OTP_SIZE = parseInt(process.env.OTP_SIZE); -const generateOTP = (size) => { - if (size < 1 && size > 10) { - logger.error('Invalid OTP size'); - throw new Error('Invalid OTP size'); - } - - const min = 10 ** (size - 1); - const max = 10 ** size - 1; - return Math.floor(Math.random() * (max - min + 1)) + min; -} - const otpController = { - generateOtp: async (email) => { + generateOtp: async (email, type) => { try { // Check if an OTP has already been generated for this email const existingOtp = await Otp.findOne({ @@ -30,13 +20,12 @@ const otpController = { return existingOtp.otp; } - const otp = generateOTP(OTP_SIZE); + const otp = generateOTP(OTP_SIZE, type); const otpDocument = new Otp({ id: new Date().getTime(), email: email, otp: otp, - createdAt: new Date(), }); await otpDocument.save(); diff --git a/app/controllers/sendMailController.js b/app/controllers/sendMailController.js new file mode 100644 index 0000000..f38b13d --- /dev/null +++ b/app/controllers/sendMailController.js @@ -0,0 +1,125 @@ +const nodemailer = require("nodemailer"); +const logger = require("../utils/logger"); + +async function sendMailController(email, otp, organization, subject) { + try { + // Create transporter + const transporter = nodemailer.createTransport({ + service: "gmail", + secure: true, + auth: { + user: process.env.GMAIL_USER, + pass: process.env.GMAIL_PASS, + }, + }); + + const mailOptions = { + from: `"${organization}" <${process.env.GMAIL_USER}>`, + to: email, + subject: `${subject}`, + text: `Your OTP is ${otp}`, + html: ` + + + + + + ${organization} One-Time Password (OTP) + + + +
+
+

${organization}

+
+
+

Your One-Time Password (OTP) is:

+

${otp}

+
+ +
+ + + `, + }; + + // Send email + await transporter.sendMail(mailOptions); + logger.info(`Sent OTP to ${email}`); + } catch (error) { + logger.error(`Failed to send OTP to ${email}`, error.message); + throw new Error(error.message); + } +} + +module.exports = sendMailController; \ No newline at end of file diff --git a/app/db/config.js b/app/db/config.js new file mode 100644 index 0000000..a16a359 --- /dev/null +++ b/app/db/config.js @@ -0,0 +1,17 @@ +const mongoose = require('mongoose'); +const logger = require('../utils/logger'); +const dotenv = require('dotenv'); + +dotenv.config(); + +const connectDB = async () => { + try { + await mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); + logger.info('🚀 Connected to MongoDB'); + } catch (error) { + console.error(error); + logger.error(error); + } +}; + +module.exports = connectDB; \ No newline at end of file diff --git a/app/index.js b/app/index.js index b0bc8d7..8e3ea1b 100644 --- a/app/index.js +++ b/app/index.js @@ -2,33 +2,30 @@ const express = require('express'); const cors = require('cors'); const mongoose = require('mongoose'); const dotenv = require('dotenv'); +const connectDB = require('./db/config'); +const { isValidEmail } = require('./utils/validator'); +const otpRoutes = require('./routes/otpRoutes'); +const logger = require('./utils/logger'); +require('./controllers/schedulerController'); + dotenv.config(); const app = express(); -mongoose.connect(process.env.MONGODB_URI, { useNewUrlParser: true, useUnifiedTopology: true }); -const db = mongoose.connection; -db.on('error', console.error.bind(console, 'MongoDB connection error:')); -db.once('open', () => { - console.log('Connected to MongoDB'); -}); - app.use(cors()); app.use(express.json()); -const {isValidEmail} = require('./utils/validator'); -const otpRoutes = require('./routes/otpRoutes'); -const schedulerController = require('./controllers/schedulerController'); - const middleware = (req, res, next) => { - const { email } = req.body; - if (!isValidEmail(email)) { - console.log('middleware'); - return res.status(400).json({ error: 'Invalid email' }); - } - next(); + const { email } = req.body; + if (!isValidEmail(email)) { + logger.error('Invalid email'); + return res.status(400).json({ error: 'Invalid email' }); + } + next(); }; +connectDB(); + app.use('/api', middleware, otpRoutes); const PORT = process.env.PORT || 3000; diff --git a/app/models/otpModel.js b/app/models/otpModel.js index 88c5699..5bc9751 100644 --- a/app/models/otpModel.js +++ b/app/models/otpModel.js @@ -2,9 +2,18 @@ const mongoose = require('mongoose'); const otpSchema = new mongoose.Schema({ id: String, - email: String, - otp: Number, - createdAt: Date, + email: { + type: String, + required: true, + }, + otp: { + type: String, + required: true, + }, + createdAt: { + type: Date, + default: Date.now, + }, }); const Otp = mongoose.model('Otp', otpSchema); diff --git a/app/routes/otpRoutes.js b/app/routes/otpRoutes.js index 3f77d77..cdeb1e7 100644 --- a/app/routes/otpRoutes.js +++ b/app/routes/otpRoutes.js @@ -1,15 +1,19 @@ const express = require('express'); const otpController = require('../controllers/otpController'); +const sendMailController = require('../controllers/sendMailController'); const logger = require('../utils/logger'); const router = express.Router(); -router.post('/otp', async (req, res) => { - try {const { email, encryption } = req.body; +router.post('/otp/generate', async (req, res) => { + try { + const { email, type = 'numeric', organization = 'Saurav Hathi', subject = 'One-Time Password (OTP)' } = req.body; + + const otp = await otpController.generateOtp(email, type); - const otp = await otpController.generateOtp(email); + await sendMailController(email, otp, organization, subject); - res.status(200).json({ otp }); + res.status(200).json({ message: 'OTP is generated and sent to your email' }); } catch (error) { logger.error('Failed to generate OTP', error.message); res.status(400).json({ error: error.message }); @@ -21,9 +25,8 @@ router.post('/otp/verify', async (req, res) => { const { email, otp } = req.body; await otpController.verifyOtp(email, otp); - res.status(200).json({ message: 'OTP is valid' }); + res.status(200).json({ message: 'OTP is verified' }); } catch (error) { - logger.error('Failed to verify OTP', error.message); res.status(400).json({ error: error.message }); } }); diff --git a/app/utils/generateOTP.js b/app/utils/generateOTP.js new file mode 100644 index 0000000..531ca28 --- /dev/null +++ b/app/utils/generateOTP.js @@ -0,0 +1,33 @@ +const generateOTP = (size, type) => { + if (size < 1 && size > 10) { + logger.error('Invalid OTP size'); + throw new Error('Invalid OTP size'); + } + + const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'; + const numbers = '0123456789'; + let otpChars = ''; + + if (type === 'numeric') { + otpChars = numbers; + } + else if (type === 'alphanumeric') { + otpChars = numbers + characters; + } + else if (type === 'alphabet') { + otpChars = characters; + } + else { + logger.error('Invalid OTP type'); + throw new Error('Invalid OTP type'); + } + + let otp = ''; + for (let i = 0; i < size; i++) { + otp += otpChars.charAt(Math.floor(Math.random() * otpChars.length)); + } + + return otp; +} + +module.exports = generateOTP; \ No newline at end of file diff --git a/app/utils/validator.js b/app/utils/validator.js index 5d7a42f..e15441b 100644 --- a/app/utils/validator.js +++ b/app/utils/validator.js @@ -1,27 +1,20 @@ const isValidEmail = (email) => { const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; - return emailRegex.test(email); -}; + const [localPart, domain] = email.split("@"); + const allowedDomains = process.env.ALLOWED_DOMAINS + ? process.env.ALLOWED_DOMAINS.split(",") + : []; -const key = process.env.CRYPTO_KEY; + const minLocalPartLength = 5; + const maxLocalPartLength = 64; -const crypto = { - encrypt: (text) => { - const result = new Uint8Array(text.length); - for (let i = 0; i < text.length; i++) { - const charCode = text.charCodeAt(i) ^ key.charCodeAt(i % key.length); - result[i] = charCode; - } - return String.fromCharCode.apply(null, result); - }, - decrypt: (encryptedText) => { - const result = new Uint8Array(encryptedText.length); - for (let i = 0; i < encryptedText.length; i++) { - const charCode = encryptedText.charCodeAt(i) ^ key.charCodeAt(i % key.length); - result[i] = charCode; - } - return String.fromCharCode.apply(null, result); - } -} + return ( + (allowedDomains.length === 0 || allowedDomains.includes(domain)) && + localPart.length >= minLocalPartLength && + localPart.length <= maxLocalPartLength && + !/^[0-9]/.test(localPart) && + emailRegex.test(email) + ); +}; -module.exports = {isValidEmail, crypto}; \ No newline at end of file +module.exports = { isValidEmail }; \ No newline at end of file diff --git a/package.json b/package.json index ff1aaa8..a78d665 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,8 @@ "dotenv": "^16.3.1", "express": "^4.18.2", "mongoose": "^7.5.0", - "node-cron": "^3.0.2" + "node-cron": "^3.0.2", + "nodemailer": "^6.9.5" }, "devDependencies": { "nodemon": "^3.0.1" diff --git a/yarn.lock b/yarn.lock index 560f0cf..c7ab3da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -525,6 +525,11 @@ node-cron@^3.0.2: dependencies: uuid "8.3.2" +nodemailer@^6.9.5: + version "6.9.5" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.9.5.tgz#eaeae949c62ec84ef1e9128df89fc146a1017aca" + integrity sha512-/dmdWo62XjumuLc5+AYQZeiRj+PRR8y8qKtFCOyuOl1k/hckZd8durUUHs/ucKx6/8kN+wFxqKJlQ/LK/qR5FA== + nodemon@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-3.0.1.tgz#affe822a2c5f21354466b2fc8ae83277d27dadc7"