spanx 0.1.1 → 0.3.0
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 +7 -0
- data/Gemfile +10 -0
- data/Guardfile +4 -4
- data/README.md +37 -3
- data/conf/spanx-config.yml.example +5 -0
- data/lib/spanx.rb +1 -0
- data/lib/spanx/actor/analyzer.rb +1 -0
- data/lib/spanx/actor/log_reader.rb +18 -17
- data/lib/spanx/api.rb +7 -0
- data/lib/spanx/api/machine.rb +20 -0
- data/lib/spanx/api/resources/blocked_ips.rb +15 -0
- data/lib/spanx/api/resources/unblock_ip.rb +17 -0
- data/lib/spanx/cli.rb +12 -7
- data/lib/spanx/cli/analyze.rb +7 -6
- data/lib/spanx/cli/api.rb +70 -0
- data/lib/spanx/cli/disable.rb +2 -1
- data/lib/spanx/cli/enable.rb +2 -1
- data/lib/spanx/cli/flush.rb +27 -2
- data/lib/spanx/cli/report.rb +77 -0
- data/lib/spanx/cli/watch.rb +18 -11
- data/lib/spanx/helper/exit.rb +6 -2
- data/lib/spanx/helper/subclassing.rb +9 -0
- data/lib/spanx/logger.rb +1 -1
- data/lib/spanx/notifier/slack.rb +42 -0
- data/lib/spanx/runner.rb +1 -1
- data/lib/spanx/usage.rb +11 -7
- data/lib/spanx/version.rb +1 -1
- data/spanx.gemspec +3 -9
- data/spec/spanx/actor/analyzer_spec.rb +5 -5
- data/spec/spanx/actor/log_reader_spec.rb +78 -41
- data/spec/spanx/api/machine_spec.rb +33 -0
- data/spec/spanx/cli/cli_spec.rb +22 -0
- data/spec/spanx/config_spec.rb +2 -2
- data/spec/spanx/notifier/email_spec.rb +1 -1
- data/spec/spanx/notifier/slack_spec.rb +77 -0
- data/spec/spanx/runner_spec.rb +33 -33
- data/spec/spanx/usage_spec.rb +13 -0
- data/spec/spanx/whitelist_spec.rb +24 -24
- data/spec/spec_helper.rb +1 -0
- metadata +46 -111
- data/.pairs +0 -13
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spanx/api/machine'
|
2
|
+
require 'webmachine/test'
|
3
|
+
|
4
|
+
describe Spanx::API::Machine do
|
5
|
+
include Webmachine::Test
|
6
|
+
|
7
|
+
let(:app) { Spanx::API::Machine }
|
8
|
+
let(:json) { JSON.parse(response.body) }
|
9
|
+
|
10
|
+
describe "GET /ips/blocked" do
|
11
|
+
it 'returns a list of ips that have been blocked' do
|
12
|
+
Spanx::IPChecker.stub(:rate_limited_identifiers).and_return(["127.0.0.1", "123.45.34.1"])
|
13
|
+
|
14
|
+
get '/ips/blocked'
|
15
|
+
expect(response.code).to eq(200)
|
16
|
+
|
17
|
+
expect(json).to eq(["127.0.0.1", "123.45.34.1"])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "DELETE /ips/blocked/:ip" do
|
22
|
+
it 'unblocks the specified ip' do
|
23
|
+
mock_ip_checker = double
|
24
|
+
mock_ip_checker.should_receive(:unblock).once
|
25
|
+
|
26
|
+
Spanx::IPChecker.should_receive(:new).with('127.0.0.1').and_return(mock_ip_checker)
|
27
|
+
|
28
|
+
delete '/ips/blocked/127.0.0.1'
|
29
|
+
|
30
|
+
expect(response.code).to eq(204)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class ::TestCommand < Spanx::CLI
|
4
|
+
description 'Test Command'
|
5
|
+
end
|
6
|
+
|
7
|
+
describe Spanx::CLI do
|
8
|
+
before do
|
9
|
+
Spanx.stub(:redis).and_return(Redis.new)
|
10
|
+
end
|
11
|
+
|
12
|
+
describe 'cli' do
|
13
|
+
describe 'class description' do
|
14
|
+
let(:command) { ::TestCommand }
|
15
|
+
|
16
|
+
it 'should be set' do
|
17
|
+
expect(command.description).to eql 'Test Command'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
data/spec/spanx/config_spec.rb
CHANGED
@@ -51,8 +51,8 @@ describe Spanx::Config do
|
|
51
51
|
context "config file does not exist" do
|
52
52
|
let(:file) { "non_existent_file" }
|
53
53
|
it "should write error to stderr" do
|
54
|
-
$stderr.should_receive(:puts).with("Error: Unable to find config_file at #{file}")
|
55
|
-
$stderr.should_receive(:puts).with(Spanx::
|
54
|
+
$stderr.should_receive(:puts).with("Error: Unable to find config_file at #{file}\n")
|
55
|
+
$stderr.should_receive(:puts).with(Spanx::Usage.usage)
|
56
56
|
lambda {
|
57
57
|
Spanx::Config.new(file)
|
58
58
|
}.should raise_error(SystemExit)
|
@@ -45,7 +45,7 @@ describe Spanx::Notifier::Email, "#publish" do
|
|
45
45
|
subject { Spanx::Notifier::Email.new(config) }
|
46
46
|
|
47
47
|
let(:time_blocked) { Time.now }
|
48
|
-
let(:period) {
|
48
|
+
let(:period) { double() }
|
49
49
|
let(:action) { Spanx::IPChecker.new("1.2.3.4") }
|
50
50
|
let(:blocked_ip) { Pause::RateLimitedEvent.new(action, period, 50, time_blocked) }
|
51
51
|
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spanx::Notifier::Slack do
|
4
|
+
subject { Spanx::Notifier::Slack.new(config) }
|
5
|
+
|
6
|
+
describe "#enabled?" do
|
7
|
+
context "with no slack configuration" do
|
8
|
+
let(:config) { {} }
|
9
|
+
|
10
|
+
it { should_not be_enabled }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "with enabled slack configuration" do
|
14
|
+
let(:config) { {slack: {enabled: true}} }
|
15
|
+
|
16
|
+
it { should be_enabled }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#endpoint' do
|
21
|
+
context 'when there is no configuration' do
|
22
|
+
let(:config) { {} }
|
23
|
+
|
24
|
+
it 'returns nil' do
|
25
|
+
expect(subject.endpoint).to be_nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'when the configuration is set' do
|
30
|
+
let(:config) { {slack: {enabled: true, base_url: 'https://wanelo.slack.com', token: 'shipoopi'}} }
|
31
|
+
|
32
|
+
it 'should use base_url and token to generate the URL' do
|
33
|
+
expect(subject.endpoint.to_s).to eq('https://wanelo.slack.com/services/hooks/incoming-webhook?token=shipoopi')
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
describe "#publish" do
|
40
|
+
let(:blocked_ip) { double }
|
41
|
+
let(:blocked_ip_message) { 'shenanigans' }
|
42
|
+
let!(:stubbed_request) {
|
43
|
+
stub_request(:post, "https://wanelo.slack.com/services/hooks/incoming-webhook?token=shipoopi").
|
44
|
+
with(:body => "{\"text\":\"#{blocked_ip_message}\"}")
|
45
|
+
}
|
46
|
+
|
47
|
+
context 'when there is no configuration' do
|
48
|
+
let(:config) { {} }
|
49
|
+
|
50
|
+
it 'does not explode' do
|
51
|
+
expect { subject.publish(blocked_ip) }.to_not raise_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'when it is disabled' do
|
56
|
+
let(:config) { { slack: { enabled: false }} }
|
57
|
+
|
58
|
+
it 'does not publish a message' do
|
59
|
+
subject.publish(blocked_ip)
|
60
|
+
|
61
|
+
expect(stubbed_request).to_not have_been_requested
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when it is enabled' do
|
66
|
+
let(:config) { {slack: {enabled: true, base_url: 'https://wanelo.slack.com', token: 'shipoopi'}} }
|
67
|
+
|
68
|
+
it 'should publish the message to the endpoint' do
|
69
|
+
allow(subject).to receive(:generate_block_ip_message).and_return(blocked_ip_message)
|
70
|
+
|
71
|
+
subject.publish(blocked_ip)
|
72
|
+
|
73
|
+
expect(stubbed_request).to have_been_requested
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/spec/spanx/runner_spec.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Spanx::Runner do
|
4
|
-
let(:config) { {:access_log =>
|
4
|
+
let(:config) { {:access_log => 'logfile', :whitelist_file => 'whitelist', :log_reader => {:tail_interval => 1}} }
|
5
5
|
let(:runner) { Spanx::Runner.new(config) }
|
6
6
|
let(:faker) { double() }
|
7
7
|
|
8
|
-
describe
|
9
|
-
it
|
8
|
+
describe '#new' do
|
9
|
+
it 'should create a new thread queue' do
|
10
10
|
runner.queue.should be_a(Queue)
|
11
11
|
end
|
12
12
|
|
13
|
-
context
|
14
|
-
let(:collector) {
|
15
|
-
let(:writer) {
|
16
|
-
let(:log_reader) {
|
17
|
-
let(:analyzer) {
|
13
|
+
context 'actor initialization' do
|
14
|
+
let(:collector) { double('collector') }
|
15
|
+
let(:writer) { double('writer') }
|
16
|
+
let(:log_reader) { double('log_reader') }
|
17
|
+
let(:analyzer) { double('analyzer') }
|
18
18
|
|
19
19
|
before do
|
20
20
|
Spanx::Runner.any_instance.stub(:collector).and_return(collector)
|
@@ -23,25 +23,25 @@ describe Spanx::Runner do
|
|
23
23
|
Spanx::Runner.any_instance.stub(:analyzer).and_return(analyzer)
|
24
24
|
end
|
25
25
|
|
26
|
-
it
|
27
|
-
Spanx::Runner.new(
|
28
|
-
Spanx::Runner.new(
|
29
|
-
Spanx::Runner.new(
|
30
|
-
Spanx::Runner.new(
|
31
|
-
Spanx::Runner.new(
|
26
|
+
it 'should match string args' do
|
27
|
+
Spanx::Runner.new('collector', config).actors.should == [collector]
|
28
|
+
Spanx::Runner.new('writer', config).actors.should == [writer]
|
29
|
+
Spanx::Runner.new('log_reader', config).actors.should == [log_reader]
|
30
|
+
Spanx::Runner.new('analyzer', config).actors.should == [analyzer]
|
31
|
+
Spanx::Runner.new('collector', 'analyzer', config).actors.should == [collector, analyzer]
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
34
|
+
it 'raises if an invalid actor is passed' do
|
35
35
|
lambda {
|
36
|
-
Spanx::Runner.new(
|
37
|
-
}.should raise_error(
|
36
|
+
Spanx::Runner.new('methods', config)
|
37
|
+
}.should raise_error('Invalid actor')
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
describe
|
43
|
-
let(:actor1) {
|
44
|
-
let(:actor2) {
|
42
|
+
describe '#run' do
|
43
|
+
let(:actor1) { double('actor') }
|
44
|
+
let(:actor2) { double('actor') }
|
45
45
|
|
46
46
|
before do
|
47
47
|
actor1.should_receive(:run).and_return(actor1)
|
@@ -49,53 +49,53 @@ describe Spanx::Runner do
|
|
49
49
|
actor2.should_receive(:join).and_return(true)
|
50
50
|
end
|
51
51
|
|
52
|
-
it
|
52
|
+
it 'runs all actors and joins the last one' do
|
53
53
|
runner.actors = [actor1, actor2]
|
54
54
|
runner.run
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
describe
|
58
|
+
describe '#collector' do
|
59
59
|
before { Spanx::Actor::Collector.should_receive(:new).with(config, runner.queue).and_return(faker) }
|
60
60
|
|
61
|
-
it
|
61
|
+
it 'should create a collector' do
|
62
62
|
runner.collector.should === faker
|
63
63
|
end
|
64
64
|
end
|
65
65
|
|
66
|
-
describe
|
67
|
-
before { Spanx::Whitelist.should_receive(:new).with(
|
66
|
+
describe '#whitelist' do
|
67
|
+
before { Spanx::Whitelist.should_receive(:new).with('whitelist').and_return(faker) }
|
68
68
|
|
69
|
-
it
|
69
|
+
it 'should create a collector' do
|
70
70
|
runner.whitelist.should === faker
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
-
describe
|
74
|
+
describe '#log_reader' do
|
75
75
|
let(:whitelist) { double() }
|
76
76
|
|
77
77
|
before do
|
78
78
|
runner.should_receive(:whitelist).and_return(whitelist)
|
79
|
-
Spanx::Actor::LogReader.should_receive(:new).with(
|
79
|
+
Spanx::Actor::LogReader.should_receive(:new).with('logfile', runner.queue, 1, whitelist).and_return(faker)
|
80
80
|
end
|
81
81
|
|
82
|
-
it
|
82
|
+
it 'should create a log reader' do
|
83
83
|
runner.log_reader.should === faker
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
87
|
-
describe
|
87
|
+
describe '#analyzer' do
|
88
88
|
before { Spanx::Actor::Analyzer.should_receive(:new).with(config).and_return(faker) }
|
89
89
|
|
90
|
-
it
|
90
|
+
it 'should create an analyzer' do
|
91
91
|
runner.analyzer.should === faker
|
92
92
|
end
|
93
93
|
end
|
94
94
|
|
95
|
-
describe
|
95
|
+
describe '#writer' do
|
96
96
|
before { Spanx::Actor::Writer.should_receive(:new).with(config).and_return(faker) }
|
97
97
|
|
98
|
-
it
|
98
|
+
it 'should create an analyzer' do
|
99
99
|
runner.writer.should === faker
|
100
100
|
end
|
101
101
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Spanx::Usage do
|
4
|
+
describe 'usage' do
|
5
|
+
let(:usage) { Spanx::Usage.usage }
|
6
|
+
it 'should be set' do
|
7
|
+
|
8
|
+
expect(usage).to match /flush/
|
9
|
+
expect(usage).to match /analyze/
|
10
|
+
expect(usage).to match /Analyze IP traffic and save blocked IPs/
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -2,32 +2,32 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe Spanx::Whitelist do
|
4
4
|
let(:whitelist) { Spanx::Whitelist.new(file) }
|
5
|
-
let(:file) {
|
5
|
+
let(:file) { 'spec/fixtures/whitelist.txt' }
|
6
6
|
|
7
7
|
|
8
|
-
describe
|
9
|
-
context
|
10
|
-
it
|
8
|
+
describe '#new' do
|
9
|
+
context 'with filename' do
|
10
|
+
it 'loads whitelist patterns into memory' do
|
11
11
|
whitelist.patterns[0].should eql(/^127\.0\.0\.1/)
|
12
12
|
whitelist.patterns[1].should eql(/^10\.1\.\d{1,3}\.\d{1,3}/)
|
13
|
-
whitelist.patterns.each{ |p| p.is_a?(Regexp).should
|
13
|
+
whitelist.patterns.each{ |p| p.is_a?(Regexp).should be_truthy }
|
14
14
|
end
|
15
15
|
end
|
16
16
|
|
17
|
-
context
|
17
|
+
context 'without filename' do
|
18
18
|
let(:file) { nil }
|
19
19
|
|
20
|
-
it
|
20
|
+
it 'keeps an empty whitelist table' do
|
21
21
|
whitelist.patterns.should == []
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
25
|
-
context
|
26
|
-
let(:file) {
|
25
|
+
context 'with non-existent file' do
|
26
|
+
let(:file) { 'non-existent-whitelist' }
|
27
27
|
|
28
|
-
it
|
29
|
-
$stderr.should_receive(:puts).with("Error: Unable to find whitelist file at #{file}")
|
30
|
-
$stderr.should_receive(:puts).with(Spanx::
|
28
|
+
it 'writes an error to stderr and exits' do
|
29
|
+
$stderr.should_receive(:puts).with("Error: Unable to find whitelist file at #{file}\n")
|
30
|
+
$stderr.should_receive(:puts).with(Spanx::Usage.usage)
|
31
31
|
|
32
32
|
lambda {
|
33
33
|
whitelist.patterns
|
@@ -37,28 +37,28 @@ describe Spanx::Whitelist do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
|
40
|
-
describe
|
41
|
-
context
|
40
|
+
describe '#match?' do
|
41
|
+
context 'IP address matching' do
|
42
42
|
it 'is true if IP address is in match list' do
|
43
|
-
whitelist.match?(
|
43
|
+
expect(whitelist.match?('127.0.0.1')).to be_truthy
|
44
44
|
end
|
45
45
|
|
46
46
|
it 'is false if IP address does not match patterns' do
|
47
|
-
whitelist.match?(
|
47
|
+
whitelist.match?('sadfasdf').should be_falsy
|
48
48
|
end
|
49
49
|
end
|
50
50
|
|
51
|
-
context
|
52
|
-
let(:googlebot) {
|
53
|
-
it
|
54
|
-
whitelist.match?(googlebot).should
|
51
|
+
context 'User agent matches pattern' do
|
52
|
+
let(:googlebot) { '66.249.73.24 - - [18/Oct/2012:03:25:33 -0700] GET /p/2213071/39535615 HTTP/1.1 "200" 3943 "-" "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "2.87""Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" "-"upstream_addr 127.0.0.1:8100upstream_response_time 0.082 request_time 0.082' }
|
53
|
+
it 'whitelists googlebot' do
|
54
|
+
whitelist.match?(googlebot).should be_truthy
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
context
|
59
|
-
let(:log) {
|
60
|
-
it
|
61
|
-
whitelist.match?(log).should
|
58
|
+
context 'users/me matches' do
|
59
|
+
let(:log) { '66.249.73.24 - - [18/Oct/2012:03:25:33 -0700] GET /users/me HTTP/1.1 "200" 3943 "-" "-" "Mozilla/5.0 ' }
|
60
|
+
it 'excludes users/me' do
|
61
|
+
whitelist.match?(log).should be_truthy
|
62
62
|
end
|
63
63
|
end
|
64
64
|
|
data/spec/spec_helper.rb
CHANGED
@@ -9,6 +9,7 @@ ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__)
|
|
9
9
|
require 'rubygems'
|
10
10
|
require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
|
11
11
|
require 'spanx'
|
12
|
+
require 'webmock/rspec'
|
12
13
|
|
13
14
|
Dir['spec/support/**/*.rb'].each { |filename| require_relative "../#{filename}" }
|
14
15
|
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spanx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.3.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Konstantin Gredeskoul
|
@@ -10,182 +9,104 @@ authors:
|
|
10
9
|
autorequire:
|
11
10
|
bindir: bin
|
12
11
|
cert_chain: []
|
13
|
-
date:
|
12
|
+
date: 2014-11-13 00:00:00.000000000 Z
|
14
13
|
dependencies:
|
15
14
|
- !ruby/object:Gem::Dependency
|
16
15
|
name: pause
|
17
16
|
requirement: !ruby/object:Gem::Requirement
|
18
|
-
none: false
|
19
17
|
requirements:
|
20
|
-
- -
|
18
|
+
- - ">="
|
21
19
|
- !ruby/object:Gem::Version
|
22
|
-
version: 0
|
20
|
+
version: '0'
|
23
21
|
type: :runtime
|
24
22
|
prerelease: false
|
25
23
|
version_requirements: !ruby/object:Gem::Requirement
|
26
|
-
none: false
|
27
24
|
requirements:
|
28
|
-
- -
|
25
|
+
- - ">="
|
29
26
|
- !ruby/object:Gem::Version
|
30
|
-
version: 0
|
27
|
+
version: '0'
|
31
28
|
- !ruby/object:Gem::Dependency
|
32
29
|
name: file-tail
|
33
30
|
requirement: !ruby/object:Gem::Requirement
|
34
|
-
none: false
|
35
31
|
requirements:
|
36
|
-
- -
|
32
|
+
- - ">="
|
37
33
|
- !ruby/object:Gem::Version
|
38
34
|
version: '0'
|
39
35
|
type: :runtime
|
40
36
|
prerelease: false
|
41
37
|
version_requirements: !ruby/object:Gem::Requirement
|
42
|
-
none: false
|
43
38
|
requirements:
|
44
|
-
- -
|
39
|
+
- - ">="
|
45
40
|
- !ruby/object:Gem::Version
|
46
41
|
version: '0'
|
47
42
|
- !ruby/object:Gem::Dependency
|
48
43
|
name: mixlib-cli
|
49
44
|
requirement: !ruby/object:Gem::Requirement
|
50
|
-
none: false
|
51
45
|
requirements:
|
52
|
-
- -
|
46
|
+
- - ">="
|
53
47
|
- !ruby/object:Gem::Version
|
54
48
|
version: '0'
|
55
49
|
type: :runtime
|
56
50
|
prerelease: false
|
57
51
|
version_requirements: !ruby/object:Gem::Requirement
|
58
|
-
none: false
|
59
52
|
requirements:
|
60
|
-
- -
|
53
|
+
- - ">="
|
61
54
|
- !ruby/object:Gem::Version
|
62
55
|
version: '0'
|
63
56
|
- !ruby/object:Gem::Dependency
|
64
57
|
name: daemons
|
65
58
|
requirement: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
59
|
requirements:
|
68
|
-
- -
|
60
|
+
- - ">="
|
69
61
|
- !ruby/object:Gem::Version
|
70
62
|
version: '0'
|
71
63
|
type: :runtime
|
72
64
|
prerelease: false
|
73
65
|
version_requirements: !ruby/object:Gem::Requirement
|
74
|
-
none: false
|
75
66
|
requirements:
|
76
|
-
- -
|
67
|
+
- - ">="
|
77
68
|
- !ruby/object:Gem::Version
|
78
69
|
version: '0'
|
79
70
|
- !ruby/object:Gem::Dependency
|
80
71
|
name: tinder
|
81
72
|
requirement: !ruby/object:Gem::Requirement
|
82
|
-
none: false
|
83
73
|
requirements:
|
84
|
-
- -
|
74
|
+
- - ">="
|
85
75
|
- !ruby/object:Gem::Version
|
86
76
|
version: '0'
|
87
77
|
type: :runtime
|
88
78
|
prerelease: false
|
89
79
|
version_requirements: !ruby/object:Gem::Requirement
|
90
|
-
none: false
|
91
80
|
requirements:
|
92
|
-
- -
|
81
|
+
- - ">="
|
93
82
|
- !ruby/object:Gem::Version
|
94
83
|
version: '0'
|
95
84
|
- !ruby/object:Gem::Dependency
|
96
85
|
name: mail
|
97
86
|
requirement: !ruby/object:Gem::Requirement
|
98
|
-
none: false
|
99
|
-
requirements:
|
100
|
-
- - ~>
|
101
|
-
- !ruby/object:Gem::Version
|
102
|
-
version: 2.4.4
|
103
|
-
type: :runtime
|
104
|
-
prerelease: false
|
105
|
-
version_requirements: !ruby/object:Gem::Requirement
|
106
|
-
none: false
|
107
|
-
requirements:
|
108
|
-
- - ~>
|
109
|
-
- !ruby/object:Gem::Version
|
110
|
-
version: 2.4.4
|
111
|
-
- !ruby/object:Gem::Dependency
|
112
|
-
name: rspec
|
113
|
-
requirement: !ruby/object:Gem::Requirement
|
114
|
-
none: false
|
115
87
|
requirements:
|
116
|
-
- -
|
88
|
+
- - ">="
|
117
89
|
- !ruby/object:Gem::Version
|
118
90
|
version: '0'
|
119
|
-
type: :
|
120
|
-
prerelease: false
|
121
|
-
version_requirements: !ruby/object:Gem::Requirement
|
122
|
-
none: false
|
123
|
-
requirements:
|
124
|
-
- - ! '>='
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: '0'
|
127
|
-
- !ruby/object:Gem::Dependency
|
128
|
-
name: fakeredis
|
129
|
-
requirement: !ruby/object:Gem::Requirement
|
130
|
-
none: false
|
131
|
-
requirements:
|
132
|
-
- - ! '>='
|
133
|
-
- !ruby/object:Gem::Version
|
134
|
-
version: '0'
|
135
|
-
type: :development
|
136
|
-
prerelease: false
|
137
|
-
version_requirements: !ruby/object:Gem::Requirement
|
138
|
-
none: false
|
139
|
-
requirements:
|
140
|
-
- - ! '>='
|
141
|
-
- !ruby/object:Gem::Version
|
142
|
-
version: '0'
|
143
|
-
- !ruby/object:Gem::Dependency
|
144
|
-
name: timecop
|
145
|
-
requirement: !ruby/object:Gem::Requirement
|
146
|
-
none: false
|
147
|
-
requirements:
|
148
|
-
- - ! '>='
|
149
|
-
- !ruby/object:Gem::Version
|
150
|
-
version: '0'
|
151
|
-
type: :development
|
152
|
-
prerelease: false
|
153
|
-
version_requirements: !ruby/object:Gem::Requirement
|
154
|
-
none: false
|
155
|
-
requirements:
|
156
|
-
- - ! '>='
|
157
|
-
- !ruby/object:Gem::Version
|
158
|
-
version: '0'
|
159
|
-
- !ruby/object:Gem::Dependency
|
160
|
-
name: guard-rspec
|
161
|
-
requirement: !ruby/object:Gem::Requirement
|
162
|
-
none: false
|
163
|
-
requirements:
|
164
|
-
- - ! '>='
|
165
|
-
- !ruby/object:Gem::Version
|
166
|
-
version: '0'
|
167
|
-
type: :development
|
91
|
+
type: :runtime
|
168
92
|
prerelease: false
|
169
93
|
version_requirements: !ruby/object:Gem::Requirement
|
170
|
-
none: false
|
171
94
|
requirements:
|
172
|
-
- -
|
95
|
+
- - ">="
|
173
96
|
- !ruby/object:Gem::Version
|
174
97
|
version: '0'
|
175
98
|
- !ruby/object:Gem::Dependency
|
176
|
-
name:
|
99
|
+
name: webmachine
|
177
100
|
requirement: !ruby/object:Gem::Requirement
|
178
|
-
none: false
|
179
101
|
requirements:
|
180
|
-
- -
|
102
|
+
- - ">="
|
181
103
|
- !ruby/object:Gem::Version
|
182
104
|
version: '0'
|
183
|
-
type: :
|
105
|
+
type: :runtime
|
184
106
|
prerelease: false
|
185
107
|
version_requirements: !ruby/object:Gem::Requirement
|
186
|
-
none: false
|
187
108
|
requirements:
|
188
|
-
- -
|
109
|
+
- - ">="
|
189
110
|
- !ruby/object:Gem::Version
|
190
111
|
version: '0'
|
191
112
|
description: Real time IP parsing and rate detection gem for access_log files
|
@@ -197,11 +118,10 @@ executables:
|
|
197
118
|
extensions: []
|
198
119
|
extra_rdoc_files: []
|
199
120
|
files:
|
200
|
-
- .gitignore
|
201
|
-
- .
|
202
|
-
- .
|
203
|
-
- .
|
204
|
-
- .travis.yml
|
121
|
+
- ".gitignore"
|
122
|
+
- ".rspec"
|
123
|
+
- ".rvmrc"
|
124
|
+
- ".travis.yml"
|
205
125
|
- Gemfile
|
206
126
|
- Guardfile
|
207
127
|
- LICENSE
|
@@ -215,11 +135,17 @@ files:
|
|
215
135
|
- lib/spanx/actor/collector.rb
|
216
136
|
- lib/spanx/actor/log_reader.rb
|
217
137
|
- lib/spanx/actor/writer.rb
|
138
|
+
- lib/spanx/api.rb
|
139
|
+
- lib/spanx/api/machine.rb
|
140
|
+
- lib/spanx/api/resources/blocked_ips.rb
|
141
|
+
- lib/spanx/api/resources/unblock_ip.rb
|
218
142
|
- lib/spanx/cli.rb
|
219
143
|
- lib/spanx/cli/analyze.rb
|
144
|
+
- lib/spanx/cli/api.rb
|
220
145
|
- lib/spanx/cli/disable.rb
|
221
146
|
- lib/spanx/cli/enable.rb
|
222
147
|
- lib/spanx/cli/flush.rb
|
148
|
+
- lib/spanx/cli/report.rb
|
223
149
|
- lib/spanx/cli/watch.rb
|
224
150
|
- lib/spanx/config.rb
|
225
151
|
- lib/spanx/helper.rb
|
@@ -232,6 +158,7 @@ files:
|
|
232
158
|
- lib/spanx/notifier/base.rb
|
233
159
|
- lib/spanx/notifier/campfire.rb
|
234
160
|
- lib/spanx/notifier/email.rb
|
161
|
+
- lib/spanx/notifier/slack.rb
|
235
162
|
- lib/spanx/runner.rb
|
236
163
|
- lib/spanx/usage.rb
|
237
164
|
- lib/spanx/version.rb
|
@@ -246,39 +173,42 @@ files:
|
|
246
173
|
- spec/spanx/actor/collector_spec.rb
|
247
174
|
- spec/spanx/actor/log_reader_spec.rb
|
248
175
|
- spec/spanx/actor/writer_spec.rb
|
176
|
+
- spec/spanx/api/machine_spec.rb
|
177
|
+
- spec/spanx/cli/cli_spec.rb
|
249
178
|
- spec/spanx/config_spec.rb
|
250
179
|
- spec/spanx/helper/timing_spec.rb
|
251
180
|
- spec/spanx/notifier/base_spec.rb
|
252
181
|
- spec/spanx/notifier/campfire_spec.rb
|
253
182
|
- spec/spanx/notifier/email_spec.rb
|
183
|
+
- spec/spanx/notifier/slack_spec.rb
|
254
184
|
- spec/spanx/runner_spec.rb
|
185
|
+
- spec/spanx/usage_spec.rb
|
255
186
|
- spec/spanx/whitelist_spec.rb
|
256
187
|
- spec/spec_helper.rb
|
257
188
|
- spec/support/fakeredis.rb
|
258
189
|
- spec/support/mail.rb
|
259
190
|
homepage: https://github.com/wanelo/spanx
|
260
191
|
licenses: []
|
192
|
+
metadata: {}
|
261
193
|
post_install_message:
|
262
194
|
rdoc_options: []
|
263
195
|
require_paths:
|
264
196
|
- lib
|
265
197
|
required_ruby_version: !ruby/object:Gem::Requirement
|
266
|
-
none: false
|
267
198
|
requirements:
|
268
|
-
- -
|
199
|
+
- - ">="
|
269
200
|
- !ruby/object:Gem::Version
|
270
201
|
version: '0'
|
271
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
272
|
-
none: false
|
273
203
|
requirements:
|
274
|
-
- -
|
204
|
+
- - ">="
|
275
205
|
- !ruby/object:Gem::Version
|
276
206
|
version: '0'
|
277
207
|
requirements: []
|
278
208
|
rubyforge_project:
|
279
|
-
rubygems_version:
|
209
|
+
rubygems_version: 2.2.2
|
280
210
|
signing_key:
|
281
|
-
specification_version:
|
211
|
+
specification_version: 4
|
282
212
|
summary: Real time IP parsing and rate detection gem for access_log files
|
283
213
|
test_files:
|
284
214
|
- spec/fixtures/access.log.1
|
@@ -290,13 +220,18 @@ test_files:
|
|
290
220
|
- spec/spanx/actor/collector_spec.rb
|
291
221
|
- spec/spanx/actor/log_reader_spec.rb
|
292
222
|
- spec/spanx/actor/writer_spec.rb
|
223
|
+
- spec/spanx/api/machine_spec.rb
|
224
|
+
- spec/spanx/cli/cli_spec.rb
|
293
225
|
- spec/spanx/config_spec.rb
|
294
226
|
- spec/spanx/helper/timing_spec.rb
|
295
227
|
- spec/spanx/notifier/base_spec.rb
|
296
228
|
- spec/spanx/notifier/campfire_spec.rb
|
297
229
|
- spec/spanx/notifier/email_spec.rb
|
230
|
+
- spec/spanx/notifier/slack_spec.rb
|
298
231
|
- spec/spanx/runner_spec.rb
|
232
|
+
- spec/spanx/usage_spec.rb
|
299
233
|
- spec/spanx/whitelist_spec.rb
|
300
234
|
- spec/spec_helper.rb
|
301
235
|
- spec/support/fakeredis.rb
|
302
236
|
- spec/support/mail.rb
|
237
|
+
has_rdoc:
|