Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
163 changes: 163 additions & 0 deletions environment-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
# Environment Configuration Setup

## Required .env Files

Create `.env` file in **each backend directory** with these variables:

### 1. budgetapp/backend/.env

```bash
NODE_ENV=development
PORT=7000
MONGODB_URL=mongodb://localhost:27017/wedding_budget
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-budget
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-budget
```

### 2. eventapp/backend/.env

```bash
NODE_ENV=development
PORT=5003
MONGO_CONNECTION_STRING=mongodb://localhost:27017/wedding_events
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-events
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-events
GOOGLE_CLIENT_ID=your-google-oauth-client-id
GOOGLE_CLIENT_SECRET=your-google-oauth-client-secret
GOOGLE_CALLBACK_URL=http://localhost:5003/auth/google/callback
FRONTEND_URL=http://localhost:3003
```

### 3. guestapp/backend/.env

```bash
NODE_ENV=development
PORT=5002
MONGO_URL=mongodb://localhost:27017/wedding_guests
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-guests
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-guests
```

### 4. mainapp/backend/.env

```bash
NODE_ENV=development
PORT=8000
MONGO_URI=mongodb://localhost:27017/wedding_main
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-main
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-main
```

### 5. packageapp/backend/.env

```bash
NODE_ENV=development
PORT=5000
MONGO_URI=mongodb://localhost:27017/wedding_packages
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-packages
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-packages
```

### 6. vendorapp/backend/.env

```bash
NODE_ENV=development
PORT=5001
MONGO_URL=mongodb://localhost:27017/wedding_vendors
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-vendors
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-vendors
SECRET_KEY=your-vendor-specific-secret-key-minimum-32-characters
```

### 7. feedbackapp/backend/.env

```bash
NODE_ENV=development
PORT=3001
MONGO_URI=mongodb://localhost:27017/wedding_feedback
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-feedback
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-feedback
ADMIN_PASSWORD=your-admin-password-for-basic-auth
```

### 8. taskapp/backend/.env

```bash
NODE_ENV=development
PORT=8080
MONGO_URL=mongodb://localhost:27017/wedding_tasks
JWT_SECRET_KEY=your-super-secret-jwt-key-minimum-32-characters-tasks
SESSION_SECRET=your-super-secret-session-key-minimum-32-characters-tasks
FRONTEND_DOMAIN=http://localhost:3000
GOOGLE_CLIENT_ID=your-google-oauth-client-id
GOOGLE_CLIENT_SECRET=your-google-oauth-client-secret
FACEBOOK_CLIENT_ID=your-facebook-oauth-client-id
FACEBOOK_CLIENT_SECRET=your-facebook-oauth-client-secret
```

## Security Requirements

### Secret Key Generation

Use this command to generate secure keys:

```bash
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
```

### Database Setup

1. Install MongoDB locally or use MongoDB Atlas
2. Create separate databases for each service
3. Ensure MongoDB authentication is enabled in production

### OAuth Setup

1. Create Google OAuth application at: https://console.cloud.google.com/
2. Create Facebook OAuth application at: https://developers.facebook.com/
3. Set appropriate callback URLs

## Installation Script

Create this script to set up all environments:

```bash
#!/bin/bash
# setup-env.sh

# Generate a secure key
generate_key() {
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
}

# Create .env files for each backend
backends=("budgetapp" "eventapp" "guestapp" "mainapp" "packageapp" "vendorapp" "feedbackapp" "taskapp")

for backend in "${backends[@]}"; do
if [ -d "${backend}/backend" ]; then
echo "Setting up ${backend}/backend/.env"
# Copy template and replace placeholders
# (Implementation depends on your setup)
fi
done

echo "Environment setup complete!"
echo "Remember to:"
echo "1. Update all placeholder values with actual secrets"
echo "2. Set up OAuth applications"
echo "3. Configure MongoDB connection strings"
echo "4. Never commit .env files to version control"
```

## Verification

Test your setup:

```bash
# Check each backend can start
cd budgetapp/backend && npm start
cd eventapp/backend && npm start
# ... etc for each backend
```

