logstash-input-blueliv 0.1.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 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