Skip to content
Merged
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
65 changes: 65 additions & 0 deletions adaptive-rate-limit.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
// Adaptive Rate Limiting for API Abuse Prevention
// Issue #995
// Dynamically adjusts quotas using real-time analytics and ML risk scoring

const analytics = require('./analytics-dashboard'); // Example analytics module
const anomalyDetector = require('./anomaly-detector'); // Example ML module

class AdaptiveRateLimiter {
constructor(options = {}) {
this.defaultLimit = options.defaultLimit || 1000; // requests per hour
this.userLimits = new Map(); // userId -> limit
this.usage = new Map(); // userId -> [timestamps]
this.riskScores = new Map(); // userId -> score
}

recordRequest(userId) {
const now = Date.now();
if (!this.usage.has(userId)) {
this.usage.set(userId, []);
}
this.usage.get(userId).push(now);
this.updateRiskScore(userId);
this.adjustLimit(userId);
}

isAllowed(userId) {
const limit = this.userLimits.get(userId) || this.defaultLimit;
const windowMs = 60 * 60 * 1000; // 1 hour
const now = Date.now();
const timestamps = (this.usage.get(userId) || []).filter(ts => now - ts < windowMs);
this.usage.set(userId, timestamps);
return timestamps.length < limit;
}

updateRiskScore(userId) {
// Use analytics and ML to score risk
const usageStats = analytics.getUserStats(userId);
const anomaly = anomalyDetector.detect(usageStats);
let score = 0;
if (anomaly.isAnomalous) score += 50;
score += usageStats.failedLogins * 2;
score += usageStats.requestsPerMinute;
this.riskScores.set(userId, score);
}

adjustLimit(userId) {
// Lower limit for high risk, raise for low risk
const score = this.riskScores.get(userId) || 0;
let limit = this.defaultLimit;
if (score > 80) limit = Math.max(100, this.defaultLimit * 0.1);
else if (score > 50) limit = Math.max(300, this.defaultLimit * 0.3);
else if (score < 10) limit = this.defaultLimit * 2;
this.userLimits.set(userId, Math.floor(limit));
}

getUserLimit(userId) {
return this.userLimits.get(userId) || this.defaultLimit;
}

getUserRiskScore(userId) {
return this.riskScores.get(userId) || 0;
}
}

module.exports = AdaptiveRateLimiter;
40 changes: 40 additions & 0 deletions adaptive/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Adaptive Rate Limiting System

This module implements adaptive rate limiting for API abuse prevention using real-time analytics and machine learning risk scoring. It dynamically adjusts user quotas based on behavior and risk profiles.

## Features
- Real-time analytics for API usage
- ML-based risk scoring
- Dynamic quota adjustment
- Logging and monitoring
- Easy integration with Express API routes

## File Structure
- `analytics.js`: Tracks requests, user actions, endpoint stats
- `ml-risk.js`: Scores user risk using ML/anomaly detection
- `quota.js`: Adjusts user quotas based on risk
- `logger.js`: Logs rate limiting events and statistics
- `rate-limiter.js`: Orchestrates all modules for adaptive rate limiting

## Usage Example
```js
const rateLimiter = require('./adaptive/rate-limiter');

function rateLimitMiddleware(req, res, next) {
const userId = req.body.userId || req.ip;
const endpoint = req.path;
rateLimiter.recordRequest(userId, endpoint, 'success');
if (!rateLimiter.isAllowed(userId)) {
return res.status(429).json({ success: false, error: 'Rate limit exceeded', limit: rateLimiter.getUserLimit(userId), riskScore: rateLimiter.getUserRiskScore(userId) });
}
next();
}
```

## Extensibility
- Add more sophisticated ML models in `ml-risk.js`
- Integrate with external monitoring tools via `logger.js`
- Customize quota logic in `quota.js`

## Compliance
All events are logged for audit and compliance purposes.
34 changes: 34 additions & 0 deletions adaptive/README_API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Adaptive Rate Limiting API Reference

## Endpoints

### POST /test
- Description: Test endpoint for rate limiting
- Request Body: `{ "userId": "string" }`
- Response: `{ success: true, message: "Request allowed!" }` or `{ success: false, error: "Rate limit exceeded", limit, riskScore }`