**IMPORTANT**: Never commit `.env` files to version control!
10 changes: 0 additions & 10 deletions eventapp/backend/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,7 @@ const {
getCorsOptions,
} = require("../../middleware/securityHeaders.js");

// --- Auth deps ---
const session = require("express-session");
const passport = require("passport");
const GoogleStrategy = require("passport-google-oauth20").Strategy;
const jwt = require("jsonwebtoken");
const User = require("./models/user/user.model");

// --- App setup ---
const app = express();

const environment = process.env.NODE_ENV || "development";

// Setup security headers and middleware
Expand All @@ -33,7 +24,6 @@ app.use(express.urlencoded({ extended: true, limit: "5mb" }));

const port = process.env.PORT || 5003;


// CORS: allow your frontend + credentials (cookies)
app.use(
cors({
Expand Down
25 changes: 18 additions & 7 deletions feedbackapp/backend/routes/feedbackRouter.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,21 @@
const express = require('express');
const express = require("express");
const router = express.Router();
const controller = require('../controllers/feedbackController');
const controller = require("../controllers/feedbackController");
const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");

router.get('/feedbacks',controller.getFeedback);
router.post('/createfeedback',controller.addFeedback);
router.post('/updatefeedback',controller.updateFeedback);
router.post('/deletefeedback',controller.deleteFeedback);
router.get("/feedbacks", controller.getFeedback);

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.

Copilot Autofix

AI 10 months ago

To fix the missing rate limiting on the /feedbacks route, add a rate-limiting middleware before the controller.getFeedback handler on this route. The best practice is to use a well-known rate-limiting package, express-rate-limit, which is easy to use and effective. Add the import for express-rate-limit, define a limiter with a reasonable limit (e.g., 100 requests per 15 minutes), and insert the limiter as middleware to the /feedbacks route. Restrict changes strictly to the code you've been shown: only edit feedbackapp/backend/routes/feedbackRouter.js and add minimal required code in visible regions.

Suggested changeset 2
feedbackapp/backend/routes/feedbackRouter.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/routes/feedbackRouter.js b/feedbackapp/backend/routes/feedbackRouter.js
--- a/feedbackapp/backend/routes/feedbackRouter.js
+++ b/feedbackapp/backend/routes/feedbackRouter.js
@@ -1,9 +1,16 @@
 const express = require("express");
 const router = express.Router();
+const RateLimit = require("express-rate-limit");
 const controller = require("../controllers/feedbackController");
 const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");
 
-router.get("/feedbacks", controller.getFeedback);
+// set up rate limiter: maximum of 100 requests per 15 minutes
+const feedbacksLimiter = RateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 100 // Limit each IP to 100 requests per windowMs
+});
+
+router.get("/feedbacks", feedbacksLimiter, controller.getFeedback);
 router.post("/createfeedback", basicAuth, controller.addFeedback);
 router.post(
   "/updatefeedback",
EOF
@@ -1,9 +1,16 @@
const express = require("express");
const router = express.Router();
const RateLimit = require("express-rate-limit");
const controller = require("../controllers/feedbackController");
const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");

router.get("/feedbacks", controller.getFeedback);
// set up rate limiter: maximum of 100 requests per 15 minutes
const feedbacksLimiter = RateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 100 // Limit each IP to 100 requests per windowMs
});

router.get("/feedbacks", feedbacksLimiter, controller.getFeedback);
router.post("/createfeedback", basicAuth, controller.addFeedback);
router.post(
"/updatefeedback",
feedbackapp/backend/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/package.json b/feedbackapp/backend/package.json
--- a/feedbackapp/backend/package.json
+++ b/feedbackapp/backend/package.json
@@ -13,6 +13,7 @@
   "dependencies": {
     "cors": "^2.8.5",
     "express": "^4.19.2",
-    "mongoose": "^8.3.0"
+    "mongoose": "^8.3.0",
+    "express-rate-limit": "^8.1.0"
   }
 }
