From ff66ff92bd1d9ce8800338e261f7561227867f1b Mon Sep 17 00:00:00 2001 From: Ashish Sinsinwal Date: Sun, 3 Aug 2025 21:46:42 +0530 Subject: [PATCH 1/3] Add JWT authentication routes + controller --- backend/controllers/authController.js | 87 +++++++++++++++++++++++++++ backend/package-lock.json | 10 +++ backend/package.json | 1 + backend/routes/authRoutes.js | 11 ++++ backend/server.js | 3 + 5 files changed, 112 insertions(+) create mode 100644 backend/controllers/authController.js create mode 100644 backend/routes/authRoutes.js diff --git a/backend/controllers/authController.js b/backend/controllers/authController.js new file mode 100644 index 0000000..ffd48d4 --- /dev/null +++ b/backend/controllers/authController.js @@ -0,0 +1,87 @@ +const User = require("../models/user.model"); +const jwt = require("jsonwebtoken"); +const bcrypt = require("bcryptjs"); + +exports.register = async (req, res) => { + try { + const { name, email, password, role } = req.body; + + if (!name || !email || !password) { + return res.status(400).json({ message: 'Please provide all required fields' }); + } + + const existingUser = await User.findOne({ email }); + if (existingUser) { + return res.status(400).json({ message: 'User already exists' }); + } + + const hashedPassword = await bcrypt.hash(password, 10); + const newUser = new User({ + name, + email, + password: hashedPassword, + role: role || 'user' + }); + + await newUser.save(); + + const token = jwt.sign( + { id: newUser._id, role: newUser.role }, + process.env.JWT_SECRET, + { expiresIn: '7d' } + ); + + res.status(201).json({ + token, + user: { + id: newUser._id, + name: newUser.name, + email: newUser.email, + role: newUser.role, + } + }); + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Server error', error: err.message }); + } +}; + +exports.login = async (req, res) => { + try { + const { email, password } = req.body; + + if (!email || !password) { + return res.status(400).json({ message: 'Please provide email and password' }); + } + + const user = await User.findOne({ email }); + if (!user) { + return res.status(400).json({ message: 'Invalid credentials' }); + } + + const isMatch = await bcrypt.compare(password, user.password); + if (!isMatch) { + return res.status(400).json({ message: 'Invalid credentials' }); + } + + const token = jwt.sign( + { id: user._id, role: user.role }, + process.env.JWT_SECRET, + { expiresIn: '7d' } + ); + + res.json({ + token, + user: { + id: user._id, + name: user.name, + email: user.email, + role: user.role, + } + }); + + } catch (err) { + console.error(err); + res.status(500).json({ message: 'Server error', error: err.message }); + } +}; \ No newline at end of file diff --git a/backend/package-lock.json b/backend/package-lock.json index d3826af..30dcaf5 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -9,6 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { + "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", @@ -74,6 +75,15 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/bcryptjs": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-3.0.2.tgz", + "integrity": "sha512-k38b3XOZKv60C4E2hVsXTolJWfkGRMbILBIe2IBITXciy5bOsTKot5kDrf3ZfufQtQOUN5mXceUEpU1rTl9Uog==", + "license": "BSD-3-Clause", + "bin": { + "bcrypt": "bin/bcrypt" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", diff --git a/backend/package.json b/backend/package.json index 4a35df7..91054fb 100644 --- a/backend/package.json +++ b/backend/package.json @@ -12,6 +12,7 @@ "license": "ISC", "type": "module", "dependencies": { + "bcryptjs": "^3.0.2", "cors": "^2.8.5", "dotenv": "^16.5.0", "express": "^5.1.0", diff --git a/backend/routes/authRoutes.js b/backend/routes/authRoutes.js new file mode 100644 index 0000000..3a29389 --- /dev/null +++ b/backend/routes/authRoutes.js @@ -0,0 +1,11 @@ +const express = require("express"); +const router = express.Router(); +const { register, login } = require("../controllers/authController"); + +// POST /api/auth/register +router.post('/register', register); + +// POST /api/auth/login +router.post('/login', login); + +module.exports = router; \ No newline at end of file diff --git a/backend/server.js b/backend/server.js index 3e4175f..910898d 100644 --- a/backend/server.js +++ b/backend/server.js @@ -6,6 +6,7 @@ import mainRouter from "./routes/index.js" dotenv.config(); const app = express(); const PORT = process.env.PORT || 5000; +const authRouter = require("./routes/authRoutes.js"); app.use(cors()); app.use(express.json()); @@ -17,6 +18,8 @@ app.get('/', (req, res) => { res.send('Hello from the backend!'); }); +app.use('/api/auth' , authRouter); + // Start the server app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); From 0a01d9e968b694beee2086770ac6fc2341d5e954 Mon Sep 17 00:00:00 2001 From: Ashish Sinsinwal Date: Sun, 3 Aug 2025 21:57:12 +0530 Subject: [PATCH 2/3] Refactor auth middleware: add requireRole and rename verifyToken --- backend/middleware/authMiddleware.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/backend/middleware/authMiddleware.js b/backend/middleware/authMiddleware.js index 3fbdd29..f0d7566 100644 --- a/backend/middleware/authMiddleware.js +++ b/backend/middleware/authMiddleware.js @@ -3,7 +3,7 @@ import jwt from 'jsonwebtoken'; dotenv.config(); -const authMiddleware=(req,res,next)=>{ +exports.verifyToken = (req,res,next) => { const authHeader=req.headers.authorization; if(!authHeader || !authHeader.startsWith('Bearer ')){ return res.status(403).json({ @@ -20,5 +20,14 @@ const authMiddleware=(req,res,next)=>{ msg:"Forbidden request" }) } -} -export default authMiddleware; \ No newline at end of file +}; + +// For role-based access (e.g., admin only) +exports.requireRole = (role) => { + return (req, res, next) => { + if (req.user.role !== role) { + return res.status(403).json({ message: 'Access denied' }); + } + next(); + }; +}; From 99ee42e32d0b0d76f22b2b3068f11e6bbcc57145 Mon Sep 17 00:00:00 2001 From: Ashish Sinsinwal Date: Thu, 7 Aug 2025 12:24:51 +0530 Subject: [PATCH 3/3] added Cloudinary file upload integration --- backend/cloudConfig.js | 20 +++ backend/routes/pg.routes.js | 4 +- package-lock.json | 256 +++++++++++++++++++++++++++++++++++- package.json | 7 + 4 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 backend/cloudConfig.js create mode 100644 package.json diff --git a/backend/cloudConfig.js b/backend/cloudConfig.js new file mode 100644 index 0000000..0ccb215 --- /dev/null +++ b/backend/cloudConfig.js @@ -0,0 +1,20 @@ +const cloudinary = require('cloudinary').v2; +const { CloudinaryStorage } = require('multer-storage-cloudinary'); + +cloudinary.config({ + cloud_name:process.env.CLOUD_NAME, + api_key:process.env.CLOUD_API_KEY, + api_secret:process.env.CLOUD_API_SECRET +}); + +const storage = new CloudinaryStorage({ + cloudinary: cloudinary, + params: { + folder: 'pg-finder', + allowed_Format:["png" , "jpeg" , "jpg"], + }, +}); + +module.exports = { + cloudinary , storage +} \ No newline at end of file diff --git a/backend/routes/pg.routes.js b/backend/routes/pg.routes.js index d6a9253..a678414 100644 --- a/backend/routes/pg.routes.js +++ b/backend/routes/pg.routes.js @@ -1,6 +1,8 @@ import express from 'express'; import { Pg } from '../config/db.js'; - +const {storage} = require('../cloudConfig.js'); +const multer = require('multer'); +const upload = multer({storage}); const router = express.Router(); diff --git a/package-lock.json b/package-lock.json index 4be99a4..6d4c26c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2,5 +2,259 @@ "name": "pg-finder", "lockfileVersion": 3, "requires": true, - "packages": {} + "packages": { + "": { + "dependencies": { + "cloudinary": "^1.21.0", + "multer": "^2.0.2", + "multer-storage-cloudinary": "^4.0.0" + } + }, + "node_modules/append-field": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", + "integrity": "sha512-klpgFSWLW1ZEs8svjfb7g4qWY0YS5imI82dTg+QahUvJ8YqAY0P10Uk8tTyh9ZGuYEZEMaeJYCF5BFuX552hsw==", + "license": "MIT" + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT" + }, + "node_modules/busboy": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", + "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==", + "dependencies": { + "streamsearch": "^1.1.0" + }, + "engines": { + "node": ">=10.16.0" + } + }, + "node_modules/cloudinary": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-1.21.0.tgz", + "integrity": "sha512-am8wpHbHl8bcpy9oGSlWrpWLNQ9szkW/jmhcJdEpMjaL23BYt05V1frWyrXDlo8Jt7aCo5NE6EO0CM9Zaynd5g==", + "license": "MIT", + "dependencies": { + "lodash": "^4.17.11", + "q": "^1.5.1" + }, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/multer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/multer/-/multer-2.0.2.tgz", + "integrity": "sha512-u7f2xaZ/UG8oLXHvtF/oWTRvT44p9ecwBBqTwgJVq0+4BW1g8OW01TyMEGWBHbyMOYVHXslaut7qEQ1meATXgw==", + "license": "MIT", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "concat-stream": "^2.0.0", + "mkdirp": "^0.5.6", + "object-assign": "^4.1.1", + "type-is": "^1.6.18", + "xtend": "^4.0.2" + }, + "engines": { + "node": ">= 10.16.0" + } + }, + "node_modules/multer-storage-cloudinary": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multer-storage-cloudinary/-/multer-storage-cloudinary-4.0.0.tgz", + "integrity": "sha512-25lm9R6o5dWrHLqLvygNX+kBOxprzpmZdnVKH4+r68WcfCt8XV6xfQaMuAg+kUE5Xmr8mJNA4gE0AcBj9FJyWA==", + "license": "MIT", + "peerDependencies": { + "cloudinary": "^1.21.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/q": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz", + "integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==", + "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/streamsearch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz", + "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + } + } } diff --git a/package.json b/package.json new file mode 100644 index 0000000..a08263c --- /dev/null +++ b/package.json @@ -0,0 +1,7 @@ +{ + "dependencies": { + "cloudinary": "^1.21.0", + "multer": "^2.0.2", + "multer-storage-cloudinary": "^4.0.0" + } +}