Skip to content

Commit 06c2b44

Browse files
committed
Feat: Secure API with Zod validation, fix NoSQL/XSS vulnerabilities, and add Jest integration tests
1 parent 3a1dd5b commit 06c2b44

5 files changed

Lines changed: 5695 additions & 1038 deletions

File tree

‎backend/app.js‎

Lines changed: 74 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -4,97 +4,108 @@ const mongoose = require('mongoose');
44
const cors = require('cors');
55
require('dotenv').config();
66

7+
// Middleware
78
app.use(cors());
8-
99
app.use(express.json());
1010
app.use(express.urlencoded({ extended: true }));
1111

12-
13-
console.log(process.env.MONGO_URL);
14-
const connectDB = async () => {
15-
try {
16-
await mongoose.connect(process.env.MONGO_URL);
17-
console.log("✅ MongoDB Connected");
18-
} catch (err) {
19-
console.error("❌ MongoDB Connection Error:", err);
20-
setTimeout(connectDB, 5000);
21-
}
22-
};
23-
24-
mongoose.connection.on('error', (err) => {
25-
console.error("MongoDB Runtime Error:", err);
26-
});
27-
28-
mongoose.connection.on('disconnected', () => {
29-
console.warn("MongoDB Disconnected. Retrying...");
30-
connectDB();
31-
});
32-
33-
connectDB();
34-
35-
36-
app.get('/', (req, res) => {
37-
res.send("listening")
38-
})
39-
12+
// --- IMPORTS ---
4013
const { limiter, logger } = require('./middleware/api_usage');
4114
const verifyApiKey = require('./middleware/verifyApiKey');
4215

43-
// defining Routes
16+
// Route Imports
4417
const authRoute = require('./routes/auth');
4518
const projectRoute = require('./routes/projects');
4619
const dataRoute = require('./routes/data');
4720
const userAuthRoute = require('./routes/userAuth');
4821
const storageRoute = require('./routes/storage');
4922

23+
// --- ROUTES SETUP ---
24+
app.use('/api/', limiter); // Rate Limiter
25+
app.use('/api/auth', authRoute); // Developer Auth
26+
app.use('/api/projects', projectRoute); // Project Mgmt
5027

51-
// Using routes
52-
app.use('/api/', limiter);
53-
app.use('/api/auth', authRoute);
54-
app.use('/api/projects', projectRoute);
55-
28+
// Logger added to userAuth route
5629
app.use('/api/userAuth', logger, userAuthRoute);
5730

31+
// Data & Storage Routes (Protected)
5832
app.use('/api/data', verifyApiKey, logger, dataRoute);
5933
app.use('/api/storage', verifyApiKey, logger, storageRoute);
6034

61-
app.use((err, req, res, next) => {
62-
console.error("Unhandled Error:", err);
63-
res.status(500).json({ error: "Something went wrong!" });
35+
// Test Route
36+
app.get('/', (req, res) => {
37+
res.send("urBackend API is running 🚀");
6438
});
6539

66-
const PORT = process.env.PORT || 1234;
67-
68-
69-
const server = app.listen(PORT, () => {
70-
console.log(`Server running on port ${PORT}`);
40+
// 🛡️ FAULT TOLERANCE: Global Error Handler
41+
app.use((err, req, res, next) => {
42+
console.error("🔥 Unhandled Error:", err.stack);
43+
res.status(500).json({
44+
error: "Something went wrong!",
45+
message: err.message
46+
});
7147
});
7248

73-
// 🛡️ GRACEFUL SHUTDOWN (Fixed for Mongoose 8+)
74-
const gracefulShutdown = async () => {
75-
console.log('🛑 SIGTERM/SIGINT received. Shutting down gracefully...');
49+
// --- 🛡️ DB CONNECTION & SERVER START ---
50+
// (Only connect if NOT in Test Mode)
51+
if (process.env.NODE_ENV !== 'test') {
7652

77-
server.close(async () => {
78-
console.log('✅ HTTP server closed.');
53+
const PORT = process.env.PORT || 1234;
7954

55+
const connectDB = async () => {
8056
try {
81-
// Updated: No callback, use await instead
82-
await mongoose.connection.close(false);
83-
console.log('✅ MongoDB connection closed.');
84-
process.exit(0);
57+
await mongoose.connect(process.env.MONGO_URL);
58+
console.log("✅ MongoDB Connected");
8559
} catch (err) {
86-
console.error('❌ Error closing MongoDB connection:', err);
87-
process.exit(1);
60+
console.error("❌ MongoDB Connection Error:", err);
61+
// Retry logic
62+
setTimeout(connectDB, 5000);
8863
}
64+
};
65+
66+
// Runtime Errors
67+
mongoose.connection.on('error', (err) => {
68+
console.error("🔥 MongoDB Runtime Error:", err);
8969
});
9070

91-
// Force close after 10 seconds
92-
setTimeout(() => {
93-
console.error('Force shutting down...');
94-
process.exit(1);
95-
}, 10000);
96-
};
71+
// Auto-Reconnect
72+
mongoose.connection.on('disconnected', () => {
73+
console.warn("⚠️ MongoDB Disconnected. Retrying...");
74+
connectDB();
75+
});
76+
77+
// Start DB & Server
78+
connectDB();
79+
const server = app.listen(PORT, () => {
80+
console.log(`Server running on port ${PORT}`);
81+
});
82+
83+
// 🛡️ GRACEFUL SHUTDOWN
84+
const gracefulShutdown = async () => {
85+
console.log('🛑 SIGTERM/SIGINT received. Shutting down gracefully...');
86+
87+
server.close(async () => {
88+
console.log('✅ HTTP server closed.');
89+
try {
90+
await mongoose.connection.close(false);
91+
console.log('✅ MongoDB connection closed.');
92+
process.exit(0);
93+
} catch (err) {
94+
console.error('❌ Error closing MongoDB connection:', err);
95+
process.exit(1);
96+
}
97+
});
98+
99+
// Force close after 10s
100+
setTimeout(() => {
101+
console.error('Force shutting down...');
102+
process.exit(1);
103+
}, 10000);
104+
};
105+
106+
process.on('SIGTERM', gracefulShutdown);
107+
process.on('SIGINT', gracefulShutdown);
108+
}
97109

98-
// Listen for termination signals (e.g., from PM2, Docker, or Ctrl+C)
99-
process.on('SIGTERM', gracefulShutdown);
100-
process.on('SIGINT', gracefulShutdown);
110+
// Export for Testing
111+
module.exports = app;

0 commit comments

Comments
 (0)