EOF
@@ -13,6 +13,7 @@
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"mongoose": "^8.3.0"
"mongoose": "^8.3.0",
"express-rate-limit": "^8.1.0"
}
}
This fix introduces these dependencies
Package Version Security advisories
express-rate-limit (npm) 8.1.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
router.post("/createfeedback", basicAuth, controller.addFeedback);
router.post(
"/updatefeedback",
basicAuth,
requireAdmin,
controller.updateFeedback

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.

Copilot Autofix

AI 10 months ago

To fix this problem, we should apply a rate-limiting middleware to the database-modifying routes: /updatefeedback and /deletefeedback (and optionally /createfeedback and /feedbacks for completeness). The standard way is to use the express-rate-limit npm package, which is specifically designed for Express applications. The solution involves:

  • Importing express-rate-limit in this router file.
  • Creating a rate limiter instance for these routes (ideally, set moderate limits suitable for admin actions).
  • Adding the rate limiter as middleware in the relevant route definitions, just before the controller functions.
  • Minimal changes elsewhere; no change in route logic or authorization.

This involves (1) adding the required import, (2) instantiating a rate limiter, and (3) editing the route definitions to use the rate limiter.


Suggested changeset 2
feedbackapp/backend/routes/feedbackRouter.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/routes/feedbackRouter.js b/feedbackapp/backend/routes/feedbackRouter.js
--- a/feedbackapp/backend/routes/feedbackRouter.js
+++ b/feedbackapp/backend/routes/feedbackRouter.js
@@ -2,19 +2,28 @@
 const router = express.Router();
 const controller = require("../controllers/feedbackController");
 const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");
+const rateLimit = require("express-rate-limit");
 
+// Create a rate limiter for admin routes (adjust as needed)
+const adminLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 20, // limit each IP to 20 requests per windowMs for admin actions
+  message: "Too many requests, please try again later.",
+});
 router.get("/feedbacks", controller.getFeedback);
 router.post("/createfeedback", basicAuth, controller.addFeedback);
 router.post(
   "/updatefeedback",
   basicAuth,
   requireAdmin,
+  adminLimiter,
   controller.updateFeedback
 );
 router.post(
   "/deletefeedback",
   basicAuth,
   requireAdmin,
+  adminLimiter,
   controller.deleteFeedback
 );
 
EOF
@@ -2,19 +2,28 @@
const router = express.Router();
const controller = require("../controllers/feedbackController");
const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");
const rateLimit = require("express-rate-limit");

// Create a rate limiter for admin routes (adjust as needed)
const adminLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 20, // limit each IP to 20 requests per windowMs for admin actions
message: "Too many requests, please try again later.",
});
router.get("/feedbacks", controller.getFeedback);
router.post("/createfeedback", basicAuth, controller.addFeedback);
router.post(
"/updatefeedback",
basicAuth,
requireAdmin,
adminLimiter,
controller.updateFeedback
);
router.post(
"/deletefeedback",
basicAuth,
requireAdmin,
adminLimiter,
controller.deleteFeedback
);

feedbackapp/backend/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/package.json b/feedbackapp/backend/package.json
--- a/feedbackapp/backend/package.json
+++ b/feedbackapp/backend/package.json
@@ -13,6 +13,7 @@
   "dependencies": {
     "cors": "^2.8.5",
     "express": "^4.19.2",
-    "mongoose": "^8.3.0"
+    "mongoose": "^8.3.0",
+    "express-rate-limit": "^8.1.0"
   }
 }
