rack-attack 4.3.1 → 5.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +230 -113
- data/Rakefile +11 -3
- data/bin/setup +8 -0
- data/lib/rack/attack.rb +121 -48
- data/lib/rack/attack/allow2ban.rb +2 -1
- data/lib/rack/attack/{whitelist.rb → blocklist.rb} +2 -3
- data/lib/rack/attack/cache.rb +24 -5
- data/lib/rack/attack/check.rb +6 -8
- data/lib/rack/attack/fail2ban.rb +3 -2
- data/lib/rack/attack/path_normalizer.rb +6 -11
- data/lib/rack/attack/request.rb +1 -1
- data/lib/rack/attack/{blacklist.rb → safelist.rb} +2 -4
- data/lib/rack/attack/store_proxy.rb +13 -12
- data/lib/rack/attack/store_proxy/dalli_proxy.rb +2 -3
- data/lib/rack/attack/store_proxy/mem_cache_proxy.rb +50 -0
- data/lib/rack/attack/store_proxy/mem_cache_store_proxy.rb +19 -0
- data/lib/rack/attack/store_proxy/redis_cache_store_proxy.rb +35 -0
- data/lib/rack/attack/store_proxy/redis_proxy.rb +54 -0
- data/lib/rack/attack/store_proxy/redis_store_proxy.rb +5 -24
- data/lib/rack/attack/throttle.rb +16 -12
- data/lib/rack/attack/track.rb +3 -3
- data/lib/rack/attack/version.rb +1 -1
- data/spec/acceptance/allow2ban_spec.rb +71 -0
- data/spec/acceptance/blocking_ip_spec.rb +38 -0
- data/spec/acceptance/blocking_spec.rb +41 -0
- data/spec/acceptance/blocking_subnet_spec.rb +44 -0
- data/spec/acceptance/cache_store_config_for_allow2ban_spec.rb +126 -0
- data/spec/acceptance/cache_store_config_for_fail2ban_spec.rb +121 -0
- data/spec/acceptance/cache_store_config_for_throttle_spec.rb +48 -0
- data/spec/acceptance/cache_store_config_with_rails_spec.rb +31 -0
- data/spec/acceptance/customizing_blocked_response_spec.rb +41 -0
- data/spec/acceptance/customizing_throttled_response_spec.rb +59 -0
- data/spec/acceptance/extending_request_object_spec.rb +34 -0
- data/spec/acceptance/fail2ban_spec.rb +76 -0
- data/spec/acceptance/safelisting_ip_spec.rb +48 -0
- data/spec/acceptance/safelisting_spec.rb +53 -0
- data/spec/acceptance/safelisting_subnet_spec.rb +48 -0
- data/spec/acceptance/stores/active_support_dalli_store_spec.rb +19 -0
- data/spec/acceptance/stores/active_support_mem_cache_store_pooled_spec.rb +22 -0
- data/spec/acceptance/stores/active_support_mem_cache_store_spec.rb +18 -0
- data/spec/acceptance/stores/active_support_memory_store_spec.rb +16 -0
- data/spec/acceptance/stores/active_support_redis_cache_store_pooled_spec.rb +18 -0
- data/spec/acceptance/stores/active_support_redis_cache_store_spec.rb +18 -0
- data/spec/acceptance/stores/active_support_redis_store_spec.rb +18 -0
- data/spec/acceptance/stores/connection_pool_dalli_client_spec.rb +22 -0
- data/spec/acceptance/stores/dalli_client_spec.rb +19 -0
- data/spec/acceptance/stores/redis_spec.rb +20 -0
- data/spec/acceptance/stores/redis_store_spec.rb +18 -0
- data/spec/acceptance/throttling_spec.rb +159 -0
- data/spec/acceptance/track_spec.rb +27 -0
- data/spec/acceptance/track_throttle_spec.rb +53 -0
- data/spec/allow2ban_spec.rb +10 -9
- data/spec/fail2ban_spec.rb +12 -10
- data/spec/integration/offline_spec.rb +21 -23
- data/spec/rack_attack_dalli_proxy_spec.rb +0 -2
- data/spec/rack_attack_request_spec.rb +2 -2
- data/spec/rack_attack_spec.rb +53 -18
- data/spec/rack_attack_throttle_spec.rb +45 -13
- data/spec/rack_attack_track_spec.rb +11 -8
- data/spec/spec_helper.rb +35 -14
- data/spec/support/cache_store_helper.rb +82 -0
- metadata +161 -61
- data/spec/integration/rack_attack_cache_spec.rb +0 -119
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Customizing block responses" do
|
|
4
|
+
before do
|
|
5
|
+
Rack::Attack.blocklist("block 1.2.3.4") do |request|
|
|
6
|
+
request.ip == "1.2.3.4"
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "can be customized" do
|
|
11
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
12
|
+
|
|
13
|
+
assert_equal 403, last_response.status
|
|
14
|
+
|
|
15
|
+
Rack::Attack.blocklisted_response = lambda do |_env|
|
|
16
|
+
[503, {}, ["Blocked"]]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
20
|
+
|
|
21
|
+
assert_equal 503, last_response.status
|
|
22
|
+
assert_equal "Blocked", last_response.body
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "exposes match data" do
|
|
26
|
+
matched = nil
|
|
27
|
+
match_type = nil
|
|
28
|
+
|
|
29
|
+
Rack::Attack.blocklisted_response = lambda do |env|
|
|
30
|
+
matched = env['rack.attack.matched']
|
|
31
|
+
match_type = env['rack.attack.match_type']
|
|
32
|
+
|
|
33
|
+
[503, {}, ["Blocked"]]
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
37
|
+
|
|
38
|
+
assert_equal "block 1.2.3.4", matched
|
|
39
|
+
assert_equal :blocklist, match_type
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Customizing throttled response" do
|
|
4
|
+
before do
|
|
5
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
|
6
|
+
|
|
7
|
+
Rack::Attack.throttle("by ip", limit: 1, period: 60) do |request|
|
|
8
|
+
request.ip
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "can be customized" do
|
|
13
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
14
|
+
|
|
15
|
+
assert_equal 200, last_response.status
|
|
16
|
+
|
|
17
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
18
|
+
|
|
19
|
+
assert_equal 429, last_response.status
|
|
20
|
+
|
|
21
|
+
Rack::Attack.throttled_response = lambda do |_env|
|
|
22
|
+
[503, {}, ["Throttled"]]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
26
|
+
|
|
27
|
+
assert_equal 503, last_response.status
|
|
28
|
+
assert_equal "Throttled", last_response.body
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "exposes match data" do
|
|
32
|
+
matched = nil
|
|
33
|
+
match_type = nil
|
|
34
|
+
match_data = nil
|
|
35
|
+
match_discriminator = nil
|
|
36
|
+
|
|
37
|
+
Rack::Attack.throttled_response = lambda do |env|
|
|
38
|
+
matched = env['rack.attack.matched']
|
|
39
|
+
match_type = env['rack.attack.match_type']
|
|
40
|
+
match_data = env['rack.attack.match_data']
|
|
41
|
+
match_discriminator = env['rack.attack.match_discriminator']
|
|
42
|
+
|
|
43
|
+
[429, {}, ["Throttled"]]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
47
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
48
|
+
|
|
49
|
+
assert_equal "by ip", matched
|
|
50
|
+
assert_equal :throttle, match_type
|
|
51
|
+
assert_equal 60, match_data[:period]
|
|
52
|
+
assert_equal 1, match_data[:limit]
|
|
53
|
+
assert_equal 2, match_data[:count]
|
|
54
|
+
assert_equal "1.2.3.4", match_discriminator
|
|
55
|
+
|
|
56
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
57
|
+
assert_equal 3, match_data[:count]
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Extending the request object" do
|
|
4
|
+
before do
|
|
5
|
+
class Rack::Attack::Request
|
|
6
|
+
def authorized?
|
|
7
|
+
env["APIKey"] == "private-secret"
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
Rack::Attack.blocklist("unauthorized requests") do |request|
|
|
12
|
+
!request.authorized?
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# We don't want the extension to leak to other test cases
|
|
17
|
+
after do
|
|
18
|
+
class Rack::Attack::Request
|
|
19
|
+
remove_method :authorized?
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "forbids request if blocklist condition is true" do
|
|
24
|
+
get "/"
|
|
25
|
+
|
|
26
|
+
assert_equal 403, last_response.status
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
it "succeeds if blocklist condition is false" do
|
|
30
|
+
get "/", {}, "APIKey" => "private-secret"
|
|
31
|
+
|
|
32
|
+
assert_equal 200, last_response.status
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
require "timecop"
|
|
3
|
+
|
|
4
|
+
describe "fail2ban" do
|
|
5
|
+
before do
|
|
6
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
|
7
|
+
|
|
8
|
+
Rack::Attack.blocklist("fail2ban pentesters") do |request|
|
|
9
|
+
Rack::Attack::Fail2Ban.filter(request.ip, maxretry: 2, findtime: 30, bantime: 60) do
|
|
10
|
+
request.path.include?("private-place")
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it "returns OK for many requests to non filtered path" do
|
|
16
|
+
get "/"
|
|
17
|
+
assert_equal 200, last_response.status
|
|
18
|
+
|
|
19
|
+
get "/"
|
|
20
|
+
assert_equal 200, last_response.status
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "forbids access to private path" do
|
|
24
|
+
get "/private-place"
|
|
25
|
+
assert_equal 403, last_response.status
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "returns OK for non filtered path if yet not reached maxretry limit" do
|
|
29
|
+
get "/private-place"
|
|
30
|
+
assert_equal 403, last_response.status
|
|
31
|
+
|
|
32
|
+
get "/"
|
|
33
|
+
assert_equal 200, last_response.status
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "forbids all access after reaching maxretry limit" do
|
|
37
|
+
get "/private-place"
|
|
38
|
+
assert_equal 403, last_response.status
|
|
39
|
+
|
|
40
|
+
get "/private-place"
|
|
41
|
+
assert_equal 403, last_response.status
|
|
42
|
+
|
|
43
|
+
get "/"
|
|
44
|
+
assert_equal 403, last_response.status
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
it "restores access after bantime elapsed" do
|
|
48
|
+
get "/private-place"
|
|
49
|
+
assert_equal 403, last_response.status
|
|
50
|
+
|
|
51
|
+
get "/private-place"
|
|
52
|
+
assert_equal 403, last_response.status
|
|
53
|
+
|
|
54
|
+
get "/"
|
|
55
|
+
assert_equal 403, last_response.status
|
|
56
|
+
|
|
57
|
+
Timecop.travel(60) do
|
|
58
|
+
get "/"
|
|
59
|
+
|
|
60
|
+
assert_equal 200, last_response.status
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "does not forbid all access if maxrety condition is met but not within the findtime timespan" do
|
|
65
|
+
get "/private-place"
|
|
66
|
+
assert_equal 403, last_response.status
|
|
67
|
+
|
|
68
|
+
Timecop.travel(31) do
|
|
69
|
+
get "/private-place"
|
|
70
|
+
assert_equal 403, last_response.status
|
|
71
|
+
|
|
72
|
+
get "/"
|
|
73
|
+
assert_equal 200, last_response.status
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Safelist an IP" do
|
|
4
|
+
before do
|
|
5
|
+
Rack::Attack.blocklist("admin") do |request|
|
|
6
|
+
request.path == "/admin"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Rack::Attack.safelist_ip("5.6.7.8")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "forbids request if blocklist condition is true and safelist is false" do
|
|
13
|
+
get "/admin", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
14
|
+
|
|
15
|
+
assert_equal 403, last_response.status
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "succeeds if blocklist condition is false and safelist is false" do
|
|
19
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
20
|
+
|
|
21
|
+
assert_equal 200, last_response.status
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "succeeds request if blocklist condition is false and safelist is true" do
|
|
25
|
+
get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
|
|
26
|
+
|
|
27
|
+
assert_equal 200, last_response.status
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "succeeds request if both blocklist and safelist conditions are true" do
|
|
31
|
+
get "/admin", {}, "REMOTE_ADDR" => "5.6.7.8"
|
|
32
|
+
|
|
33
|
+
assert_equal 200, last_response.status
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "notifies when the request is safe" do
|
|
37
|
+
notification_type = nil
|
|
38
|
+
|
|
39
|
+
ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
|
|
40
|
+
notification_type = request.env["rack.attack.match_type"]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
get "/admin", {}, "REMOTE_ADDR" => "5.6.7.8"
|
|
44
|
+
|
|
45
|
+
assert_equal 200, last_response.status
|
|
46
|
+
assert_equal :safelist, notification_type
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "#safelist" do
|
|
4
|
+
before do
|
|
5
|
+
Rack::Attack.blocklist("block 1.2.3.4") do |request|
|
|
6
|
+
request.ip == "1.2.3.4"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Rack::Attack.safelist("safe path") do |request|
|
|
10
|
+
request.path == "/safe_space"
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "forbids request if blocklist condition is true and safelist is false" do
|
|
15
|
+
get "/", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
16
|
+
|
|
17
|
+
assert_equal 403, last_response.status
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "succeeds if blocklist condition is false and safelist is false" do
|
|
21
|
+
get "/", {}, "REMOTE_ADDR" => "5.6.7.8"
|
|
22
|
+
|
|
23
|
+
assert_equal 200, last_response.status
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it "succeeds request if blocklist condition is false and safelist is true" do
|
|
27
|
+
get "/safe_space", {}, "REMOTE_ADDR" => "5.6.7.8"
|
|
28
|
+
|
|
29
|
+
assert_equal 200, last_response.status
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "succeeds request if both blocklist and safelist conditions are true" do
|
|
33
|
+
get "/safe_space", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
34
|
+
|
|
35
|
+
assert_equal 200, last_response.status
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "notifies when the request is safe" do
|
|
39
|
+
notification_matched = nil
|
|
40
|
+
notification_type = nil
|
|
41
|
+
|
|
42
|
+
ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
|
|
43
|
+
notification_matched = request.env["rack.attack.matched"]
|
|
44
|
+
notification_type = request.env["rack.attack.match_type"]
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
get "/safe_space", {}, "REMOTE_ADDR" => "1.2.3.4"
|
|
48
|
+
|
|
49
|
+
assert_equal 200, last_response.status
|
|
50
|
+
assert_equal "safe path", notification_matched
|
|
51
|
+
assert_equal :safelist, notification_type
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require_relative "../spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Safelisting an IP subnet" do
|
|
4
|
+
before do
|
|
5
|
+
Rack::Attack.blocklist("admin") do |request|
|
|
6
|
+
request.path == "/admin"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
Rack::Attack.safelist_ip("5.6.0.0/16")
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "forbids request if blocklist condition is true and safelist is false" do
|
|
13
|
+
get "/admin", {}, "REMOTE_ADDR" => "5.7.0.0"
|
|
14
|
+
|
|
15
|
+
assert_equal 403, last_response.status
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "succeeds if blocklist condition is false and safelist is false" do
|
|
19
|
+
get "/", {}, "REMOTE_ADDR" => "5.7.0.0"
|
|
20
|
+
|
|
21
|
+
assert_equal 200, last_response.status
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "succeeds request if blocklist condition is false and safelist is true" do
|
|
25
|
+
get "/", {}, "REMOTE_ADDR" => "5.6.0.0"
|
|
26
|
+
|
|
27
|
+
assert_equal 200, last_response.status
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it "succeeds request if both blocklist and safelist conditions are true" do
|
|
31
|
+
get "/admin", {}, "REMOTE_ADDR" => "5.6.255.255"
|
|
32
|
+
|
|
33
|
+
assert_equal 200, last_response.status
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "notifies when the request is safe" do
|
|
37
|
+
notification_type = nil
|
|
38
|
+
|
|
39
|
+
ActiveSupport::Notifications.subscribe("rack.attack") do |_name, _start, _finish, _id, request|
|
|
40
|
+
notification_type = request.env["rack.attack.match_type"]
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
get "/admin", {}, "REMOTE_ADDR" => "5.6.0.0"
|
|
44
|
+
|
|
45
|
+
assert_equal 200, last_response.status
|
|
46
|
+
assert_equal :safelist, notification_type
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
|
|
3
|
+
if defined?(::Dalli)
|
|
4
|
+
require_relative "../../support/cache_store_helper"
|
|
5
|
+
require "active_support/cache/dalli_store"
|
|
6
|
+
require "timecop"
|
|
7
|
+
|
|
8
|
+
describe "ActiveSupport::Cache::DalliStore as a cache backend" do
|
|
9
|
+
before do
|
|
10
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::DalliStore.new
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
after do
|
|
14
|
+
Rack::Attack.cache.store.clear
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "../../spec_helper"
|
|
4
|
+
|
|
5
|
+
if defined?(::ConnectionPool) && defined?(::Dalli)
|
|
6
|
+
require_relative "../../support/cache_store_helper"
|
|
7
|
+
require "timecop"
|
|
8
|
+
|
|
9
|
+
describe "ActiveSupport::Cache::MemCacheStore (pooled) as a cache backend" do
|
|
10
|
+
before do
|
|
11
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new(pool_size: 2)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
after do
|
|
15
|
+
Rack::Attack.cache.store.clear
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it_works_for_cache_backed_features(fetch_from_store: ->(key) {
|
|
19
|
+
Rack::Attack.cache.store.read(key)
|
|
20
|
+
})
|
|
21
|
+
end
|
|
22
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
|
|
3
|
+
if defined?(::Dalli)
|
|
4
|
+
require_relative "../../support/cache_store_helper"
|
|
5
|
+
require "timecop"
|
|
6
|
+
|
|
7
|
+
describe "ActiveSupport::Cache::MemCacheStore as a cache backend" do
|
|
8
|
+
before do
|
|
9
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemCacheStore.new
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
after do
|
|
13
|
+
Rack::Attack.cache.store.clear
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.read(key) })
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require_relative "../../spec_helper"
|
|
2
|
+
require_relative "../../support/cache_store_helper"
|
|
3
|
+
|
|
4
|
+
require "timecop"
|
|
5
|
+
|
|
6
|
+
describe "ActiveSupport::Cache::MemoryStore as a cache backend" do
|
|
7
|
+
before do
|
|
8
|
+
Rack::Attack.cache.store = ActiveSupport::Cache::MemoryStore.new
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
after do
|
|
12
|
+
Rack::Attack.cache.store.clear
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it_works_for_cache_backed_features(fetch_from_store: ->(key) { Rack::Attack.cache.store.fetch(key) })
|
|
16
|
+
end
|