Skip to content

Commit 6405834

Browse files
committed
Fix reset! when using namespaced cache store
1 parent 0b48f9f commit 6405834

File tree

5 files changed

+97
-24
lines changed

5 files changed

+97
-24
lines changed

lib/rack/attack/cache.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def delete(unprefixed_key)
5555

5656
def reset!
5757
if store.respond_to?(:delete_matched)
58-
store.delete_matched("#{prefix}*")
58+
store.delete_matched(/#{prefix}*/)
5959
else
6060
raise(
6161
Rack::Attack::IncompatibleStoreError,

lib/rack/attack/store_proxy/redis_cache_store_proxy.rb

+4
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ def read(name, options = {})
3333
def write(name, value, options = {})
3434
super(name, value, options.merge!(raw: true))
3535
end
36+
37+
def delete_matched(matcher, options = nil)
38+
super(matcher.source, options)
39+
end
3640
end
3741
end
3842
end

lib/rack/attack/store_proxy/redis_proxy.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -45,11 +45,12 @@ def delete(key, _options = {})
4545

4646
def delete_matched(matcher, _options = nil)
4747
cursor = "0"
48+
source = matcher.source
4849

4950
rescuing do
5051
# Fetch keys in batches using SCAN to avoid blocking the Redis server.
5152
loop do
52-
cursor, keys = scan(cursor, match: matcher, count: 1000)
53+
cursor, keys = scan(cursor, match: source, count: 1000)
5354
del(*keys) unless keys.empty?
5455
break if cursor == "0"
5556
end

spec/rack_attack_reset_spec.rb

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# frozen_string_literal: true
2+
3+
require_relative "spec_helper"
4+
5+
describe "Rack::Attack.reset!" do
6+
it "raises an error when is not supported by cache store" do
7+
Rack::Attack.cache.store = Class.new
8+
assert_raises(Rack::Attack::IncompatibleStoreError) do
9+
Rack::Attack.reset!
10+
end
11+
end
12+
13+
if defined?(Redis)
14+
it "should delete rack attack keys" do
15+
redis = Redis.new
16+
redis.set("key", "value")
17+
redis.set("#{Rack::Attack.cache.prefix}::key", "value")
18+
Rack::Attack.cache.store = redis
19+
Rack::Attack.reset!
20+
21+
_(redis.get("key")).must_equal "value"
22+
_(redis.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil
23+
end
24+
end
25+
26+
if defined?(Redis::Store)
27+
it "should delete rack attack keys" do
28+
redis_store = Redis::Store.new
29+
redis_store.set("key", "value")
30+
redis_store.set("#{Rack::Attack.cache.prefix}::key", "value")
31+
Rack::Attack.cache.store = redis_store
32+
Rack::Attack.reset!
33+
34+
_(redis_store.get("key")).must_equal "value"
35+
_(redis_store.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil
36+
end
37+
end
38+
39+
if defined?(Redis) && defined?(ActiveSupport::Cache::RedisCacheStore)
40+
it "should delete rack attack keys" do
41+
redis_cache_store = ActiveSupport::Cache::RedisCacheStore.new
42+
redis_cache_store.write("key", "value")
43+
redis_cache_store.write("#{Rack::Attack.cache.prefix}::key", "value")
44+
Rack::Attack.cache.store = redis_cache_store
45+
Rack::Attack.reset!
46+
47+
_(redis_cache_store.read("key")).must_equal "value"
48+
_(redis_cache_store.read("#{Rack::Attack.cache.prefix}::key")).must_be_nil
49+
end
50+
51+
describe "with a namespaced cache" do
52+
it "should delete rack attack keys" do
53+
redis_cache_store = ActiveSupport::Cache::RedisCacheStore.new(namespace: "ns")
54+
redis_cache_store.write("key", "value")
55+
redis_cache_store.write("#{Rack::Attack.cache.prefix}::key", "value")
56+
Rack::Attack.cache.store = redis_cache_store
57+
Rack::Attack.reset!
58+
59+
_(redis_cache_store.read("key")).must_equal "value"
60+
_(redis_cache_store.read("#{Rack::Attack.cache.prefix}::key")).must_be_nil
61+
end
62+
end
63+
end
64+
65+
if defined?(ActiveSupport::Cache::MemoryStore)
66+
it "should delete rack attack keys" do
67+
memory_store = ActiveSupport::Cache::MemoryStore.new
68+
memory_store.write("key", "value")
69+
memory_store.write("#{Rack::Attack.cache.prefix}::key", "value")
70+
Rack::Attack.cache.store = memory_store
71+
Rack::Attack.reset!
72+
73+
_(memory_store.read("key")).must_equal "value"
74+
_(memory_store.read("#{Rack::Attack.cache.prefix}::key")).must_be_nil
75+
end
76+
77+
describe "with a namespaced cache" do
78+
it "should delete rack attack keys" do
79+
memory_store = ActiveSupport::Cache::MemoryStore.new(namespace: "ns")
80+
memory_store.write("key", "value")
81+
memory_store.write("#{Rack::Attack.cache.prefix}::key", "value")
82+
Rack::Attack.cache.store = memory_store
83+
Rack::Attack.reset!
84+
85+
_(memory_store.read("key")).must_equal "value"
86+
_(memory_store.read("#{Rack::Attack.cache.prefix}::key")).must_be_nil
87+
end
88+
end
89+
end
90+
end

spec/rack_attack_spec.rb

-22
Original file line numberDiff line numberDiff line change
@@ -103,26 +103,4 @@
103103
end
104104
end
105105
end
106-
107-
describe 'reset!' do
108-
it 'raises an error when is not supported by cache store' do
109-
Rack::Attack.cache.store = Class.new
110-
assert_raises(Rack::Attack::IncompatibleStoreError) do
111-
Rack::Attack.reset!
112-
end
113-
end
114-
115-
if defined?(Redis)
116-
it 'should delete rack attack keys' do
117-
redis = Redis.new
118-
redis.set('key', 'value')
119-
redis.set("#{Rack::Attack.cache.prefix}::key", 'value')
120-
Rack::Attack.cache.store = redis
121-
Rack::Attack.reset!
122-
123-
_(redis.get('key')).must_equal 'value'
124-
_(redis.get("#{Rack::Attack.cache.prefix}::key")).must_be_nil
125-
end
126-
end
127-
end
128106
end

0 commit comments

Comments
 (0)