EOF
@@ -13,6 +13,7 @@
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"mongoose": "^8.3.0"
"mongoose": "^8.3.0",
"express-rate-limit": "^8.1.0"
}
}
This fix introduces these dependencies
Package Version Security advisories
express-rate-limit (npm) 8.1.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
);
router.post(
"/deletefeedback",
basicAuth,
requireAdmin,
controller.deleteFeedback

Check failure

Code scanning / CodeQL

Missing rate limiting High

This route handler performs
a database access
, but is not rate-limited.

Copilot Autofix

AI 10 months ago

To fix the issue, add rate limiting middleware to the /deletefeedback route (and potentially other sensitive, database-modifying routes). The best practice is to use a well-known, battle-tested middleware such as express-rate-limit. This can be required at the top of the file, configured with reasonable defaults (e.g., allowing a modest number of requests per minute), and then added as middleware specifically to the affected route(s) (e.g., /deletefeedback). Only apply it to the relevant routes to avoid overly restricting the rest of the API.

Specifically:

  • Import and configure express-rate-limit near the top of feedbackRouter.js.
  • Create a limiter instance (e.g., allowing 10 delete requests per 15 minutes).
  • Add this limiter as middleware to the /deletefeedback POST route (between authentication and controller).
  • Add the required import at the top of the file.
Suggested changeset 2
feedbackapp/backend/routes/feedbackRouter.js

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/routes/feedbackRouter.js b/feedbackapp/backend/routes/feedbackRouter.js
--- a/feedbackapp/backend/routes/feedbackRouter.js
+++ b/feedbackapp/backend/routes/feedbackRouter.js
@@ -3,6 +3,14 @@
 const controller = require("../controllers/feedbackController");
 const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");
 
+// Rate limiting for sensitive modifying routes
+const rateLimit = require('express-rate-limit');
+const deleteFeedbackLimiter = rateLimit({
+  windowMs: 15 * 60 * 1000, // 15 minutes
+  max: 10, // limit each IP to 10 delete requests per windowMs
+  message: 'Too many delete requests from this IP, please try again after 15 minutes'
+});
+
 router.get("/feedbacks", controller.getFeedback);
 router.post("/createfeedback", basicAuth, controller.addFeedback);
 router.post(
@@ -15,6 +23,7 @@
   "/deletefeedback",
   basicAuth,
   requireAdmin,
+  deleteFeedbackLimiter,
   controller.deleteFeedback
 );
 
EOF
@@ -3,6 +3,14 @@
const controller = require("../controllers/feedbackController");
const { basicAuth, requireAdmin } = require("../../../middleware/basicAuth.js");

// Rate limiting for sensitive modifying routes
const rateLimit = require('express-rate-limit');
const deleteFeedbackLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10, // limit each IP to 10 delete requests per windowMs
message: 'Too many delete requests from this IP, please try again after 15 minutes'
});

router.get("/feedbacks", controller.getFeedback);
router.post("/createfeedback", basicAuth, controller.addFeedback);
router.post(
@@ -15,6 +23,7 @@
"/deletefeedback",
basicAuth,
requireAdmin,
deleteFeedbackLimiter,
controller.deleteFeedback
);

feedbackapp/backend/package.json
Outside changed files

Autofix patch

Autofix patch
Run the following command in your local git repository to apply this patch
cat << 'EOF' | git apply
diff --git a/feedbackapp/backend/package.json b/feedbackapp/backend/package.json
--- a/feedbackapp/backend/package.json
+++ b/feedbackapp/backend/package.json
@@ -13,6 +13,7 @@
   "dependencies": {
     "cors": "^2.8.5",
     "express": "^4.19.2",
-    "mongoose": "^8.3.0"
+    "mongoose": "^8.3.0",
+    "express-rate-limit": "^8.1.0"
   }
 }
EOF
@@ -13,6 +13,7 @@
"dependencies": {
"cors": "^2.8.5",
"express": "^4.19.2",
"mongoose": "^8.3.0"
"mongoose": "^8.3.0",
"express-rate-limit": "^8.1.0"
}
}
This fix introduces these dependencies
Package Version Security advisories
express-rate-limit (npm) 8.1.0 None
Copilot is powered by AI and may make mistakes. Always verify output.
);

module.exports = router;
module.exports = router;
43 changes: 27 additions & 16 deletions feedbackapp/backend/server.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,44 @@
const express = require('express');
const express = require("express");
const app = express();
const cors = require('cors');
const dotenv = require('dotenv');
const cors = require("cors");
const dotenv = require("dotenv");
dotenv.config();

const port = 3001;
const host = 'localhost';
const mongoose = require('mongoose');
const router = require('./routes/feedbackRouter');
const host = "localhost";
const mongoose = require("mongoose");
const router = require("./routes/feedbackRouter");

