From fd2b42f9eb5ea8f4f8f742e9c91406c0e11c000b Mon Sep 17 00:00:00 2001 From: Biswakalyan Bhuyan 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