mirror of
https://github.com/samsonjs/rack-attack.git
synced 2026-03-25 09:25:49 +00:00
Merge pull request #436 from fatkodima/reset-method
Allow to reset state
This commit is contained in:
commit
a4ea2146dd
4 changed files with 51 additions and 0 deletions
|
|
@ -14,6 +14,7 @@ module Rack
|
|||
class Error < StandardError; end
|
||||
class MisconfiguredStoreError < Error; end
|
||||
class MissingStoreError < Error; end
|
||||
class IncompatibleStoreError < Error; end
|
||||
|
||||
autoload :Check, 'rack/attack/check'
|
||||
autoload :Throttle, 'rack/attack/throttle'
|
||||
|
|
@ -53,6 +54,10 @@ module Rack
|
|||
@configuration.clear_configuration
|
||||
end
|
||||
|
||||
def reset!
|
||||
cache.reset!
|
||||
end
|
||||
|
||||
extend Forwardable
|
||||
def_delegators(
|
||||
:@configuration,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,17 @@ module Rack
|
|||
store.delete("#{prefix}:#{unprefixed_key}")
|
||||
end
|
||||
|
||||
def reset!
|
||||
if store.respond_to?(:delete_matched)
|
||||
store.delete_matched("#{prefix}*")
|
||||
else
|
||||
raise(
|
||||
Rack::Attack::IncompatibleStoreError,
|
||||
"Configured store #{store.class.name} doesn't respond to #delete_matched method"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def key_and_expiry(unprefixed_key, period)
|
||||
|
|
|
|||
|
|
@ -43,6 +43,19 @@ module Rack
|
|||
rescuing { del(key) }
|
||||
end
|
||||
|
||||
def delete_matched(matcher, _options = nil)
|
||||
cursor = "0"
|
||||
|
||||
rescuing do
|
||||
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
|
||||
loop do
|
||||
cursor, keys = scan(cursor, match: matcher, count: 1000)
|
||||
del(*keys) unless keys.empty?
|
||||
break if cursor == "0"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rescuing
|
||||
|
|
|
|||
|
|
@ -99,4 +99,26 @@ describe 'Rack::Attack' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'reset!' do
|
||||
it 'raises an error when is not supported by cache store' do
|
||||
Rack::Attack.cache.store = Class.new
|
||||
assert_raises(Rack::Attack::IncompatibleStoreError) do
|
||||
Rack::Attack.reset!
|
||||
end
|
||||
end
|
||||
|
||||
if defined?(Redis)
|
||||
it 'should delete rack attack keys' do
|
||||
redis = Redis.new
|
||||
redis.set('key', 'value')
|
||||
redis.set("#{Rack::Attack.cache.prefix}::key", 'value')
|
||||
Rack::Attack.cache.store = redis
|
||||
Rack::Attack.reset!
|
||||
|
||||
_(redis.get('key')).must_equal 'value'
|
||||
_(redis.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue