Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
d8537e4
SCRUM-116 added get history and delete history routes
Phoenix9994 Oct 22, 2024
a04c030
Merge branch 'main' of github.com:Study-Compass/Study-Compass into SC…
Phoenix9994 Oct 25, 2024
9096f60
SCRUM-125 Club, Members, Followers Schema Created
Phoenix9994 Oct 25, 2024
4e2414f
fixing merge issue
Phoenix9994 Nov 1, 2024
da8417d
Get/Create/Edit/Delete Clubs
Phoenix9994 Nov 4, 2024
3d563ba
SCRUM-125 Get/Create/Edit/Delete Clubs
Phoenix9994 Nov 4, 2024
57bfc3e
SCRUM-125 Get/Create/Edit/Delete Clubs fixed errors
Phoenix9994 Nov 6, 2024
c9d267c
SCRUM-125 Added Profanity Blockers
Phoenix9994 Nov 6, 2024
444cf92
git pull origin main conflict
Phoenix9994 Nov 15, 2024
2994c6f
SCRUM-125 Added Scrum Scalability
Phoenix9994 Nov 15, 2024
347b6ec
testing
Phoenix9994 Nov 19, 2024
f9d0f38
SCRUM-158 Updated rateLimit and Developing Validate
Phoenix9994 Nov 22, 2024
326344b
Need to Pull
Phoenix9994 Dec 10, 2024
71fab11
SCRUM-158 Added Input Validator Middleware
Phoenix9994 Dec 10, 2024
5f90a65
SCRUM-158 Added Input Validator Middleware
Phoenix9994 Dec 10, 2024
6f3daa2
SCRUM-158 Added Monitor and Logging Middleware
Phoenix9994 Dec 10, 2024
05ea438
SCRUM 158- API Modifications
Phoenix9994 Jan 21, 2025
5fb3bc5
Trying to fix file changes
Phoenix9994 Jan 21, 2025
708d2eb
Fixed App.js merge conflict
Phoenix9994 Jan 21, 2025
81c93c6
Added Routes to App.js
Phoenix9994 Jan 24, 2025
21960f3
SCRUM 158- Fixed API Generation
Phoenix9994 Jan 28, 2025
a25483b
SCRUM 158- Removed validated.js
Phoenix9994 Jan 31, 2025
84d2a5d
SCRUM 158- Fixed and Debuged router issues
Phoenix9994 Feb 4, 2025
39782fa
commit change
Phoenix9994 Feb 7, 2025
657255f
SCRUM 158- Added Tangible routing for middleware
Phoenix9994 Feb 10, 2025
8b70011
SCRUM 158- Removed Monitoring.js from middleware
Phoenix9994 Feb 10, 2025
836c44a
SCRUM 158- Added Api Delete Rout
Phoenix9994 Feb 10, 2025
8247484
SCRUM 158- Implemented Delete, Fixed Bugs, Added to ApiKeyMiddleware
Phoenix9994 Feb 10, 2025
f807707
SCRUM 158- Cleanup to code
Phoenix9994 Feb 10, 2025
ece2a1c
SCRUM 158- Updating Misc
Phoenix9994 Feb 12, 2025
1c19781
SCRUM 158- Update api.js
Phoenix9994 Feb 21, 2025
2917919
SCRUM 158- Update api.js
Phoenix9994 Feb 21, 2025
34ace2e
SCRUM 158- Added Dynamic rate limiting
Phoenix9994 Feb 21, 2025
5331541
SCRUM 158- Updated Routing
Phoenix9994 Mar 18, 2025
4748576
merge conflict resolution
Phoenix9994 Mar 18, 2025
c344c28
SCRUM 158- Fixed all errors and Updated Authorization
Phoenix9994 Mar 18, 2025
afdd850
SCRUM-158 Removed comments
Phoenix9994 Mar 18, 2025
b6b4c58
SCRUM-158 adding temporary api access
AZ0228 Mar 18, 2025
6d640eb
SCRUM-158 new testing route
AZ0228 Mar 19, 2025
f7b7e48
SCRUM-158 Fixed Rate Limiting
Phoenix9994 Apr 1, 2025
337425d
SCRUM-158 Fixed API KEY Rate LIMIT
Phoenix9994 Apr 7, 2025
aa14396
Merge
Phoenix9994 Apr 7, 2025
cf55844
SCRUM-158 refactoring api, real world considerations
AZ0228 Apr 7, 2025
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
Binary file modified .DS_Store
Binary file not shown.
31 changes: 26 additions & 5 deletions backend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,36 @@ const io = new Server(server, {
}
});

//cors configuration
if (process.env.NODE_ENV === 'production') {
app.use(enforce.HTTPS({ trustProtoHeader: true }));
const corsOptions = {
origin: [
'https://www.study-compass.com',
'https://studycompass.com',
`http://${process.env.EDUREKA_IP}:${process.env.EDUREKA_PORT}`
// `http://${process.env.EDUREKA_IP}:${process.env.EDUREKA_PORT}`
],
optionsSuccessStatus: 200 // for legacy browser support
};
app.use(cors(corsOptions));

//apply CORS policy to all routes EXCEPT /api routes
app.use((req, res, next) => {
if (req.path.startsWith('/api')) {
return next();
}
return cors(corsOptions)(req, res, next);
});
} else {
//in development, use a more permissive CORS policy for non-API routes
app.use((req, res, next) => {
if (req.path.startsWith('/api')) {
return next();
}
return cors({
origin: true, //allow all origins in development
credentials: true
})(req, res, next);
});
}

// Other middleware
Expand Down Expand Up @@ -68,6 +87,8 @@ app.use(async (req, res, next) => {
res.status(500).send('Database connection error');
}
});
// berkeley.study-compass.com


const upload = multer({
storage: multer.memoryStorage(),
Expand All @@ -87,22 +108,22 @@ const ratingRoutes = require('./routes/ratingRoutes.js');
const searchRoutes = require('./routes/searchRoutes.js');
const eventRoutes = require('./routes/eventRoutes.js');
const oieRoutes = require('./routes/oie-routes.js');
const apiRoutes = require('./routes/apiRoutes.js'); //Added Pk ERROR
const orgRoutes = require('./routes/orgRoutes.js');
const workflowRoutes = require('./routes/workflowRoutes.js');

// Mount routes
app.use(authRoutes);
app.use(dataRoutes);
app.use(friendRoutes);
app.use(userRoutes);
app.use(analyticsRoutes);
app.use(eventRoutes);

app.use(classroomChangeRoutes);
app.use(ratingRoutes);
app.use(searchRoutes);

app.use(eventRoutes);
app.use(oieRoutes);
app.use('/api', apiRoutes); // API routes with their own CORS configuration
app.use(orgRoutes);
app.use(workflowRoutes);

Expand Down
31 changes: 31 additions & 0 deletions backend/middlewares/apiCors.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
const cors = require('cors');

/**
* CORS middleware specifically for API routes
* This allows cross-origin requests to API endpoints while maintaining security through API keys
*/
const apiCors = cors({
origin: '*',
methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS', 'PATCH'],

allowedHeaders: [
'Content-Type',
'Authorization',
'X-Requested-With',
'Accept',
'Origin',
'x-api-key'
],

//set credentials to false since we're using '*' for origin
credentials: false,

//set how long the results of a preflight request can be cached
maxAge: 86400, // 24 hours

//enable preflight requests
preflightContinue: false,
optionsSuccessStatus: 204
});

module.exports = apiCors;
42 changes: 42 additions & 0 deletions backend/middlewares/apiKeyMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const mongoose = require('mongoose');
const getModels = require('../services/getModelService.js');

const apiKeyMiddleware = async (req, res, next) => {
try {
const apiKey = req.headers['x-api-key'];

if (!apiKey) {
return res.status(401).json({ error: 'API key is required' });
}

const { Api } = getModels(req, 'Api');
const apiKeyData = await Api.findOne({ api_key: apiKey });

if (!apiKeyData) {
return res.status(401).json({ error: 'Invalid API key' });
}

//check if API key is expired
if (apiKeyData.expiresAt && new Date() > apiKeyData.expiresAt) {
return res.status(401).json({ error: 'API key has expired' });
}

//check IP whitelist if configured
if (apiKeyData.allowedIPs && apiKeyData.allowedIPs.length > 0) {
const clientIP = req.ip;
if (!apiKeyData.allowedIPs.includes(clientIP)) {
return res.status(403).json({ error: 'IP not whitelisted' });
}
}

//attach API key data to request for use in other middleware
req.apiKeyData = apiKeyData;
next();
} catch (error) {
console.error('API Key Middleware Error:', error);
res.status(500).json({ error: 'Internal server error' });
}
};

module.exports = { apiKeyMiddleware };

69 changes: 69 additions & 0 deletions backend/middlewares/rateLimit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
//Rate Limiter

const rateLimit = require('express-rate-limit');

const coolDown = 15 * 60 * 1000; // 15 minutes

const limiter = (options = {}) => {
const {
maxRequests = 200,
windowMs = coolDown, // 15 minutes
message = 'Too many requests, please try again later.',
keyGenerator = (req) => {
//use API key if available, otherwise fall back to IP
return req.apiKeyData ? req.apiKeyData.api_key : req.ip;
},
skip = (req) => false,
handler = (req, res) => {
res.status(429).json({
error: message,
requestId: req.requestId,
retryAfter: Math.ceil(windowMs / 1000)
});
},
//debug option to help troubleshoot rate limiting
debug = process.env.NODE_ENV === 'development'
} = options;

return rateLimit({
windowMs,
max: maxRequests,
message,
standardHeaders: true,
legacyHeaders: false,
keyGenerator,
skip,
handler,
//custom headers
headers: true,
skipFailedRequests: false,
skipSuccessfulRequests: false,
statusCode: 429,
skip: (req) => {
//skip rate limiting for certain paths or conditions
//examples below
// if (req.path.startsWith('/health')) return true;
// if (req.path.startsWith('/metrics')) return true;
return false;
},
debug
});
};

module.exports = {
limiter,
//strict rate limiter for sensitive endpoints
strictLimiter: (maxRequests = 50) => limiter({
maxRequests,
windowMs: coolDown, // 15 minutes
message: 'Rate limit exceeded. Please try again in a minute.'
}),
//burst rate limiter for high-traffic endpoints
burstLimiter: (maxRequests = 1000) => limiter({
maxRequests,
windowMs: coolDown, // 15 minutes
message: 'Too many requests in a short time. Please try again in a minute.'
}),
//default rate limiter
defaultLimiter: limiter
};
72 changes: 72 additions & 0 deletions backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,13 @@
"date-fns": "^4.1.0",
"dotenv": "^16.3.2",
"express": "^4.18.2",
"express-rate-limit": "^7.5.0",
"express-sslify": "^1.2.0",
"google-auth-library": "^9.4.2",
"googleapis": "^131.0.0",
"jsonwebtoken": "^9.0.2",
"mongoose": "^8.0.3",
"morgan": "^1.10.0",
"multer": "^1.4.5-lts.1",
"node-cron": "^3.0.3",
"nodemon": "^3.1.7",
Expand Down
Loading