app.use(cors()); //cors origin unblocking(cross origine resoures sharing)
app.use(
cors({
origin: [
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:3004",
],
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
allowedHeaders: ["Content-Type", "Authorization"],
})
); //cors origin blocking for security
app.use(express.json());

// Use environment variable for MongoDB URI
const uri = process.env.MONGO_URI;
const connect = async () => {
try {
await mongoose.connect(uri);
console.log('connected to mongoDB');
} catch (error) {
console.log('mongoDB error: ',error);
}
try {
await mongoose.connect(uri);
console.log("connected to mongoDB");
} catch (error) {
console.log("mongoDB error: ", error);
}
};

connect();

//call back function
const server = app.listen(port,host, () => {
console.log(`Node server is listing to ${server.address().port}`)
const server = app.listen(port, host, () => {
console.log(`Node server is listing to ${server.address().port}`);
});

app.use('/api',router);
app.use("/api", router);
13 changes: 12 additions & 1 deletion guestapp/backend/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,18 @@ dotenv.config();
// app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }))

app.use(express.json({ limit: "10mb" }));
app.use(cors());
app.use(
cors({
origin: [
"http://localhost:3000",
"http://localhost:3001",
"http://localhost:3003",
],
credentials: true,
methods: ["GET", "POST", "PUT", "DELETE", "PATCH"],
allowedHeaders: ["Content-Type", "Authorization"],
})
);

mongoose
.connect(process.env.MONGO_URL, {
Expand Down
8 changes: 6 additions & 2 deletions middleware/auth.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,12 @@ const authenticateUser = async (req, res, next) => {
});
}

// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY);
// Verify token with specific algorithm to prevent attacks
const decoded = jwt.verify(token, process.env.JWT_SECRET_KEY, {
algorithms: ["HS256"],
issuer: "wedding-management-system",
maxAge: "1h",
});

// Get user from database
const user = await User.findById(decoded.id);
Expand Down
51 changes: 51 additions & 0 deletions middleware/basicAuth.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Basic authentication middleware for applications without full user management
const basicAuth = (req, res, next) => {
const authHeader = req.headers.authorization;

if (!authHeader || !authHeader.startsWith("Basic ")) {
return res.status(401).json({
error: "Authentication required",
code: "NO_AUTH",
});
}

try {
const base64Credentials = authHeader.substring(6);
const credentials = Buffer.from(base64Credentials, "base64").toString(
"ascii"
);
const [username, password] = credentials.split(":");

// Simple admin check (in production, use proper user management)
if (username === "admin" && password === process.env.ADMIN_PASSWORD) {
req.user = { role: "admin", username: "admin" };
next();
} else {
return res.status(401).json({
error: "Invalid credentials",
code: "INVALID_CREDENTIALS",
});
}
} catch (error) {
return res.status(401).json({
error: "Invalid authorization header",
code: "INVALID_AUTH_HEADER",
});
}
};

// Role-based authorization
const requireAdmin = (req, res, next) => {
if (!req.user || req.user.role !== "admin") {
return res.status(403).json({
error: "Admin access required",
code: "ADMIN_REQUIRED",
});
}
next();
};

module.exports = {
basicAuth,
requireAdmin,
};
14 changes: 10 additions & 4 deletions middleware/security.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,16 +41,22 @@ const validateInput = (schema) => {
// Search query sanitizer
const sanitizeSearchQuery = (req, res, next) => {
if (req.query.search) {
// Escape special regex characters
req.query.search = req.query.search.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");

// Limit search length
// Validate search query length first
if (req.query.search.length > 100) {
return res.status(400).json({
error: "Search query too long",
code: "SEARCH_TOO_LONG",
});
}

// Use safer character allowlist instead of escaping
const safePattern = /^[a-zA-Z0-9\s\-_]+$/;
if (!safePattern.test(req.query.search)) {
return res.status(400).json({
error: "Search query contains invalid characters",
code: "INVALID_SEARCH_CHARS",
});
}
}
next();
};
Expand Down
Loading
Loading