File: rack_attack_spec.rb

package info (click to toggle)
ruby-rack-attack 6.7.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 380 kB
  • sloc: ruby: 2,626; makefile: 4
file content (128 lines) | stat: -rw-r--r-- 3,568 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# frozen_string_literal: true

require_relative 'spec_helper'

describe 'Rack::Attack' do
  it_allows_ok_requests

  describe 'normalizing paths' do
    before do
      Rack::Attack.blocklist("banned_path") { |req| req.path == '/foo' }
    end

    it 'blocks requests with trailing slash' do
      if Rack::Attack::PathNormalizer == Rack::Attack::FallbackPathNormalizer
        skip "Normalization is only present on Rails"
      end

      get '/foo/'
      _(last_response.status).must_equal 403
    end
  end

  describe 'blocklist' do
    before do
      @bad_ip = '1.2.3.4'
      Rack::Attack.blocklist("ip #{@bad_ip}") { |req| req.ip == @bad_ip }
    end

    it 'has a blocklist' do
      _(Rack::Attack.blocklists.key?("ip #{@bad_ip}")).must_equal true
    end

    describe "a bad request" do
      before { get '/', {}, 'REMOTE_ADDR' => @bad_ip }

      it "should return a blocklist response" do
        _(last_response.status).must_equal 403
        _(last_response.body).must_equal "Forbidden\n"
      end

      it "should tag the env" do
        _(last_request.env['rack.attack.matched']).must_equal "ip #{@bad_ip}"
        _(last_request.env['rack.attack.match_type']).must_equal :blocklist
      end

      it_allows_ok_requests
    end

    describe "and safelist" do
      before do
        @good_ua = 'GoodUA'
        Rack::Attack.safelist("good ua") { |req| req.user_agent == @good_ua }
      end

      it('has a safelist') { Rack::Attack.safelists.key?("good ua") }

      describe "with a request match both safelist & blocklist" do
        before { get '/', {}, 'REMOTE_ADDR' => @bad_ip, 'HTTP_USER_AGENT' => @good_ua }

        it "should allow safelists before blocklists" do
          _(last_response.status).must_equal 200
        end

        it "should tag the env" do
          _(last_request.env['rack.attack.matched']).must_equal 'good ua'
          _(last_request.env['rack.attack.match_type']).must_equal :safelist
        end
      end
    end

    describe '#blocklisted_responder' do
      it 'should exist' do
        _(Rack::Attack.blocklisted_responder).must_respond_to :call
      end
    end

    describe '#throttled_responder' do
      it 'should exist' do
        _(Rack::Attack.throttled_responder).must_respond_to :call
      end
    end
  end

  describe 'enabled' do
    it 'should be enabled by default' do
      _(Rack::Attack.enabled).must_equal true
    end

    it 'should directly pass request when disabled' do
      bad_ip = '1.2.3.4'
      Rack::Attack.blocklist("ip #{bad_ip}") { |req| req.ip == bad_ip }

      get '/', {}, 'REMOTE_ADDR' => bad_ip
      _(last_response.status).must_equal 403

      prev_enabled = Rack::Attack.enabled
      begin
        Rack::Attack.enabled = false
        get '/', {}, 'REMOTE_ADDR' => bad_ip
        _(last_response.status).must_equal 200
      ensure
        Rack::Attack.enabled = prev_enabled
      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