logstash-input-blueliv 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f93593a5f0ac2f84de2133f030b010f9d6e9ddcc
4
+ data.tar.gz: 96f7fb2c72c1fbcce6bf03e59d0564084e5ef836
5
+ SHA512:
6
+ metadata.gz: 94a6b4fa308af18e6e4a01618c7443fc697aa312197475f7ec5fe34f3b4ceb1b80add236292b907cc54f942530d1d6ef114e67218d5d105131f5367aea1944d8
7
+ data.tar.gz: 6ba937047471ea2ca1df09c2e27d1084ae0e25799acd83bcd57607c48d62f7ee5096a67f994023f02c2f7c685188474750c6b8ffecf3cac0c97540cd70593c9a
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ Gemfile.lock
3
+ Gemfile.bak
4
+ .bundle
5
+ vendor
6
+ *.json
data/CHANGELOG.md ADDED
@@ -0,0 +1,3 @@
1
+ **v1.0.0 - 2015 Jun 30**
2
+
3
+ + First version
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source 'https://rubygems.org'
2
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright 2015 Blueliv
2
+
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+
7
+ http://www.apache.org/licenses/LICENSE-2.0
8
+
9
+ Unless required by applicable law or agreed to in writing, software
10
+ distributed under the License is distributed on an "AS IS" BASIS,
11
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ See the License for the specific language governing permissions and
13
+ limitations under the License.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Logstash Input Plugin by Blueliv
2
+
3
+ This is an input plugin for [Logstash](https://github.com/elasticsearch/logstash) created and maintained by Blueliv (community@blueliv.com), that allows to access Blueliv's Cyber-Threat Intelligence feeds, such as Crime Servers and Bot IPs.
4
+
5
+ ## Minimum Requirements
6
+
7
+ * API key (get yours <a href="https://map.blueliv.com" target="_blank">here</a>)
8
+ * Logstash >= 1.5.0
9
+ * 1.5 GB of RAM of heap size for Logstash (``-Xmx1500m``)
10
+
11
+ ## Installing
12
+
13
+ ```
14
+ $LS_HOME/bin/plugin install logstash-input-blueliv
15
+ ```
16
+
17
+ ### Configuration
18
+
19
+ This plugin has the following configuration parameters:
20
+
21
+ + ``api_url`` (default: ``https://api.blueliv.com``): the URL of the API. It may change if you are using our free or commercial API.
22
+ + ``api_key``: The API key to access our feeds. This parameter is **mandatory**.
23
+ + ``http_timeout``(default: ``500`` seconds): HTTP timeout for each API call.
24
+ + ``feeds``: It is a [hash](http://ruby-doc.org/core-1.9.3/Hash.html) that specifies the parameters to access each one of our feeds. Each feed may be configured with the following properties:
25
+ + ``active`` (default: ``false``): if the feed is active or not.
26
+ + ``feed_type`` (default: ``test``): the type of the feed that you want. For **Crime Servers** apart from ``test`` (for _debug_ purposes) you only have ``all``. As of **Bot IPs** you may choose between ``non_pos`` (all BotIPs **but** the ones from Point-of-Sale), ``pos`` (only from POS) or ``full`` (all of them) feed.
27
+ + ``interval`` (default: ``600`` seconds for BotIPs and ``900`` seconds for Crime Servers). The intervall of polling data from our API.
28
+
29
+ The default configuration for ``feeds`` field is the following:
30
+ ```javascript
31
+ "crimeservers" => {
32
+ "active" => false,
33
+ "feed_type" => "test",
34
+ "interval" => 900,
35
+ },
36
+ "botips" => {
37
+ "active" => false,
38
+ "feed_type" => "test",
39
+ "interval" => 600
40
+ }
41
+ ```
42
+
43
+
44
+ #### Example
45
+
46
+ ```javascript
47
+ input {
48
+ blueliv { api_key => "7da63a74-bece-42b0-843b-15728e44740d"
49
+ feeds => { "botips" => {
50
+ "active" => true
51
+ "feed_type" => "non_pos"
52
+ }
53
+ "crimeservers" => {
54
+ "active" => true
55
+ "feed_type" => "all"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+ Be aware that if you do not specify a given field, the default value will be configured. In this case, we did not touch the ``interval`` field for the feeds, so the defaults will apply.
62
+
63
+ ## Need Help?
64
+
65
+ Need help? Send us an email to community@blueliv.com
66
+
67
+ ## Contributing
68
+
69
+ All contributions are welcome: ideas, patches, documentation, bug reports, complaints, and even something you drew up on a napkin.
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "logstash/devutils/rake"
@@ -0,0 +1,208 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: UTF-8
3
+
4
+ require "date"
5
+ require "logstash/inputs/base"
6
+ require "logstash/namespace"
7
+ require "rest-client"
8
+ require "securerandom"
9
+
10
+ ONE_DAY_IN_SECONDS = 86400
11
+
12
+ RESOURCES = {
13
+ :crimeservers => {
14
+ :items => "crimeServers",
15
+ :endpoint => "/v1/crimeserver",
16
+ :feeds => {
17
+ :all => {
18
+ 900 => "/last",
19
+ 3600 => "/recent",
20
+ ONE_DAY_IN_SECONDS => "/online"
21
+ },
22
+ :test => {
23
+ 900 => "/test"
24
+ }
25
+ }
26
+ },
27
+ :botips => {
28
+ :items => "ips",
29
+ :endpoint => "/v1/ip",
30
+ :feeds => {
31
+ :non_pos => {
32
+ 600 => "/recent",
33
+ 3600 => "/last"
34
+ },
35
+ :pos => {
36
+ 600 => "/pos/recent",
37
+ 3600 => "/pos/last"
38
+ },
39
+ :full => {
40
+ 600 => "/full/recent",
41
+ 3600 => "/full/last"
42
+ },
43
+ :test => {
44
+ 600 => "/test"
45
+ }
46
+ }
47
+ }
48
+ }
49
+
50
+ DEFAULT_CONFIG = {
51
+ "crimeservers" => {
52
+ "active" => false,
53
+ "feed_type" => "test",
54
+ "interval" => 900,
55
+ "initialize" => true
56
+ },
57
+ "botips" => {
58
+ "active" => false,
59
+ "feed_type" => "test",
60
+ "interval" => 600
61
+ }
62
+ }
63
+
64
+ INITIALIZE_FILE = "blueliv.ini"
65
+ FAILURE_SLEEP = 5 # seconds
66
+
67
+ class LogStash::Inputs::Blueliv < LogStash::Inputs::Base
68
+ attr_accessor :auth, :timeout
69
+
70
+ config_name "blueliv"
71
+
72
+ @contact = "community@blueliv.com"
73
+
74
+ default :codec, "plain"
75
+
76
+ config :api_key, :validate => :string, :default => ""
77
+ config :api_url, :validate => :string, :default => "https://api.blueliv.com"
78
+ config :http_timeout, :validate => :number, :default => 500
79
+
80
+ config :feeds, :validate => :hash, :default => {}
81
+
82
+ public
83
+ def register
84
+ merger = proc { |key, v1, v2| Hash === v1 && Hash === v2 ? v1.merge(v2, &merger) : Array === v1 && Array === v2 ? v1 | v2 : [:undefined, nil, :nil].include?(v2) ? v1 : v2 }
85
+
86
+ @auth = "Bearer #{api_key}"
87
+ @feeds = DEFAULT_CONFIG.merge(feeds, &merger)
88
+ @timeout = http_timeout
89
+ end
90
+
91
+ def run(queue)
92
+ threads = []
93
+ @feeds.each do |name, conf|
94
+ if feeds[name]["active"]
95
+ if feeds[name]["initialize"]
96
+ if not db_updated?(DateTime.now)
97
+ threads << Thread.new do
98
+ url, interval = get_url(name, @feeds[name]["feed_type"], ONE_DAY_IN_SECONDS)
99
+ get_feed(queue, name, url) { write_last_update_db(DateTime.now) }
100
+ url, interval = get_url(name, @feeds[name]["feed_type"], @feeds[name]["interval"])
101
+ get_feed_each(queue, name, url, interval) { write_last_update_db(DateTime.now) }
102
+ end
103
+ end
104
+ else
105
+ url, interval = get_url(name, @feeds[name]["feed_type"], @feeds[name]["interval"])
106
+ threads << Thread.new(get_feed_each(queue, name, url, interval))
107
+ end
108
+ end
109
+ end
110
+
111
+ threads.map {|t| t.join}
112
+ end
113
+
114
+ def db_updated?(now)
115
+ result = false
116
+ if File.exists?(INITIALIZE_FILE)
117
+ File.open(INITIALIZE_FILE, "r") do |file|
118
+ file.each do |line|
119
+ unless line.strip.start_with? "#"
120
+ begin
121
+ time = DateTime.strptime(line.strip, "%s")
122
+ result = ((now - time) * ONE_DAY_IN_SECONDS).to_i < ONE_DAY_IN_SECONDS
123
+ break
124
+ rescue Exception => e
125
+ @logger.error(e)
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+
132
+ result
133
+ end
134
+
135
+ def write_last_update_db(date)
136
+ File.open(INITIALIZE_FILE, "w") do |file|
137
+ file.write("# GENERATED FILE. DO NOT EDIT IT\n")
138
+ file.write("#{date.to_time.to_i}\n")
139
+ end
140
+ end
141
+
142
+ def get_url(name, feed_type, feed_interval)
143
+ base_url = @api_url + RESOURCES[name.to_sym][:endpoint]
144
+
145
+ if RESOURCES[name.to_sym][:feeds].key?(feed_type.to_sym)
146
+ feed_lookup = RESOURCES[name.to_sym][:feeds][feed_type.to_sym]
147
+ else
148
+ raise ArgumentError, "Feed #{feed_type} does not exist!"
149
+ end
150
+
151
+ interval = nil
152
+ feed_lookup.keys.each do |k|
153
+ if feed_interval <= k
154
+ interval = k
155
+ break
156
+ end
157
+ end
158
+ interval = feed_lookup.keys.max if interval == nil
159
+
160
+ return base_url + feed_lookup[interval], interval
161
+ end
162
+
163
+ def get_feed_each(queue, name, url, interval, &block)
164
+ loop do
165
+ get_feed(queue, name, url, &block)
166
+ sleep(interval)
167
+ end
168
+ end
169
+
170
+ def get_feed(queue, name, url, &block)
171
+ loop do
172
+ begin
173
+ response = client.get url, :Authorization => @auth, :timeout => @timeout
174
+ response_json = JSON.parse(response.body)
175
+ items = response_json[RESOURCES[name.to_sym][:items]]
176
+ items.each do |it|
177
+ it["location"] = [it["longitude"].to_f, it["latitude"].to_f]
178
+ collection = RESOURCES[name.to_sym][:items].downcase
179
+ it["@collection"] = collection
180
+ it["_id"] = SecureRandom.base64(32) unless it.has_key?("_id")
181
+ evt = LogStash::Event.new(it)
182
+ decorate(evt)
183
+ queue << evt
184
+ end
185
+ block.call if block
186
+ break
187
+ rescue RestClient::Exception => e
188
+ @logger.error(e)
189
+ case e.http_code
190
+ when 401, 403
191
+ @logger.info("You do not have access to this resource! Please contact #{@contact}")
192
+ break
193
+ else
194
+ @logger.info("Will retry in #{FAILURE_SLEEP} seconds")
195
+ sleep(FAILURE_SLEEP)
196
+ end
197
+ rescue Exception => e
198
+ @logger.info("Will retry in #{FAILURE_SLEEP} seconds")
199
+ sleep(FAILURE_SLEEP)
200
+ end
201
+ end
202
+ end
203
+
204
+ def client
205
+ RestClient
206
+ end
207
+
208
+ end
@@ -0,0 +1,25 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "logstash-input-blueliv"
3
+ s.version = "0.1.0"
4
+ s.licenses = ["Apache License (2.0)"]
5
+ s.summary = "This plugin allows users to access Blueliv Crime Servers and Bot IPs feeds."
6
+ s.description = "This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install logstash-input-blueliv. This gem is not a stand-alone program"
7
+ s.authors = ["Blueliv"]
8
+ s.email = 'community@blueliv.com'
9
+ s.homepage = "http://github.com/Blueliv/logstash-input-blueliv"
10
+ s.require_paths = ["lib"]
11
+
12
+ # Files
13
+ s.files = `git ls-files`.split($\)
14
+ # Tests
15
+ s.test_files = s.files.grep(%r{^(test|spec|features)/})
16
+
17
+
18
+ s.metadata = { "logstash_plugin" => "true", "logstash_group" => "input" }
19
+
20
+ # Gem dependencies
21
+ s.add_runtime_dependency "logstash-core", ">= 1.4.0", "< 2.0.0"
22
+ s.add_runtime_dependency "logstash-codec-plain"
23
+ s.add_runtime_dependency "rest-client", "~> 1.8.0"
24
+ s.add_development_dependency "logstash-devutils"
25
+ end
@@ -0,0 +1,82 @@
1
+ require "logstash/devutils/rspec/spec_helper"
2
+ require "logstash/inputs/blueliv"
3
+ require "json"
4
+
5
+ describe LogStash::Inputs::Blueliv do
6
+ let(:settings) {
7
+ {
8
+ "api_key" => "mykey",
9
+ "feeds" => {
10
+ "crimeservers" => {
11
+ "active" => false,
12
+ "feed_type" => "test",
13
+ "interval" => 900,
14
+ "initialize" => true
15
+ },
16
+ "botips" => {
17
+ "active" => false,
18
+ "feed_type" => "test",
19
+ "interval" => 600
20
+ }
21
+ }
22
+ }
23
+ }
24
+
25
+ let(:authorization) {
26
+ "Bearer mykey"
27
+ }
28
+
29
+ let(:timeout) {
30
+ 500
31
+ }
32
+
33
+ let(:url) {
34
+ "https://api.blueliv.com/v1/ip/full/last"
35
+ }
36
+
37
+ let(:feed_name) {
38
+ "botips"
39
+ }
40
+
41
+ let(:mock_response) {
42
+ RestClient::Response.create(
43
+ {
44
+ "ips" => [
45
+ {
46
+ "field1" => "this",
47
+ "longitude" => 0.0,
48
+ "latitude" => 0.0
49
+ }
50
+ ],
51
+ "meta" => {
52
+ "totalSize" => 1,
53
+ "updated" => "2015-07-01T10:40:00+0000",
54
+ "nextUpdate" => "2015-07-01T10:50:00+0000"
55
+ }
56
+ }.to_json, nil, nil, nil)
57
+ }
58
+
59
+ context "with json codec, when server responds" do
60
+ it "should not add an event if user is not authorized" do
61
+ subject = LogStash::Inputs::Blueliv.new()
62
+ logstash_queue = Queue.new
63
+
64
+ subject.get_feed logstash_queue, feed_name, url
65
+ expect(logstash_queue.size).to eq(0)
66
+ subject.teardown
67
+ end
68
+
69
+ it "should add an event if user is authorized" do
70
+ subject = LogStash::Inputs::Blueliv.new()
71
+ logstash_queue = Queue.new
72
+ subject.auth = authorization
73
+ subject.timeout = timeout
74
+
75
+ allow(subject.client).to receive(:get).with(url, :Authorization => authorization, :timeout => timeout).and_return(mock_response)
76
+ subject.get_feed logstash_queue, feed_name, url
77
+ expect(logstash_queue.size).to eq(1)
78
+ subject.teardown
79
+ end
80
+ end
81
+ end
82
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: logstash-input-blueliv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Blueliv
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - '>='
17
+ - !ruby/object:Gem::Version
18
+ version: 1.4.0
19
+ - - <
20
+ - !ruby/object:Gem::Version
21
+ version: 2.0.0
22
+ name: logstash-core
23
+ prerelease: false
24
+ type: :runtime
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.4.0
30
+ - - <
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ - !ruby/object:Gem::Dependency
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - '>='
37
+ - !ruby/object:Gem::Version
38
+ version: '0'
39
+ name: logstash-codec-plain
40
+ prerelease: false
41
+ type: :runtime
42
+ version_requirements: !ruby/object:Gem::Requirement
43
+ requirements:
44
+ - - '>='
45
+ - !ruby/object:Gem::Version
46
+ version: '0'
47
+ - !ruby/object:Gem::Dependency
48
+ requirement: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ~>
51
+ - !ruby/object:Gem::Version
52
+ version: 1.8.0
53
+ name: rest-client
54
+ prerelease: false
55
+ type: :runtime
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ~>
59
+ - !ruby/object:Gem::Version
60
+ version: 1.8.0
61
+ - !ruby/object:Gem::Dependency
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - '>='
65
+ - !ruby/object:Gem::Version
66
+ version: '0'
67
+ name: logstash-devutils
68
+ prerelease: false
69
+ type: :development
70
+ version_requirements: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - '>='
73
+ - !ruby/object:Gem::Version
74
+ version: '0'
75
+ description: This gem is a logstash plugin required to be installed on top of the Logstash core pipeline using $LS_HOME/bin/plugin install logstash-input-blueliv. This gem is not a stand-alone program
76
+ email: community@blueliv.com
77
+ executables: []
78
+ extensions: []
79
+ extra_rdoc_files: []
80
+ files:
81
+ - .gitignore
82
+ - CHANGELOG.md
83
+ - Gemfile
84
+ - LICENSE
85
+ - README.md
86
+ - Rakefile
87
+ - lib/logstash/inputs/blueliv.rb
88
+ - logstash-input-blueliv.gemspec
89
+ - spec/inputs/blueliv_spec.rb
90
+ homepage: http://github.com/Blueliv/logstash-input-blueliv
91
+ licenses:
92
+ - Apache License (2.0)
93
+ metadata:
94
+ logstash_plugin: 'true'
95
+ logstash_group: input
96
+ post_install_message:
97
+ rdoc_options: []
98
+ require_paths:
99
+ - lib
100
+ required_ruby_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
110
+ requirements: []
111
+ rubyforge_project:
112
+ rubygems_version: 2.4.5
113
+ signing_key:
114
+ specification_version: 4
115
+ summary: This plugin allows users to access Blueliv Crime Servers and Bot IPs feeds.
116
+ test_files:
117
+ - spec/inputs/blueliv_spec.rb