## Middleware
```js
const rateLimiter = require('./adaptive/rate-limiter');
function rateLimitMiddleware(req, res, next) {
const userId = req.body.userId || req.ip;
const endpoint = req.path;
rateLimiter.recordRequest(userId, endpoint, 'success');
if (!rateLimiter.isAllowed(userId)) {
return res.status(429).json({ success: false, error: 'Rate limit exceeded', limit: rateLimiter.getUserLimit(userId), riskScore: rateLimiter.getUserRiskScore(userId) });
}
next();
}
```

## Dashboard
- Run `dashboard.js` to view stats

## Alerts
- High risk users trigger alerts in `monitor.js` and `alerts.js`

## Admin
- Use `admin.js` for manual overrides

## Compliance
- All events logged in `rate-limit.log` for audit
36 changes: 36 additions & 0 deletions adaptive/admin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Admin utility for Adaptive Rate Limiting
// Allows manual override of quotas and risk scores

const quota = require('./quota');
const mlRisk = require('./ml-risk');

function setUserLimit(userId, limit) {
quota.userLimits.set(userId, limit);
console.log(`Set quota for ${userId} to ${limit}`);
}

function setUserRiskScore(userId, score) {
mlRisk.userScores.set(userId, score);
console.log(`Set risk score for ${userId} to ${score}`);
}

function printAllLimits() {
console.log('User Quotas:');
for (const [userId, limit] of quota.getAllLimits()) {
console.log(`${userId}: ${limit}`);
}
}

function printAllScores() {
console.log('User Risk Scores:');
for (const [userId, score] of mlRisk.getAllScores()) {
console.log(`${userId}: ${score}`);
}
}

module.exports = {
setUserLimit,
setUserRiskScore,
printAllLimits,
printAllScores
};
24 changes: 24 additions & 0 deletions adaptive/alerts.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Alerting utility for Adaptive Rate Limiting
// Sends notifications for high risk events

const logger = require('./logger');
const config = require('./config');

function checkAlerts() {
const logs = logger.getLogs();
logs.forEach(entry => {
if (entry.event === 'request' && entry.details.riskScore > config.alertRiskThreshold) {
sendAlert(entry.details);
}
});
}

function sendAlert(details) {
// Placeholder: send email, SMS, webhook, etc.
console.log('ALERT: High risk user detected!', details);
}

module.exports = {
checkAlerts,
sendAlert
};
62 changes: 62 additions & 0 deletions adaptive/analytics.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Real-Time Analytics for API Usage
// Tracks requests, user actions, endpoint stats

class Analytics {
constructor() {
this.userStats = new Map(); // userId -> stats
this.endpointStats = new Map(); // endpoint -> stats
}

recordRequest(userId, endpoint, status, timestamp = Date.now()) {
if (!this.userStats.has(userId)) {
this.userStats.set(userId, {
requests: 0,
failedLogins: 0,
requestsPerMinute: 0,
lastMinute: [],
endpoints: {}
});
}
const stats = this.userStats.get(userId);
stats.requests++;
stats.lastMinute.push(timestamp);
stats.lastMinute = stats.lastMinute.filter(ts => timestamp - ts < 60000);
stats.requestsPerMinute = stats.lastMinute.length;
if (!stats.endpoints[endpoint]) stats.endpoints[endpoint] = 0;
stats.endpoints[endpoint]++;
if (status === 'fail') stats.failedLogins++;
this.userStats.set(userId, stats);

// Endpoint stats
if (!this.endpointStats.has(endpoint)) {
this.endpointStats.set(endpoint, { requests: 0, users: new Set() });
}
const epStats = this.endpointStats.get(endpoint);
epStats.requests++;
epStats.users.add(userId);
this.endpointStats.set(endpoint, epStats);
}

getUserStats(userId) {
return this.userStats.get(userId) || {
requests: 0,
failedLogins: 0,
requestsPerMinute: 0,
endpoints: {}
};
}

getEndpointStats(endpoint) {
return this.endpointStats.get(endpoint) || { requests: 0, users: new Set() };
}

getAllUserStats() {
return Array.from(this.userStats.entries());
}

getAllEndpointStats() {
return Array.from(this.endpointStats.entries());
}
}

module.exports = new Analytics();
26 changes: 26 additions & 0 deletions adaptive/api.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Adaptive Rate Limiting API Integration Example
const express = require('express');
const app = express();
const rateLimiter = require('./rate-limiter');

app.use(express.json());

