spanx 0.1.0 → 0.1.1

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.
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ script: "bundle exec rspec"
5
+ notifications:
6
+ email: false
data/README.md CHANGED
@@ -1,9 +1,13 @@
1
- # Spanx
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 is a simple Redis-based web request rate limiter, which integrates into any web application simply by monitoring
6
- one or more HTTP server access log file(s) in real time (think Apache/nginx access.log).
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
 
@@ -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.blocked_identifiers
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 = analyze_ip(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], count)
42
+ Spanx::IPChecker.new(key[0]).increment!(count, key[1])
43
43
  end
44
44
  reset_cache
45
45
  end
@@ -26,7 +26,7 @@ module Spanx
26
26
 
27
27
  def write
28
28
  if Spanx::IPChecker.enabled?
29
- ips = Spanx::IPChecker.blocked_identifiers
29
+ ips = Spanx::IPChecker.rate_limited_identifiers
30
30
  else
31
31
  Logger.log "writing empty block file due to disabled state"
32
32
  ips = []
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 check[:period_seconds].to_i, check[:max_allowed].to_i, check[:block_ttl].to_i
28
+ Spanx::IPChecker.check(check)
29
29
  end
30
30
  end
31
31
 
@@ -1,5 +1,5 @@
1
1
  require 'pause'
2
2
 
3
3
  class Spanx::IPChecker < Pause::Action
4
- scope "spanx:ip"
4
+ scope "ip"
5
5
  end
data/lib/spanx/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Spanx
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
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.3'
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 "#analyze_ip" do
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
- analyzer.analyze_ip(ip1).should be_nil
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, 2)
52
- Spanx::IPChecker.new(ip1).increment!(now - 15, 1)
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::BlockedAction" do
56
- analyzer.analyze_ip(ip1).should be_a(Pause::BlockedAction)
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(:blocked_identifiers).and_return([ip1, ip2])
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
- analyzer.should_receive(:analyze_ip).with(ip1)
81
- analyzer.should_receive(:analyze_ip).with(ip2)
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::BlockedAction))
109
- Spanx::IPChecker.new(ip1).increment!(Time.now.to_i - 5, 50000)
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(:blocked_identifiers).and_return(["1.2.3.4", "127.0.0.1"])
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::BlockedAction.new(ip_check, period_check, 500, time.to_i)}
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::BlockedAction.new(action, period, 50, time_blocked) }
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.0
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.3
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.3
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: