├── Procfile ├── .gitignore ├── templates ├── sms │ ├── phone_2FA.js │ ├── phone_forget.js │ └── phone_verification.js └── email │ ├── email_2FA.js │ ├── email_forget.js │ └── email_verification.js ├── sequelize.js ├── package.json ├── middlewares └── crypt.js ├── redoc.html ├── models └── OTP.js ├── app.js ├── README.md └── routes ├── sendOTP_to_email.js ├── sendOTP_to_phone.js └── verifyOTP.js /Procfile: -------------------------------------------------------------------------------- 1 | web:node app.js -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | /node_modules -------------------------------------------------------------------------------- /templates/sms/phone_2FA.js: -------------------------------------------------------------------------------- 1 | const message = (otp) =>{ 2 | return `Dear User,\n` 3 | + `${otp} is your otp for Login.Please Enter the OTP to proceed.\n` 4 | + `Regards\n` 5 | + `Divyansh Agarwal` 6 | } 7 | 8 | module.exports= message; -------------------------------------------------------------------------------- /templates/sms/phone_forget.js: -------------------------------------------------------------------------------- 1 | const message = (otp) =>{ 2 | return `Dear User,\n` 3 | + `${otp} is your otp for Reset Password.Please Enter the OTP to proceed.\n` 4 | + `Regards\n` 5 | + `Divyansh Agarwal` 6 | } 7 | 8 | module.exports= message; -------------------------------------------------------------------------------- /templates/sms/phone_verification.js: -------------------------------------------------------------------------------- 1 | const message = (otp) =>{ 2 | return `Dear User,\n` 3 | + `${otp} is your otp for Incampus. Please enter the OTP to verify your phone number.\n` 4 | + `Regards\n` 5 | + `Divyansh Agarwal` 6 | } 7 | 8 | module.exports= message; -------------------------------------------------------------------------------- /templates/email/email_2FA.js: -------------------------------------------------------------------------------- 1 | const subject_mail = "OTP: For Login" 2 | 3 | 4 | 5 | const message = (otp) =>{ 6 | return `Dear User, \n\n` 7 | + 'OTP for Login is : \n\n' 8 | + `${otp}\n\n` 9 | + 'This is a auto-generated email. Please do not reply to this email.\n\n' 10 | + 'Regards\n' 11 | + 'Divyansh Agarwal\n\n' 12 | } 13 | 14 | module.exports = {subject_mail, message}; -------------------------------------------------------------------------------- /templates/email/email_forget.js: -------------------------------------------------------------------------------- 1 | const subject_mail = "OTP: For Reset Password" 2 | 3 | 4 | 5 | const message = (otp) =>{ 6 | return `Dear User, \n\n` 7 | + 'OTP for Reset Password is : \n\n' 8 | + `${otp}\n\n` 9 | + 'This is a auto-generated email. Please do not reply to this email.\n\n' 10 | + 'Regards\n' 11 | + 'Divyansh Agarwals\n\n' 12 | } 13 | 14 | module.exports = {subject_mail, message}; -------------------------------------------------------------------------------- /templates/email/email_verification.js: -------------------------------------------------------------------------------- 1 | const subject_mail = "OTP: For Email Verification" 2 | 3 | 4 | 5 | const message = (otp) =>{ 6 | return `Dear User, \n\n` 7 | + 'OTP for your email verification is : \n\n' 8 | + `${otp}\n\n` 9 | + 'This is a auto-generated email. Please do not reply to this email.\n\n' 10 | + 'Regards\n' 11 | + 'Divyansh Agarwal\n\n' 12 | } 13 | 14 | module.exports={subject_mail, message}; -------------------------------------------------------------------------------- /sequelize.js: -------------------------------------------------------------------------------- 1 | const Sequelize = require('sequelize'); 2 | const OTP_Model = require('./models/OTP'); 3 | 4 | const sequelize = new Sequelize(process.env['DB_NAME'], process.env['DB_USER'], process.env['DB_PASSWORD'], { 5 | host: process.env['DB_HOST'], 6 | dialect: 'postgres', 7 | protocol: 'postgres', 8 | port: process.env['DB_PORT'], 9 | dialectOptions: { 10 | "ssl": { 11 | "require":true, 12 | "rejectUnauthorized": false 13 | } 14 | }, 15 | define: { 16 | timestamps: false 17 | }, 18 | 19 | pool: { 20 | max: 20, 21 | min: 0, 22 | idle: 5000 23 | }, 24 | logging:false 25 | }); 26 | 27 | const OTP = OTP_Model(sequelize, Sequelize); 28 | 29 | sequelize.sync().then(() => { 30 | console.log('db and tables have been created'); 31 | }); 32 | 33 | module.exports = {OTP}; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-js-otp", 3 | "version": "1.0.0", 4 | "description": "Basic OTP service in NodeJs using express", 5 | "main": "app.js", 6 | "scripts": { 7 | "start": "nodemon app.js", 8 | "server": "nodemon app.js", 9 | "dev": "npm run server" 10 | }, 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "aws-sdk": "^2.709.0", 15 | "cors": "^2.8.5", 16 | "crypto": "^1.0.1", 17 | "custom-id": "^1.2.0", 18 | "dotenv": "^8.2.0", 19 | "express": "^4.17.1", 20 | "fs": "0.0.1-security", 21 | "helmet": "^3.23.0", 22 | "jsonwebtoken": "^8.5.1", 23 | "morgan": "^1.10.0", 24 | "nodemailer": "^6.4.8", 25 | "nodemon": "^2.0.4", 26 | "otp-generator": "^3.0.0", 27 | "pg": "^8.2.1", 28 | "sequelize": "^5.21.12", 29 | "sequelize-cli": "^5.5.1", 30 | "swagger-jsdoc": "^4.0.0", 31 | "swagger-ui-express": "^4.1.4", 32 | "tls": "0.0.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /middlewares/crypt.js: -------------------------------------------------------------------------------- 1 | const crypto = require('crypto'); 2 | var password = process.env['CRYPT_PASSWORD']; 3 | // var iv = 'kiamdksndn'; 4 | var iv = Buffer.from(process.env['IV']); 5 | var ivstring = iv.toString('hex'); 6 | 7 | function sha1(input) { 8 | return crypto.createHash('sha1').update(input).digest(); 9 | } 10 | 11 | function password_derive_bytes(password, salt, iterations, len) { 12 | var key = Buffer.from(password + salt); 13 | for (var i = 0; i < iterations; i++) { 14 | key = sha1(key); 15 | } 16 | if (key.length < len) { 17 | var hx = password_derive_bytes(password, salt, iterations - 1, 20); 18 | for (var counter = 1; key.length < len; ++counter) { 19 | key = Buffer.concat([key, sha1(Buffer.concat([Buffer.from(counter.toString()), hx]))]); 20 | } 21 | } 22 | return Buffer.alloc(len, key); 23 | } 24 | 25 | 26 | async function encode(string) { 27 | var key = password_derive_bytes(password, '', 100, 32); 28 | var cipher = crypto.createCipheriv('aes-256-cbc', key, ivstring); 29 | var part1 = cipher.update(string, 'utf8'); 30 | var part2 = cipher.final(); 31 | const encrypted = Buffer.concat([part1, part2]).toString('base64'); 32 | return encrypted; 33 | } 34 | 35 | async function decode(string) { 36 | var key = password_derive_bytes(password, '', 100, 32); 37 | var decipher = crypto.createDecipheriv('aes-256-cbc', key, ivstring); 38 | var decrypted = decipher.update(string, 'base64', 'utf8'); 39 | decrypted += decipher.final(); 40 | return decrypted; 41 | } 42 | 43 | 44 | module.exports={encode, decode}; -------------------------------------------------------------------------------- /redoc.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Node-OTP-Service | Documentation 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 17 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /models/OTP.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable indent */ 2 | 3 | /** 4 | * @swagger 5 | * definitions: 6 | * Details: 7 | * type: object 8 | * properties: 9 | * Status: 10 | * type: string 11 | * Details: 12 | * type: string 13 | */ 14 | 15 | /** 16 | * @swagger 17 | * definitions: 18 | * VerificationDetails: 19 | * type: object 20 | * properties: 21 | * Status: 22 | * type: string 23 | * Details: 24 | * type: string 25 | * Check: 26 | * type: string 27 | */ 28 | 29 | /** 30 | * @swagger 31 | * definitions: 32 | * OTP: 33 | * type: object 34 | * properties: 35 | * id: 36 | * type: uuid 37 | * first_name: 38 | * type: string 39 | * last_name: 40 | * type: string 41 | * email: 42 | * type: string 43 | * username: 44 | * type: string 45 | * password: 46 | * type: string 47 | * format: password 48 | * resetPasswordToken: 49 | * type: string 50 | * resetPasswordExpires: 51 | * type: string 52 | * format: date-time 53 | * required: 54 | * - email 55 | * - username 56 | * - password 57 | */ 58 | 59 | module.exports = function(sequelize, DataTypes) { 60 | // return queryInterface.sequelize.query('CREATE EXTENSION IF NOT EXISTS "uuid-ossp";').then(()=>{ 61 | return sequelize.define('OTP', { 62 | id: { 63 | type: DataTypes.UUID, 64 | primaryKey: true, 65 | defaultValue: DataTypes.UUIDV4, 66 | }, 67 | otp: DataTypes.STRING, 68 | expiration_time: DataTypes.DATE, 69 | verified: { 70 | type: DataTypes.BOOLEAN, 71 | defaultValue: false, 72 | allowNull: true 73 | }, 74 | created_at: { 75 | type: DataTypes.DATE, 76 | allowNull: false, 77 | defaultValue: sequelize.fn('now') 78 | }, 79 | updated_at: { 80 | type: DataTypes.DATE, 81 | allowNull: false, 82 | defaultValue: sequelize.fn('now') 83 | } 84 | }, { 85 | tableName: 'OTP' 86 | }); 87 | // }); 88 | }; 89 | 90 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | 2 | // DB_PORT= 3 | // DB_NAME= 4 | // DB_HOST= 5 | // DB_USER= 6 | // DB_PASSWORD= 7 | // EMAIL_ADDRESS= 8 | // EMAIL_PASSWORD= 9 | // AWS_ACCESS_KEY_ID= 10 | // AWS_SECRET_ACCESS_KEY= 11 | // AWS_REGION= 12 | // IV= 13 | // CRYPT_PASSWORD= 14 | 15 | require('dotenv').config(); 16 | const express = require('express'); 17 | const path = require('path'); 18 | const helmet = require('helmet'); 19 | const logger = require('morgan'); 20 | var os = require("os"); 21 | var hostname = os.hostname(); 22 | const app = express(); 23 | 24 | const port = process.env.PORT || 4500 25 | 26 | 27 | // Getting data in json format 28 | 29 | app.use(express.urlencoded({ extended: true })); 30 | app.use(express.json()); 31 | 32 | //Setting up cors 33 | 34 | var cors = require('cors'); 35 | var corsOption = { 36 | origin: "*", 37 | methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', 38 | credentials: true, 39 | exposedHeaders: ['x-auth-token'] 40 | }; 41 | app.use(cors(corsOption)); 42 | 43 | // Using Helmet 44 | 45 | app.use(helmet()) 46 | 47 | // Logger 48 | 49 | app.use(logger('common')) 50 | 51 | //Setting swagger Documentation 52 | 53 | const swaggerJSDoc = require('swagger-jsdoc'); 54 | const swaggerDefinition = { 55 | info: { 56 | title: 'Node-OTP-Service API', 57 | version: '1.0.0', 58 | description: 'Documentation for Node-Js OTP service API', 59 | }, 60 | host: 'node-otp-service.herokuapp.com', 61 | basePath: '/api/v1/', 62 | }; 63 | const options = { 64 | swaggerDefinition, 65 | apis: ['./routes/*.js','./models/OTP.js'], 66 | 67 | }; 68 | const swaggerSpec = swaggerJSDoc(options); 69 | app.get('/swagger.json', (req, res) => { 70 | res.setHeader('Content-Type', 'application/json'); 71 | res.send(swaggerSpec); 72 | }); 73 | 74 | app.get('/docs', (req, res) => { 75 | res.sendFile(path.join(__dirname, 'redoc.html')); 76 | }); 77 | 78 | 79 | //Importing Routes 80 | const sendOTP_to_phone = require('./routes/sendOTP_to_phone'); 81 | const verify_otp = require('./routes/verifyOTP') 82 | const sendOTP_to_email = require('./routes/sendOTP_to_email') 83 | 84 | 85 | //Using imported Routes 86 | app.use('/api/v1', sendOTP_to_phone); 87 | app.use('/api/v1', verify_otp); 88 | app.use('/api/v1/', sendOTP_to_email); 89 | 90 | 91 | 92 | 93 | //================================================================================================================================== 94 | 95 | app.get('/', function (req, res) { 96 | console.log('route / is accessed.'); 97 | res.send('Hi'); 98 | }); 99 | 100 | app.listen(port, function () { 101 | console.log(`Server is running on port ${port}`); 102 | }); 103 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Node-js-OTP Service 2 | 3 | ### About 4 | 5 | It is an API that implements a OTP service in a scalable manner. In this, we do not need to store OTP with email or phone numbers rather a encrypted object is sent in response when OTP is requested which is decrypted and verified at the time of verification. 6 | 7 | ### Setup 8 | 9 | - Download postgreSQL from https://www.postgresql.org/download/ . 10 | - Setup postgres Database by using psql command line. 11 | - Get the Database Credentials. 12 | - Create a ```.env``` file in the project folder. 13 | 14 | ``` 15 | PORT= 16 | DB_PORT= 17 | DB_NAME= 18 | DB_HOST= 19 | DB_USER= 20 | DB_PASSWORD= 21 | EMAIL_ADDRESS= 22 | EMAIL_PASSWORD= 23 | AWS_ACCESS_KEY_ID= 24 | AWS_SECRET_ACCESS_KEY= 25 | AWS_REGION= 26 | IV= 27 | CRYPT_PASSWORD= 28 | ``` 29 | > Note : You have set a valid value for IV. Like: 30 | ``` 31 | IV=28408e46 32 | ``` 33 | - Use ` npm install` to install all the dependency for the project. 34 | - Database will be automatically migrated when the application starts. 35 | - Use ` npm start` to start the application. 36 | 37 | ## Usage 38 | 39 | #### To Send OTP to Emails 40 | 41 | - `/api/v1/email/otp` 42 | - _Allowed Methods_ : `POST` 43 | - `Description`: In this endpoint, we will take the email and type of the service request from any service using this OTP service and send the status and encrypted details in the response. 44 | - Request Object : 45 | ```json 46 | { 47 | "email":"", 48 | "type":"" 49 | } 50 | ``` 51 | > Note: Type can have 3 values that are : VERIFICATION, FORGET, 2FA. This is used to choose message template for email. 52 | 53 | - Response : 54 | - Status Code: 55 | - 200: 56 | ```json 57 | { 58 | "Status": "Success", 59 | "Details": "", 79 | "type":"" 80 | } 81 | ``` 82 | > Note: Type can have 3 values that are : VERIFICATION, FORGET, 2FA. This is used to choose message template for email. 83 | 84 | - Response : 85 | - Status Code: 86 | - 200: 87 | ```json 88 | { 89 | "Status": "Success", 90 | "Details": "", 110 | "verification_key": "", 111 | "check": "" 112 | } 113 | ``` 114 | > Note: Type can have 3 values that are : VERIFICATION, FORGET, 2FA. This is used to choose message template for email. 115 | 116 | - Response : 117 | - Status Code: 118 | - 200: 119 | ```json 120 | { 121 | "Status": "Success", 122 | "Details": "OTP Matched", 123 | "Check": "" 124 | } 125 | ``` 126 | - 400: 127 | ```json 128 | { 129 | "Status": "Failure", 130 | "Details": " { 69 | try{ 70 | const {email,type} = req.body; 71 | let email_subject, email_message 72 | if(!email){ 73 | const response={"Status":"Failure","Details":"Email not provided"} 74 | return res.status(400).send(response) 75 | } 76 | if(!type){ 77 | const response={"Status":"Failure","Details":"Type not provided"} 78 | return res.status(400).send(response) 79 | } 80 | 81 | //Generate OTP 82 | const otp = otpGenerator.generate(6, { alphabets: false, upperCase: false, specialChars: false }); 83 | const now = new Date(); 84 | const expiration_time = AddMinutesToDate(now,10); 85 | 86 | 87 | //Create OTP instance in DB 88 | const otp_instance = await OTP.create({ 89 | otp: otp, 90 | expiration_time: expiration_time 91 | }); 92 | 93 | // Create details object containing the email and otp id 94 | var details={ 95 | "timestamp": now, 96 | "check": email, 97 | "success": true, 98 | "message":"OTP sent to user", 99 | "otp_id": otp_instance.id 100 | } 101 | 102 | // Encrypt the details object 103 | const encoded= await encode(JSON.stringify(details)) 104 | 105 | //Choose message template according type requestedconst encoded= await encode(JSON.stringify(details)) 106 | if(type){ 107 | if(type=="VERIFICATION"){ 108 | const {message, subject_mail} = require('../templates/email/email_verification'); 109 | email_message=message(otp) 110 | email_subject=subject_mail 111 | } 112 | else if(type=="FORGET"){ 113 | const {message, subject_mail} = require('../templates/email/email_forget'); 114 | email_message=message(otp) 115 | email_subject=subject_mail 116 | } 117 | else if(type=="2FA"){ 118 | const {message, subject_mail} = require('../templates/email/email_2FA'); 119 | email_message=message(otp) 120 | email_subject=subject_mail 121 | } 122 | else{ 123 | const response={"Status":"Failure","Details":"Incorrect Type Provided"} 124 | return res.status(400).send(response) 125 | } 126 | } 127 | 128 | // Create nodemailer transporter 129 | const transporter = nodemailer.createTransport({ 130 | host: 'smtp.zoho.in', 131 | port: 465, 132 | secure: true, 133 | auth: { 134 | user: `${process.env.EMAIL_ADDRESS}`, 135 | pass: `${process.env.EMAIL_PASSWORD}` 136 | }, 137 | }); 138 | 139 | 140 | const mailOptions = { 141 | from: `"Divyansh Agarwal"<${process.env.EMAIL_ADDRESS}>`, 142 | to: `${email}`, 143 | subject: email_subject, 144 | text: email_message , 145 | }; 146 | 147 | await transporter.verify(); 148 | 149 | //Send Email 150 | await transporter.sendMail(mailOptions, (err, response) => { 151 | if (err) { 152 | return res.status(400).send({"Status":"Failure","Details": err }); 153 | } else { 154 | // console.log('here is the res: ', response); 155 | return res.send({"Status":"Success","Details":encoded}); 156 | } 157 | }); 158 | } 159 | catch(err){ 160 | const response={"Status":"Failure","Details": err.message} 161 | return res.status(400).send(response) 162 | } 163 | }); 164 | 165 | 166 | module.exports = router; 167 | -------------------------------------------------------------------------------- /routes/sendOTP_to_phone.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const {OTP} = require('../sequelize'); 3 | const router = require("express").Router(); 4 | const {encode} = require("../middlewares/crypt") 5 | var otpGenerator = require('otp-generator'); 6 | var AWS = require('aws-sdk'); 7 | const crypto = require('crypto'); 8 | 9 | 10 | /** 11 | * @swagger 12 | * /phone/otp: 13 | * post: 14 | * tags: 15 | * - OTP 16 | * name: Send OTP to Phone 17 | * summary: Send OTP to Phone 18 | * produces: 19 | * - application/json 20 | * consumes: 21 | * - application/json 22 | * parameters: 23 | * - name: body 24 | * in: body 25 | * schema: 26 | * type: object 27 | * properties: 28 | * phone_number: 29 | * type: string 30 | * type: 31 | * type: string 32 | * required: 33 | * - phone_number 34 | * - type 35 | * responses: 36 | * '200': 37 | * description: OTP sent successfully 38 | * content: 39 | * application/json: 40 | * schema: 41 | * $ref: '#/definitions/Details' 42 | * type: object 43 | * properties: 44 | * Status: 45 | * type: string 46 | * Details: 47 | * type: string 48 | * '400': 49 | * description: Number is not provided or Type is not provided 50 | * content: 51 | * application/json: 52 | * schema: 53 | * $ref: '#/definitions/Details' 54 | * type: object 55 | * properties: 56 | * Status: 57 | * type: string 58 | * Details: 59 | * type: string 60 | * '503': 61 | * description: OTP service not available for phone number as credentials are not set 62 | * content: 63 | * application/json: 64 | * schema: 65 | * $ref: '#/definitions/Details' 66 | * type: object 67 | * properties: 68 | * Status: 69 | * type: string 70 | * Details: 71 | * type: string 72 | */ 73 | 74 | // To add minutes to the current time 75 | function AddMinutesToDate(date, minutes) { 76 | return new Date(date.getTime() + minutes*60000); 77 | } 78 | 79 | 80 | router.post('/phone/otp', async (req, res, next) => { 81 | 82 | try{ 83 | 84 | if(!process.env.AWS_ACCESS_KEY_ID || !process.env.AWS_SECRET_ACCESS_KEY){ 85 | const response={"Status":"Failure","Details":"OTP for phone is not available right now"} 86 | return res.status(503).send(response) 87 | } 88 | 89 | const {phone_number,type} = req.body; 90 | 91 | let phone_message 92 | 93 | if(!phone_number){ 94 | const response={"Status":"Failure","Details":"Phone Number not provided"} 95 | return res.status(400).send(response) 96 | } 97 | if(!type){ 98 | const response={"Status":"Failure","Details":"Type not provided"} 99 | return res.status(400).send(response) 100 | } 101 | 102 | //Generate OTP 103 | const otp = otpGenerator.generate(6, { alphabets: false, upperCase: false, specialChars: false }); 104 | const now = new Date(); 105 | const expiration_time = AddMinutesToDate(now,10); 106 | 107 | 108 | //Create OTP instance in DB 109 | const otp_instance = await OTP.create({ 110 | otp: otp, 111 | expiration_time: expiration_time 112 | }); 113 | 114 | // Create details object containing the phone number and otp id 115 | var details={ 116 | "timestamp": now, 117 | "check": phone_number, 118 | "success": true, 119 | "message":"OTP sent to user", 120 | "otp_id": otp_instance.id 121 | } 122 | 123 | // Encrypt the details object 124 | const encoded= await encode(JSON.stringify(details)) 125 | 126 | //Choose message template according type requested 127 | if(type){ 128 | if(type=="VERIFICATION"){ 129 | const message = require('../templates/sms/phone_verification'); 130 | phone_message=message(otp) 131 | } 132 | else if(type=="FORGET"){ 133 | const message = require('../templates/sms/phone_forget'); 134 | phone_message=message(otp) 135 | } 136 | else if(type=="2FA"){ 137 | const message = require('../templates/sms/phone_2FA'); 138 | phone_message=message(otp) 139 | } 140 | else{ 141 | const response={"Status":"Failure","Details":"Incorrect Type Provided"} 142 | return res.status(400).send(response) 143 | } 144 | } 145 | 146 | // Settings Params for SMS 147 | var params = { 148 | Message: phone_message, 149 | PhoneNumber: phone_number 150 | }; 151 | 152 | //Send the params to AWS SNS using aws-sdk 153 | var publishTextPromise = new AWS.SNS({ apiVersion: '2010-03-31' }).publish(params).promise(); 154 | 155 | //Send response back to the client if the message is sent 156 | publishTextPromise.then( 157 | function (data) { 158 | return res.send({"Status":"Success","Details":encoded}); 159 | }).catch( 160 | function (err) { 161 | return res.status(400).send({"Status":"Failure","Details": err }); 162 | }); 163 | } 164 | catch(err){ 165 | const response={"Status":"Failure","Details": err.message} 166 | return res.status(400).send(response) 167 | } 168 | }); 169 | 170 | 171 | module.exports = router; 172 | -------------------------------------------------------------------------------- /routes/verifyOTP.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-console */ 2 | const {OTP} = require('../sequelize'); 3 | const router = require("express").Router(); 4 | const {decode} = require("../middlewares/crypt") 5 | 6 | 7 | 8 | /** 9 | * @swagger 10 | * /verify/otp: 11 | * post: 12 | * tags: 13 | * - OTP 14 | * name: Verify OTP 15 | * summary: Verify OTP 16 | * produces: 17 | * - application/json 18 | * consumes: 19 | * - application/json 20 | * parameters: 21 | * - name: body 22 | * in: body 23 | * schema: 24 | * type: object 25 | * properties: 26 | * otp: 27 | * type: string 28 | * verification_key: 29 | * type: string 30 | * check: 31 | * type: string 32 | * required: 33 | * - otp 34 | * - verification_key 35 | * - check 36 | * responses: 37 | * '200': 38 | * description: OTP Matched 39 | * content: 40 | * application/json: 41 | * schema: 42 | * $ref: '#/definitions/VerificationDetails' 43 | * type: object 44 | * properties: 45 | * Status: 46 | * type: string 47 | * Details: 48 | * type: string 49 | * Check: 50 | * type: string 51 | * '400': 52 | * description: OTP cannot be verified 53 | * content: 54 | * application/json: 55 | * schema: 56 | * $ref: '#/definitions/Details' 57 | * type: object 58 | * properties: 59 | * Status: 60 | * type: string 61 | * Details: 62 | * type: string 63 | */ 64 | 65 | // Function to Compares dates (expiration time and current time in our case) 66 | var dates = { 67 | convert:function(d) { 68 | // Converts the date in d to a date-object. The input can be: 69 | // a date object: returned without modification 70 | // an array : Interpreted as [year,month,day]. NOTE: month is 0-11. 71 | // a number : Interpreted as number of milliseconds 72 | // since 1 Jan 1970 (a timestamp) 73 | // a string : Any format supported by the javascript engine, like 74 | // "YYYY/MM/DD", "MM/DD/YYYY", "Jan 31 2009" etc. 75 | // an object : Interpreted as an object with year, month and date 76 | // attributes. **NOTE** month is 0-11. 77 | return ( 78 | d.constructor === Date ? d : 79 | d.constructor === Array ? new Date(d[0],d[1],d[2]) : 80 | d.constructor === Number ? new Date(d) : 81 | d.constructor === String ? new Date(d) : 82 | typeof d === "object" ? new Date(d.year,d.month,d.date) : 83 | NaN 84 | ); 85 | }, 86 | compare:function(a,b) { 87 | // Compare two dates (could be of any type supported by the convert 88 | // function above) and returns: 89 | // -1 : if a < b 90 | // 0 : if a = b 91 | // 1 : if a > b 92 | // NaN : if a or b is an illegal date 93 | // NOTE: The code inside isFinite does an assignment (=). 94 | return ( 95 | isFinite(a=this.convert(a).valueOf()) && 96 | isFinite(b=this.convert(b).valueOf()) ? 97 | (a>b)-(a { 119 | try{ 120 | var currentdate = new Date(); 121 | const {verification_key, otp, check} = req.body; 122 | 123 | if(!verification_key){ 124 | const response={"Status":"Failure","Details":"Verification Key not provided"} 125 | return res.status(400).send(response) 126 | } 127 | if(!otp){ 128 | const response={"Status":"Failure","Details":"OTP not Provided"} 129 | return res.status(400).send(response) 130 | } 131 | if(!check){ 132 | const response={"Status":"Failure","Details":"Check not Provided"} 133 | return res.status(400).send(response) 134 | } 135 | 136 | let decoded; 137 | 138 | //Check if verification key is altered or not and store it in variable decoded after decryption 139 | try{ 140 | decoded = await decode(verification_key) 141 | } 142 | catch(err) { 143 | const response={"Status":"Failure", "Details":"Bad Request"} 144 | return res.status(400).send(response) 145 | } 146 | 147 | var obj= JSON.parse(decoded) 148 | const check_obj = obj.check 149 | 150 | // Check if the OTP was meant for the same email or phone number for which it is being verified 151 | if(check_obj!=check){ 152 | const response={"Status":"Failure", "Details": "OTP was not sent to this particular email or phone number"} 153 | return res.status(400).send(response) 154 | } 155 | 156 | const otp_instance= await OTP.findOne({where:{id: obj.otp_id}}) 157 | 158 | //Check if OTP is available in the DB 159 | if(otp_instance!=null){ 160 | 161 | //Check if OTP is already used or not 162 | if(otp_instance.verified!=true){ 163 | 164 | //Check if OTP is expired or not 165 | if (dates.compare(otp_instance.expiration_time, currentdate)==1){ 166 | 167 | //Check if OTP is equal to the OTP in the DB 168 | if(otp===otp_instance.otp){ 169 | otp_instance.verified=true 170 | otp_instance.save() 171 | const response={"Status":"Success", "Details":"OTP Matched", "Check": check} 172 | return res.status(200).send(response) 173 | } 174 | else{ 175 | const response={"Status":"Failure","Details":"OTP NOT Matched"} 176 | return res.status(400).send(response) 177 | } 178 | 179 | } 180 | else{ 181 | const response={"Status":"Failure","Details":"OTP Expired"} 182 | return res.status(400).send(response) 183 | } 184 | } 185 | else{ 186 | const response={"Status":"Failure","Details":"OTP Already Used"} 187 | return res.status(400).send(response) 188 | } 189 | } 190 | else{ 191 | const response={"Status":"Failure","Details":"Bad Request"} 192 | return res.status(400).send(response) 193 | } 194 | } 195 | catch(err){ 196 | const response={"Status":"Failure","Details": err.message} 197 | return res.status(400).send(response) 198 | } 199 | }); 200 | 201 | 202 | module.exports = router; 203 | --------------------------------------------------------------------------------