function rateLimitMiddleware(req, res, next) {
const userId = req.body.userId || req.ip;
const endpoint = req.path;
rateLimiter.recordRequest(userId, endpoint, 'success');
if (!rateLimiter.isAllowed(userId)) {
return res.status(429).json({ success: false, error: 'Rate limit exceeded', limit: rateLimiter.getUserLimit(userId), riskScore: rateLimiter.getUserRiskScore(userId) });
}
next();
}

app.use(rateLimitMiddleware);

app.post('/test', (req, res) => {
res.json({ success: true, message: 'Request allowed!' });
});

app.listen(4000, () => {
console.log('Adaptive Rate Limiting API running on port 4000');
});
7 changes: 7 additions & 0 deletions adaptive/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Configuration for Adaptive Rate Limiting
module.exports = {
defaultLimit: 1000,
alertRiskThreshold: 100,
logFile: 'rate-limit.log',
dashboardPort: 4001
};
29 changes: 29 additions & 0 deletions adaptive/dashboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Adaptive Rate Limiting Dashboard (CLI)
// Displays user stats, risk scores, quotas, and logs

const analytics = require('./analytics');
const mlRisk = require('./ml-risk');
const quota = require('./quota');
const logger = require('./logger');

function printDashboard() {
console.log('--- Adaptive Rate Limiting Dashboard ---');
console.log('User Stats:');
for (const [userId, stats] of analytics.getAllUserStats()) {
console.log(`User: ${userId}`);
console.log(' Requests:', stats.requests);
console.log(' Requests/min:', stats.requestsPerMinute);
console.log(' Endpoints:', Object.keys(stats.endpoints));
console.log(' Failed Logins:', stats.failedLogins);
console.log(' Risk Score:', mlRisk.getUserScore(userId));
console.log(' Quota:', quota.getUserLimit(userId));
console.log('---');
}
console.log('Recent Logs:');
const logs = logger.getLogs().slice(-10);
for (const log of logs) {
console.log(log);
}
}

printDashboard();
40 changes: 40 additions & 0 deletions adaptive/docs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Adaptive Rate Limiting Documentation

## Overview
Adaptive rate limiting prevents API abuse by dynamically adjusting quotas based on user behavior and risk profiles. It uses real-time analytics and machine learning to detect anomalies and enforce limits.

## Modules
- **analytics.js**: Tracks API usage, user actions, endpoint stats
- **ml-risk.js**: Scores user risk using ML/anomaly detection
- **quota.js**: Adjusts quotas based on risk
- **logger.js**: Logs events for monitoring and compliance
- **rate-limiter.js**: Orchestrates all modules

## Integration
Add the middleware to your Express routes:
```js
const rateLimiter = require('./adaptive/rate-limiter');
function rateLimitMiddleware(req, res, next) {
const userId = req.body.userId || req.ip;
const endpoint = req.path;
rateLimiter.recordRequest(userId, endpoint, 'success');
if (!rateLimiter.isAllowed(userId)) {
return res.status(429).json({ success: false, error: 'Rate limit exceeded', limit: rateLimiter.getUserLimit(userId), riskScore: rateLimiter.getUserRiskScore(userId) });
}
next();
}
```

## Dashboard
Run `dashboard.js` to view user stats, risk scores, quotas, and logs.

## Testing
Run `test.js` for a basic test suite.

## Extending
- Enhance ML logic in `ml-risk.js`
- Integrate external monitoring in `logger.js`
- Customize quota logic in `quota.js`

## Compliance
All rate limiting events are logged for audit and compliance.
19 changes: 19 additions & 0 deletions adaptive/examples.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Example usage scenarios for Adaptive Rate Limiting
const rateLimiter = require('./rate-limiter');

function simulateScenario(userId, endpoint, actions) {
actions.forEach(action => {
rateLimiter.recordRequest(userId, endpoint, action.status);
const allowed = rateLimiter.isAllowed(userId);
console.log(`User: ${userId}, Endpoint: ${endpoint}, Status: ${action.status}, Allowed: ${allowed}, Limit: ${rateLimiter.getUserLimit(userId)}, Risk: ${rateLimiter.getUserRiskScore(userId)}`);
});
}

// Scenario 1: Normal user
simulateScenario('normalUser', '/gdpr', Array(20).fill({ status: 'success' }));

// Scenario 2: Abusive user
simulateScenario('abuser', '/pci-dss', Array(1200).fill({ status: 'success' }));

// Scenario 3: User with failed logins
simulateScenario('suspiciousUser', '/sox', Array(10).fill({ status: 'fail' }));
Loading