Skip to content

Add option to rate limit the publish endpoint #1420

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

ricardo-devis-agullo
Copy link
Collaborator

@ricardo-devis-agullo ricardo-devis-agullo commented Jul 29, 2025

This adds an option to rate-limit the publish endpoint. By default it will use a memory one with lru-cache, but it's extendable by passing an object that follows the interface described so you could plug-in Redis or whatever library you want. I'm leaning towards enabling this by default

Rate Limiting

The registry supports rate limiting for the publish endpoint to prevent abuse. By default, it allows 100 requests per 15 minutes per IP/user combination.

Basic Configuration

const registry = require('oc-registry');

registry({
  // ... other config
  publishRateLimit: {
    windowMs: 15 * 60 * 1000, // 15 minutes (default)
    max: 100 // Maximum requests per window (default)
  }
});

Advanced Configuration

registry({
  // ... other config
  publishRateLimit: {
    windowMs: 5 * 60 * 1000, // 5 minutes
    max: 50, // 50 requests per 5 minutes
    maxCacheSize: 2000, // Maximum number of rate limit entries in memory
    keyGenerator: req => `${req.ip}:${req.user || 'anonymous'}`, // Custom key generation
    skip: req => req.headers['x-admin'] === 'true', // Skip for admin users
    store: new RedisStore({
      // Custom storage backend
      client: redisClient,
      prefix: 'rate-limit:'
    })
  }
});

Custom Storage Backends

You can implement custom storage backends by creating a class that implements the RateLimitStore interface:

class RedisRateLimitStore {
  async increment(key, windowMs) {
    // Your Redis implementation
    return { totalHits: count, resetTime: new Date() };
  }

  init() {
    // Optional: initialization logic
  }
}

}

export default function createPublishRateLimiter(conf: Config) {
const rateLimitConfig = conf.publishRateLimit ?? {};
Copy link
Collaborator

Choose a reason for hiding this comment

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

rather than gathering things like windowMs, maxHits, maxCacheSize, etc. on global level wouldn't it be better to leave it purely to the rate limit store?

So you could provide in config a factory function that would provide those values to the store directly. For default store you would provide those values on line 22, but not configurable.

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.

2 participants