From fd2b42f9eb5ea8f4f8f742e9c91406c0e11c000b Mon Sep 17 00:00:00 2001
From: Biswakalyan Bhuyan <biswa@surgot.in>
Date: Sat, 27 Jul 2024 22:06:20 +0530
Subject: added Input Validation/Sanitization

---
 backend/index.js | 102 ++++++++++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 82 insertions(+), 20 deletions(-)

(limited to 'backend')

diff --git a/backend/index.js b/backend/index.js
index f70153a..b23adc9 100644
--- a/backend/index.js
+++ b/backend/index.js
@@ -1,17 +1,17 @@
+require('dotenv').config();
 const express = require('express');
 const rateLimit = require('express-rate-limit');
 const bodyParser = require('body-parser');
 const bcrypt = require('bcryptjs');
 const jwt = require('jsonwebtoken');
 const admin = require('firebase-admin');
-const cors = require('cors'); // Import the cors package
-require('dotenv').config(); // Load environment variables from .env
+const cors = require('cors');
+const { body, validationResult } = require('express-validator');
 
+// Initialize Express app
 const app = express();
 app.use(bodyParser.json());
-
-// Enable CORS for all origins
-app.use(cors());
+app.use(cors()); // Enable CORS for all origins
 
 // Firebase Admin SDK setup
 const serviceAccount = {
@@ -28,31 +28,60 @@ const serviceAccount = {
 };
 
 admin.initializeApp({
-  credential: admin.credential.cert(serviceAccount)
+  credential: admin.credential.cert(serviceAccount),
+  storageBucket: process.env.FIREBASE_BUCKET, // Specify the bucket name here
 });
 
 const db = admin.firestore();
+const bucket = admin.storage().bucket(); // Access the bucket
 
 // Secret key for JWT
-const JWT_SECRET = process.env.JWT_SECRET_KEY;
+const JWT_SECRET = process.env.JWT_SECRET;
 
 // Rate Limiting middleware
 const limiter = rateLimit({
-  	windowMs: 15 * 60 * 1000, // 15 minutes
-  	max: 100, // limit each IP to 100 requests per windowMs
-	message: 'Too many requests from this IP, please try again after 15 minutes',
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 100, // Limit each IP to 100 requests per windowMs
+  message: 'Too many requests from this IP, please try again after 15 minutes',
 });
 
 // Apply rate limiter to all requests
 app.use(limiter);
 
-// Register route
-app.post('/register', async (req, res) => {
-  const { username, password } = req.body;
-
-  if (!username || !password) {
-    return res.status(400).send('Username and password are required');
+// Validation and sanitization middleware for registration
+const registerValidationRules = () => [
+  body('username')
+    .isLength({ min: 3 }).withMessage('Username must be at least 3 characters long')
+    .trim()
+    .escape(),
+  body('password')
+    .isLength({ min: 6 }).withMessage('Password must be at least 6 characters long')
+    .trim()
+];
+
+// Validation and sanitization middleware for login
+const loginValidationRules = () => [
+  body('username')
+    .isLength({ min: 3 }).withMessage('Username must be at least 3 characters long')
+    .trim()
+    .escape(),
+  body('password')
+    .isLength({ min: 6 }).withMessage('Password must be at least 6 characters long')
+    .trim()
+];
+
+// Middleware to check validation results
+const validate = (req, res, next) => {
+  const errors = validationResult(req);
+  if (!errors.isEmpty()) {
+    return res.status(400).json({ errors: errors.array() });
   }
+  next();
+};
+
+// Register route with validation and sanitization
+app.post('/register', registerValidationRules(), validate, async (req, res) => {
+  const { username, password } = req.body;
 
   const hashedPassword = await bcrypt.hash(password, 10);
 
@@ -69,8 +98,8 @@ app.post('/register', async (req, res) => {
   }
 });
 
-// Login route
-app.post('/login', async (req, res) => {
+// Login route with validation and sanitization
+app.post('/login', loginValidationRules(), validate, async (req, res) => {
   const { username, password } = req.body;
 
   try {
@@ -85,7 +114,7 @@ app.post('/login', async (req, res) => {
       return res.status(400).send('Invalid username or password');
     }
 
-    const token = jwt.sign({ username: user.username }, process.env.JWT_SECRET, { expiresIn: '1h' });
+    const token = jwt.sign({ username: user.username }, JWT_SECRET, { expiresIn: '1h' });
     res.json({ token });
   } catch (error) {
     console.error('Error during login:', error);
@@ -105,7 +134,40 @@ app.get('/ads', async (req, res) => {
   }
 });
 
-const PORT = 5000;
+// Increment ad view count route
+app.post('/ads/:id/view', async (req, res) => {
+  const { id } = req.params;
+
+  try {
+    const adRef = db.collection('ads').doc(id);
+    await adRef.update({
+      view_count: admin.firestore.FieldValue.increment(1),
+    });
+    res.status(200).json({ message: 'View count incremented' });
+  } catch (error) {
+    console.error('Error incrementing ad view count:', error);
+    res.status(500).send('Error incrementing ad view count');
+  }
+});
+
+// Get ad view counts route
+app.get('/ads/:id/view-count', async (req, res) => {
+  const { id } = req.params;
+
+  try {
+    const adDoc = await db.collection('ads').doc(id).get();
+    if (!adDoc.exists) {
+      return res.status(404).send('Ad not found');
+    }
+    res.json({ view_count: adDoc.data().view_count });
+  } catch (error) {
+    console.error('Error fetching ad view count:', error);
+    res.status(500).send('Error fetching ad view count');
+  }
+});
+
+// Start the server
+const PORT = process.env.PORT || 5000;
 app.listen(PORT, () => {
   console.log(`Server running on http://localhost:${PORT}`);
 });
-- 
cgit v1.2.3-59-g8ed1b