spanx 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +6 -0
- data/README.md +7 -3
- data/lib/spanx/actor/analyzer.rb +2 -9
- data/lib/spanx/actor/collector.rb +1 -1
- data/lib/spanx/actor/writer.rb +1 -1
- data/lib/spanx/config.rb +1 -1
- data/lib/spanx/ip_checker.rb +1 -1
- data/lib/spanx/version.rb +1 -1
- data/spanx.gemspec +1 -1
- data/spec/spanx/actor/analyzer_spec.rb +11 -12
- data/spec/spanx/actor/writer_spec.rb +1 -1
- data/spec/spanx/notifier/base_spec.rb +1 -1
- data/spec/spanx/notifier/email_spec.rb +1 -1
- metadata +4 -4
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
-
|
1
|
+
Spanx
|
2
|
+
=====
|
3
|
+
|
4
|
+
[![Build status](https://secure.travis-ci.org/wanelo/spanx.png)](http://travis-ci.org/wanelo/spanx)
|
2
5
|
|
3
6
|
Spank down IP spam: IP-based rate limiting for web applications behind HTTP server such as nginx or Apache.
|
4
7
|
|
5
|
-
Spanx
|
6
|
-
|
8
|
+
Spanx integrates into any web application simply by monitoring one or more HTTP server access log file(s)
|
9
|
+
in real time (think Apache/nginx access.log). Spanx is built on top of the gem Pause, which is a simple Redis-based rate
|
10
|
+
limiter.
|
7
11
|
|
8
12
|
Basic flow is as follows:
|
9
13
|
|
data/lib/spanx/actor/analyzer.rb
CHANGED
@@ -38,13 +38,12 @@ module Spanx
|
|
38
38
|
def analyze_all_ips
|
39
39
|
return unless Spanx::IPChecker.enabled?
|
40
40
|
|
41
|
-
@previously_blocked_ips = Spanx::IPChecker.
|
42
|
-
|
41
|
+
@previously_blocked_ips = Spanx::IPChecker.rate_limited_identifiers
|
43
42
|
ips = Spanx::IPChecker.tracked_identifiers
|
44
43
|
|
45
44
|
Logger.logging "analyzed #{ips.size} IPs" do
|
46
45
|
ips.each do |ip|
|
47
|
-
blocked_ip =
|
46
|
+
blocked_ip = Spanx::IPChecker.new(ip).analyze
|
48
47
|
blocked_ips << blocked_ip if blocked_ip
|
49
48
|
end
|
50
49
|
end
|
@@ -54,12 +53,6 @@ module Spanx
|
|
54
53
|
blocked_ips.clear
|
55
54
|
end
|
56
55
|
|
57
|
-
# Analyze individual IP for all defined periods. As soon as one
|
58
|
-
# rule is triggered, exit the method
|
59
|
-
def analyze_ip(ip)
|
60
|
-
Spanx::IPChecker.new(ip).analyze
|
61
|
-
end
|
62
|
-
|
63
56
|
private
|
64
57
|
|
65
58
|
def initialize_notifiers(config)
|
@@ -39,7 +39,7 @@ module Spanx
|
|
39
39
|
semaphore.synchronize {
|
40
40
|
Logger.logging "flushing cache with [#{cache.keys.size}] keys" do
|
41
41
|
cache.each_pair do |key, count|
|
42
|
-
Spanx::IPChecker.new(key[0]).increment!(key[1]
|
42
|
+
Spanx::IPChecker.new(key[0]).increment!(count, key[1])
|
43
43
|
end
|
44
44
|
reset_cache
|
45
45
|
end
|
data/lib/spanx/actor/writer.rb
CHANGED
data/lib/spanx/config.rb
CHANGED
@@ -25,7 +25,7 @@ module Spanx
|
|
25
25
|
|
26
26
|
if self.has_key?(:analyzer) && self[:analyzer].has_key?(:period_checks)
|
27
27
|
self[:analyzer][:period_checks].each do |check|
|
28
|
-
Spanx::IPChecker.check
|
28
|
+
Spanx::IPChecker.check(check)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
data/lib/spanx/ip_checker.rb
CHANGED
data/lib/spanx/version.rb
CHANGED
data/spanx.gemspec
CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |gem|
|
|
15
15
|
gem.require_paths = %w(lib)
|
16
16
|
gem.version = Spanx::VERSION
|
17
17
|
|
18
|
-
gem.add_dependency 'pause', '~> 0.0.
|
18
|
+
gem.add_dependency 'pause', '~> 0.0.4'
|
19
19
|
gem.add_dependency 'file-tail'
|
20
20
|
gem.add_dependency 'mixlib-cli'
|
21
21
|
gem.add_dependency 'daemons'
|
@@ -36,24 +36,24 @@ describe Spanx::Actor::Analyzer do
|
|
36
36
|
let(:ip1) { "127.0.0.1" }
|
37
37
|
let(:ip2) { "192.168.0.1" }
|
38
38
|
|
39
|
-
describe "#
|
39
|
+
describe "#RateLimitedEvent" do
|
40
40
|
|
41
41
|
let(:now) { period_marker(10, Time.now.to_i) + 1 }
|
42
42
|
|
43
43
|
context "IP blocking rules are not matched" do
|
44
44
|
it "returns nil" do
|
45
|
-
|
45
|
+
Spanx::IPChecker.new(ip1).analyze.should be_nil
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
49
|
context "IP blocking rules are matched" do
|
50
50
|
before do
|
51
|
-
Spanx::IPChecker.new(ip1).increment!(now - 5
|
52
|
-
Spanx::IPChecker.new(ip1).increment!(now - 15
|
51
|
+
Spanx::IPChecker.new(ip1).increment!(2, now - 5)
|
52
|
+
Spanx::IPChecker.new(ip1).increment!(1, now - 15)
|
53
53
|
end
|
54
54
|
|
55
|
-
it "returns a Pause::
|
56
|
-
|
55
|
+
it "returns a Pause::RateLimitedEvent" do
|
56
|
+
Spanx::IPChecker.new(ip1).analyze.should be_a(Pause::RateLimitedEvent)
|
57
57
|
end
|
58
58
|
end
|
59
59
|
end
|
@@ -61,7 +61,7 @@ describe Spanx::Actor::Analyzer do
|
|
61
61
|
describe "#analyze_all_ips" do
|
62
62
|
context "checker is disabled" do
|
63
63
|
before do
|
64
|
-
Spanx::IPChecker.stub(:
|
64
|
+
Spanx::IPChecker.stub(:rate_limited_identifiers).and_return([ip1, ip2])
|
65
65
|
Spanx::IPChecker.stub(:enabled?).and_return(false)
|
66
66
|
analyzer.should_not_receive(:analyze_ip)
|
67
67
|
end
|
@@ -73,12 +73,11 @@ describe Spanx::Actor::Analyzer do
|
|
73
73
|
|
74
74
|
context "adapter is enabled" do
|
75
75
|
let(:period_check) { double(period_seconds: 1, max_allowed: 1, block_ttl: nil) }
|
76
|
-
let(:blocked_ip) { Pause::BlockedAction.new(mock(identifier:ip2), period_check, 200, 1234566) }
|
77
76
|
|
78
77
|
before do
|
79
78
|
Spanx::IPChecker.should_receive(:tracked_identifiers).and_return([ip1, ip2])
|
80
|
-
|
81
|
-
|
79
|
+
Spanx::IPChecker.should_receive(:new).with(ip1).and_return(mock(analyze: nil))
|
80
|
+
Spanx::IPChecker.should_receive(:new).with(ip2).and_return(mock(analyze: nil))
|
82
81
|
end
|
83
82
|
|
84
83
|
it "analyzes each IP found" do
|
@@ -105,8 +104,8 @@ describe Spanx::Actor::Analyzer do
|
|
105
104
|
end
|
106
105
|
|
107
106
|
it "should publish to notifiers on blocking IP" do
|
108
|
-
fake_notifier.should_receive(:publish).with(an_instance_of(Pause::
|
109
|
-
Spanx::IPChecker.new(ip1).increment!(Time.now.to_i - 5
|
107
|
+
fake_notifier.should_receive(:publish).with(an_instance_of(Pause::RateLimitedEvent))
|
108
|
+
Spanx::IPChecker.new(ip1).increment!(50000, Time.now.to_i - 5)
|
110
109
|
analyzer.analyze_all_ips
|
111
110
|
end
|
112
111
|
end
|
@@ -19,7 +19,7 @@ describe Spanx::Actor::Writer do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
before do
|
22
|
-
Spanx::IPChecker.stub(:
|
22
|
+
Spanx::IPChecker.stub(:rate_limited_identifiers).and_return(["1.2.3.4", "127.0.0.1"])
|
23
23
|
end
|
24
24
|
|
25
25
|
context "when adapter is enabled" do
|
@@ -6,7 +6,7 @@ describe Spanx::Notifier::Base do
|
|
6
6
|
let(:time) { Time.now }
|
7
7
|
let(:ip_check) { Spanx::IPChecker.new("1.2.3.4") }
|
8
8
|
let(:period_check) { Pause::PeriodCheck.new(60, 100, 80)}
|
9
|
-
let(:blocked_action) { Pause::
|
9
|
+
let(:blocked_action) { Pause::RateLimitedEvent.new(ip_check, period_check, 500, time.to_i)}
|
10
10
|
|
11
11
|
it "should set the correct message content" do
|
12
12
|
Spanx::Notifier::Base.new.send(:generate_block_ip_message, blocked_action).should ==
|
@@ -47,7 +47,7 @@ describe Spanx::Notifier::Email, "#publish" do
|
|
47
47
|
let(:time_blocked) { Time.now }
|
48
48
|
let(:period) { mock() }
|
49
49
|
let(:action) { Spanx::IPChecker.new("1.2.3.4") }
|
50
|
-
let(:blocked_ip) { Pause::
|
50
|
+
let(:blocked_ip) { Pause::RateLimitedEvent.new(action, period, 50, time_blocked) }
|
51
51
|
|
52
52
|
before { Spanx::Notifier::Email.any_instance.stub(:configure_email_gateway) }
|
53
53
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spanx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
requirements:
|
20
20
|
- - ~>
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0.0.
|
22
|
+
version: 0.0.4
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,7 +27,7 @@ dependencies:
|
|
27
27
|
requirements:
|
28
28
|
- - ~>
|
29
29
|
- !ruby/object:Gem::Version
|
30
|
-
version: 0.0.
|
30
|
+
version: 0.0.4
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
32
|
name: file-tail
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
@@ -201,6 +201,7 @@ files:
|
|
201
201
|
- .pairs
|
202
202
|
- .rspec
|
203
203
|
- .rvmrc
|
204
|
+
- .travis.yml
|
204
205
|
- Gemfile
|
205
206
|
- Guardfile
|
206
207
|
- LICENSE
|
@@ -299,4 +300,3 @@ test_files:
|
|
299
300
|
- spec/spec_helper.rb
|
300
301
|
- spec/support/fakeredis.rb
|
301
302
|
- spec/support/mail.rb
|
302
|
-
has_rdoc:
|