Checking Limits Without Incrementing?
Closed this issue · 1 comments
Hi, it's me again.
Is it possible to check if a client is under the limit, without incrementing the count? I can see the cache class has a read method, but it looks like it's only used by fail2ban. My usecases revolve around checking if someone is at or above the limit and rendering a template differently (e.g. deciding to rendering a form with or without a captcha shouldn't count towards the limit).
From what I gather, this isn't possible because the method that returns the current count /also/ increments it. Is my understanding correct?
Through a series of monkeypatches, I've achieved the behavior I'm looking for. Hopefully this can do a decent job of explaining my usecase. This allows me to use it in a controller like like
def show
if limiter.at_limit?(request)
@warning_message = "Attempts exceeded."
@challenge = new_captcha_form
end
end
def create
if limiter.matched_by?(request)
validate_captcha
end
rest_of_the_action
end
def limiter
limiter = Rack::Attack.track("requests from bucket", limit: 5, period: 3600) do |req|
bucket
end
end
monkeypatch:
Rack::Attack::Configuration.class_eval do
# nop'd because otherwise all Rack::Attack::Throttles are incremented
# even if the gated functionality is never exercised
def tracked?(request)
end
end
Rack::Attack::Cache.class_eval do
def get_count(unprefixed_key, period)
enforce_store_presence!
enforce_store_method_presence!(:read)
key, expires_in = key_and_expiry(unprefixed_key, period)
result = store.read(key)
result || 0
end
end
Rack::Attack::Track.class_eval do
def at_limit?(request)
filter.at_limit?(request)
end
end
Rack::Attack::Throttle.class_eval do
def at_limit?(request)
discriminator = discriminator_for(request)
return false unless discriminator
current_period = period_for(request)
current_limit = limit_for(request)
count = cache.get_count("#{name}:#{discriminator}", current_period)
count > current_limit
end
end