Files
sure/config/initializers/rack_attack.rb
Juliano Julio Costa 3f92fe0f6f Relax API rate limits for self-hosted deployments (#2465)
- Introduced NoopApiRateLimiter to effectively disable API rate limiting for self-hosted mode.
- Updated ApiRateLimiter to delegate to NoopApiRateLimiter when running self-hosted.
- Increased Rack::Attack throttle limits significantly for self-hosted deployments.
- Added tests for NoopApiRateLimiter to ensure correct behavior.
- This allows self-hosted users to make more API requests without restriction, while keeping stricter limits for SaaS deployments.
2025-07-23 10:10:11 -04:00

70 lines
2.1 KiB
Ruby

# frozen_string_literal: true
class Rack::Attack
# Enable Rack::Attack
enabled = Rails.env.production? || Rails.env.staging?
# Throttle requests to the OAuth token endpoint
throttle("oauth/token", limit: 10, period: 1.minute) do |request|
request.ip if request.path == "/oauth/token"
end
# Determine limits based on self-hosted mode
self_hosted = Rails.application.config.app_mode.self_hosted?
# Throttle API requests per access token
throttle("api/requests", limit: self_hosted ? 10_000 : 100, period: 1.hour) do |request|
if request.path.start_with?("/api/")
# Extract access token from Authorization header
auth_header = request.get_header("HTTP_AUTHORIZATION")
if auth_header&.start_with?("Bearer ")
token = auth_header.split(" ").last
"api_token:#{Digest::SHA256.hexdigest(token)}"
else
# Fall back to IP-based limiting for unauthenticated requests
"api_ip:#{request.ip}"
end
end
end
# More permissive throttling for API requests by IP (for development/testing)
throttle("api/ip", limit: self_hosted ? 20_000 : 200, period: 1.hour) do |request|
request.ip if request.path.start_with?("/api/")
end
# Block requests that appear to be malicious
blocklist("block malicious requests") do |request|
# Block requests with suspicious user agents
suspicious_user_agents = [
/sqlmap/i,
/nmap/i,
/nikto/i,
/masscan/i
]
user_agent = request.user_agent
suspicious_user_agents.any? { |pattern| user_agent =~ pattern } if user_agent
end
# Configure response for throttled requests
self.throttled_responder = lambda do |request|
[
429, # status
{
"Content-Type" => "application/json",
"Retry-After" => "60"
},
[ { error: "Rate limit exceeded. Try again later." }.to_json ]
]
end
# Configure response for blocked requests
self.blocklisted_responder = lambda do |request|
[
403, # status
{ "Content-Type" => "application/json" },
[ { error: "Request blocked." }.to_json ]
]
end
end