Skip to content

Conversation

@borfast
Copy link
Contributor

@borfast borfast commented Nov 13, 2025

This pull request introduces a rate limiting system for the application, using Redis for tracking requests.

  • Uses Redis for tracking requests
  • Hashes IP addresses for GDPR compliance
  • Supports per-route and per-method limits
  • Adds rate limit headers to responses

Because for the frontend directory the dependencies have to be installed --ignore-workspace, the existing Redis client package from the crowd.dev repository was not reused. Instead, a light version was created.

The environment variables NUXT_REDIS_URL and NUXT_RATE_LIMITER_REDIS_DB must be present and care must be taken so that the rate limiter does not use a database that is being used by something else.

Jira ticket here.

@borfast borfast requested review from epipav and gaspergrom November 13, 2025 23:41
@borfast borfast self-assigned this Nov 13, 2025
Copilot AI review requested due to automatic review settings November 13, 2025 23:41
Copilot finished reviewing on behalf of borfast November 13, 2025 23:44
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces a Redis-based rate limiting system for the application to protect against excessive request volumes. The implementation uses IP address hashing for GDPR compliance and supports configurable per-route and per-method rate limits.

Key Changes:

  • Added rate limiter middleware that intercepts requests and enforces configurable rate limits
  • Implemented IP extraction and hashing logic for GDPR compliance
  • Configured Redis client integration from the crowd.dev repository
  • Added rate limit headers to API responses

Reviewed Changes

Copilot reviewed 6 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
frontend/setup/rate-limiter.ts Defines rate limiter configuration with default and route-specific limits
frontend/server/utils/rate-limiter.ts Core rate limiting logic including IP extraction, route matching, and Redis operations
frontend/server/types/rate-limiter.ts TypeScript type definitions for rate limiter configuration and results
frontend/server/middleware/rate-limiter.ts Middleware that applies rate limiting to incoming requests
frontend/package.json Added Redis client dependencies
frontend/nuxt.config.ts Integrated rate limiter config and fixed comment typo

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@borfast borfast force-pushed the feat/IN-803-add-rate-limiter branch 7 times, most recently from 642333a to 11c9c65 Compare November 14, 2025 00:19
@borfast borfast marked this pull request as draft November 14, 2025 00:25
@borfast borfast force-pushed the feat/IN-803-add-rate-limiter branch 4 times, most recently from 26b57f4 to 852529c Compare November 14, 2025 19:06
@borfast borfast marked this pull request as ready for review November 14, 2025 19:09
@borfast borfast requested review from epipav and gaspergrom November 14, 2025 19:09
@borfast borfast force-pushed the feat/IN-803-add-rate-limiter branch 2 times, most recently from f99d631 to e8fd9f9 Compare November 17, 2025 15:30
Signed-off-by: Raúl Santos <[email protected]>
@borfast borfast force-pushed the feat/IN-803-add-rate-limiter branch from e8fd9f9 to 0f32fd2 Compare November 17, 2025 15:37
Copy link
Collaborator

@gaspergrom gaspergrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no existing module to handle this?

@borfast
Copy link
Contributor Author

borfast commented Nov 18, 2025

Both @joanagmaia and I looked for something we could use but everything we found was too limited (could not specify limits per route or request method) and would not allow us to hash the IP addresses (which we need for compliance with privacy laws).

@borfast borfast requested a review from gaspergrom November 24, 2025 10:48
Copy link
Collaborator

@gaspergrom gaspergrom left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nuxt rate limiter allows limits per route, but not ip hashing so all good on that part

maxRequests: 5,
windowSeconds: 60, // 5 login attempts per minute
},
{
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you add /api/community/[slug].post.ts also here to disable rate limiting. Its a webhook and it receives quite a lot of data from external app so we dont want to have it rate limited

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also badges endpoints shouldnt be rate limited as its necessary to display badges which users include in readme

Copy link
Collaborator

@epipav epipav left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall, added a comment about client memoization issue

Comment on lines +39 to +75
export async function getRedisClient(
redisUrl: string,
database: number,
enableReadyCheck = true,
): Promise<RedisClientType> {
if (redisClient) {
return redisClient;
}

// Set the database number in the URL, replacing an existing one if present.
const url = setRedisDatabase(redisUrl, database);

redisClient = createClient({
url,
socket: {
reconnectStrategy: (retries) => {
// Timeout at 3000ms
return Math.min(retries * 50, 3000);
},
},
});

redisClient.on('error', (err) => {
console.error('Redis Client Error', err);
});

await redisClient.connect();

// Wait for a ready state if requested
if (enableReadyCheck && !redisClient.isReady) {
await new Promise<void>((resolve) => {
redisClient!.on('ready', () => resolve());
});
}

return redisClient;
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like there's a small issue here
The client memoization doesn't account for changes in the database parameter, and subsequent calls will return the same client regardless of the database number

If we initialize the client with database=1, and then on the subsequent call we try getting the client for database=2, the client for database=1 will be returned instead because of the memoization

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants