shodanz 1.0.2 → 1.0.3

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 64bf4789450bf85bdb1d354218d49c8bde71505e
4
- data.tar.gz: ef3506930d1125e20c93a4d2126defdfba8ba797
2
+ SHA256:
3
+ metadata.gz: e5da697873b94e412d3732b7a6ed529f83b9aa70bc2e14ae4b9a3ac8738659d4
4
+ data.tar.gz: f6636ec96aa077123f9e312e14259e1ddfadf6709225bc7c9b3b64b06c0ef611
5
5
  SHA512:
6
- metadata.gz: 9ec386f513214a9782eab065267661b75657468dc685740758e10da26b8b51417754eab719907adc3b5840884eeae317167a91b314f0fc2dd0964a23155a1533
7
- data.tar.gz: 6adda2fd0ac14b127c4de42325d1051cbd5bd4dea5ac2bb93858dfe9b5c31cdaaa903165fe1c71e72a281ed7e84fe5f59725df7debe67bca96f731f5851e33e1
6
+ metadata.gz: 4ca0447aa1e55d340da2959730edfb982565771adfe80bdc3a2206f4215669bf998c7cfc4c981c77635a3a58abb830f30b96ce29db46d7f72654166982d46f4e
7
+ data.tar.gz: f814bf859bbd66b80e85e3c9be339c4e68dde1717f389f49940910acfd648bd26178fd140d19d83935b632097d3525ff5c4688d860d8a30468b7d324e0754214
data/README.md CHANGED
@@ -54,9 +54,8 @@ client.rest_api.host_count("apache")
54
54
  client.rest_api.host_count("apache", country: "US")
55
55
  client.rest_api.host_count("apache", country: "US", state: "MI")
56
56
  client.rest_api.host_count("apache", country: "US", state: "MI", city: "Detroit")
57
- client.rest_api.host_count("apache", country: "US", state: "MI", city: "Detroit")
58
- client.rest_api.host_count("nginx". facets: { country: 5 })
59
- client.rest_api.host_count("apache". facets: { country: 5 })
57
+ client.rest_api.host_count("nginx", facets: { country: 5 })
58
+ client.rest_api.host_count("apache", facets: { country: 5 })
60
59
  ```
61
60
 
62
61
  #### Scan Targets
@@ -2,8 +2,10 @@ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
2
  require 'shodanz'
3
3
  require 'pry'
4
4
 
5
- rest_api = Shodanz.api.rest.new
6
- streaming_api = Shodanz.api.streaming.new
7
- exploits_api = Shodanz.api.exploits.new
5
+ # rest_api = Shodanz.api.rest.new
6
+ # streaming_api = Shodanz.api.streaming.new
7
+ # exploits_api = Shodanz.api.exploits.new
8
+
9
+ client = Shodanz.client.new
8
10
 
9
11
  binding.pry
@@ -0,0 +1,28 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require "shodanz"
3
+ require "chart_js"
4
+
5
+ module Top10
6
+ @rest_api = Shodanz.api.rest.new
7
+ def self.check(product)
8
+ begin
9
+ @rest_api.host_count(product: product, facets: { country: 10 })["facets"]["country"].collect { |x| x.values }.to_h.invert
10
+ rescue
11
+ puts "Unable to succesffully check the Shodan API."
12
+ exit 1
13
+ end
14
+ end
15
+ end
16
+
17
+ results = Top10.check("apache")
18
+
19
+ ChartJS.bar do
20
+ file "top_10_apache.html"
21
+ data do
22
+ labels results.keys
23
+ dataset "Countries" do
24
+ color :random
25
+ data results.values
26
+ end
27
+ end
28
+ end
@@ -1,13 +1,18 @@
1
- require "unirest"
2
- require "oj"
3
- require "shodanz/version"
4
- require "shodanz/api"
5
- require "shodanz/client"
1
+ require 'unirest'
2
+ require 'oj'
3
+ require 'shodanz/version'
4
+ require 'shodanz/api'
5
+ require 'shodanz/client'
6
6
 
7
+ # Shodanz is a modern Ruby gem for Shodan, the world's
8
+ # first search engine for Internet-connected devices.
7
9
  module Shodanz
10
+ # Shortcut for {Shodanz::API}
8
11
  def self.api
9
12
  API
10
13
  end
14
+
15
+ # Shortcut for {Shodanz::Client}
11
16
  def self.client
12
17
  Client
13
18
  end
@@ -1,29 +1,31 @@
1
- require_relative "apis/rest.rb"
2
- require_relative "apis/streaming.rb"
3
- require_relative "apis/exploits.rb"
1
+ require_relative 'apis/rest.rb'
2
+ require_relative 'apis/streaming.rb'
3
+ require_relative 'apis/exploits.rb'
4
4
 
5
5
  module Shodanz
6
- # There are 2 APIs for accessing Shodan: the REST API
7
- # and the Streaming API. The REST API provides methods
8
- # to search Shodan, look up hosts, get summary information
9
- # on queries and a variety of utility methods to make
10
- # developing easier. The Streaming API provides a raw,
11
- # real-time feed of the data that Shodan is currently
12
- # collecting. There are several feeds that can be subscribed
13
- # to, but the data can't be searched or otherwise interacted
14
- # with; it's a live feed of data meant for large-scale
6
+ # There are 2 APIs for accessing Shodan: the REST API
7
+ # and the Streaming API. The REST API provides methods
8
+ # to search Shodan, look up hosts, get summary information
9
+ # on queries and a variety of utility methods to make
10
+ # developing easier. The Streaming API provides a raw,
11
+ # real-time feed of the data that Shodan is currently
12
+ # collecting. There are several feeds that can be subscribed
13
+ # to, but the data can't be searched or otherwise interacted
14
+ # with; it's a live feed of data meant for large-scale
15
15
  # consumption of Shodan's information.
16
+ #
17
+ # @author Kent 'picat' Gruber
16
18
  module API
17
19
  # REST API class.
18
20
  def self.rest
19
21
  REST
20
22
  end
21
-
23
+
22
24
  # Streaming API class.
23
25
  def self.streaming
24
26
  Streaming
25
27
  end
26
-
28
+
27
29
  # Exploits API class.
28
30
  def self.exploits
29
31
  Exploits
@@ -1,8 +1,7 @@
1
1
  module Shodanz
2
-
3
2
  module API
4
- # The Exploits API provides access to several exploit
5
- # and vulnerability data sources. At the moment, it
3
+ # The Exploits API provides access to several exploit
4
+ # and vulnerability data sources. At the moment, it
6
5
  # searches across the following:
7
6
  # - Exploit DB
8
7
  # - Metasploit
@@ -10,76 +9,80 @@ module Shodanz
10
9
  #
11
10
  # @author Kent 'picat' Gruber
12
11
  class Exploits
12
+ # @return [String]
13
13
  attr_accessor :key
14
-
14
+
15
15
  # The path to the REST API endpoint.
16
- URL = "https://exploits.shodan.io/api/"
16
+ URL = 'https://exploits.shodan.io/api/'.freeze
17
17
 
18
- # @param key [String] SHODAN API key, defaulted to the *SHODAN_API_KEY* enviroment variable.
18
+ # @param key [String] SHODAN API key, defaulted to
19
+ # the *SHODAN_API_KEY* enviroment variable.
19
20
  def initialize(key: ENV['SHODAN_API_KEY'])
20
21
  self.key = key
21
- warn "No key has been found or provided!" unless self.key?
22
+ warn 'No key has been found or provided!' unless key?
22
23
  end
23
24
 
24
25
  # Check if there's an API key.
26
+ # @return [String]
25
27
  def key?
26
- return true if @key; false
28
+ return true if @key
29
+ false
27
30
  end
28
31
 
29
- # Search across a variety of data sources for exploits and
32
+ # Search across a variety of data sources for exploits and
30
33
  # use facets to get summary information.
31
34
  # == Example
32
35
  # api.search("SQL", port: 443)
33
36
  # api.search(port: 22)
34
37
  # api.search(type: "dos")
35
- def search(query = "", facets: {}, page: 1, **params)
38
+ def search(query = '', page: 1, **params)
36
39
  params[:query] = query
37
40
  params = turn_into_query(params)
38
41
  facets = turn_into_facets(facets)
39
42
  params[:page] = page
40
- get("search", params.merge(facets))
43
+ get('search', params.merge(facets))
41
44
  end
42
45
 
43
- # This method behaves identical to the "/search" method with
46
+ # This method behaves identical to the "/search" method with
44
47
  # the difference that it doesn't return any results.
45
48
  # == Example
46
49
  # api.count(type: "dos")
47
- def count(query = "", facets: {}, page: 1, **params)
50
+ def count(query = '', page: 1, **params)
48
51
  params[:query] = query
49
52
  params = turn_into_query(params)
50
53
  facets = turn_into_facets(params)
51
54
  params[:page] = page
52
- get("count", params.merge(facets))
55
+ get('count', params.merge(facets))
53
56
  end
54
57
 
55
58
  # Perform a direct GET HTTP request to the REST API.
56
59
  def get(path, **params)
57
60
  resp = Unirest.get "#{URL}#{path}?key=#{@key}", parameters: params
58
- raise resp.body["error"] if resp.code != 200 and resp.body.has_key?("error")
61
+ if resp.code != 200 && resp.body.key?('error')
62
+ raise resp.body['error']
63
+ end
59
64
  resp.body
60
65
  end
61
66
 
62
67
  private
63
68
 
64
69
  def turn_into_query(params)
65
- filters = params.reject { |key, value| key == :query }
70
+ filters = params.reject { |key, _| key == :query }
66
71
  filters.each do |key, value|
67
72
  params[:query] << " #{key}:#{value}"
68
73
  end
69
- params.select { |key, value| key == :query }
74
+ params.select { |key, _| key == :query }
70
75
  end
71
76
 
72
77
  def turn_into_facets(facets)
73
- filters = facets.reject { |key, value| key == :facets }
78
+ filters = facets.reject { |key, _| key == :facets }
74
79
  facets[:facets] = []
75
80
  filters.each do |key, value|
76
81
  facets[:facets] << "#{key}:#{value}"
77
82
  end
78
- facets[:facets] = facets[:facets].join(",")
79
- facets.select { |key, value| key == :facets }
83
+ facets[:facets] = facets[:facets].join(',')
84
+ facets.select { |key, _| key == :facets }
80
85
  end
81
-
82
86
  end
83
-
84
87
  end
85
88
  end
@@ -5,6 +5,7 @@ module Shodanz
5
5
  # hosts, get summary information on queries and a variety
6
6
  # of other utilities. This requires you to have an API key
7
7
  # which you can get from Shodan.
8
+ #
8
9
  # @author Kent 'picat' Gruber
9
10
  class REST
10
11
  attr_accessor :key
@@ -112,7 +113,7 @@ module Shodanz
112
113
  def crawl_for(**params)
113
114
  params[:query] = ""
114
115
  params = turn_into_query(params)
115
- post("shodan/scan/internet", params)
116
+ post('shodan/scan/internet', params)
116
117
  end
117
118
 
118
119
  # Check the progress of a previously submitted scan request.
@@ -122,49 +123,52 @@ module Shodanz
122
123
 
123
124
  # Use this method to obtain a list of search queries that users have saved in Shodan.
124
125
  def community_queries(**params)
125
- get("shodan/query", params)
126
+ get('shodan/query', params)
126
127
  end
127
128
 
128
129
  # Use this method to search the directory of search queries that users have saved in Shodan.
129
130
  def search_for_community_query(query, **params)
130
131
  params[:query] = query
131
132
  params = turn_into_query(params)
132
- get("shodan/query/search", params)
133
+ get('shodan/query/search', params)
133
134
  end
134
135
 
135
136
  # Use this method to obtain a list of popular tags for the saved search queries in Shodan.
136
137
  def popular_query_tags(size = 10)
137
138
  params = {}
138
139
  params[:size] = size
139
- get("shodan/query/tags", params)
140
+ get('shodan/query/tags', params)
140
141
  end
141
142
 
142
143
  # Returns information about the Shodan account linked to this API key.
143
144
  def profile
144
- get("account/profile")
145
+ get('account/profile')
145
146
  end
146
147
 
147
148
  # Look up the IP address for the provided list of hostnames.
148
149
  def resolve(*hostnames)
149
- get("dns/resolve", hostnames: hostnames.join(","))
150
+ get('dns/resolve', hostnames: hostnames.join(","))
150
151
  end
151
152
 
152
- # Look up the hostnames that have been defined for the given list of IP addresses.
153
+ # Look up the hostnames that have been defined for the
154
+ # given list of IP addresses.
153
155
  def reverse_lookup(*ips)
154
- get("dns/reverse", ips: ips.join(","))
156
+ get('dns/reverse', ips: ips.join(","))
155
157
  end
156
158
 
157
- # Shows the HTTP headers that your client sends when connecting to a webserver.
159
+ # Shows the HTTP headers that your client sends when
160
+ # connecting to a webserver.
158
161
  def http_headers
159
- get("tools/httpheaders")
162
+ get('tools/httpheaders')
160
163
  end
161
164
 
162
165
  # Get your current IP address as seen from the Internet.
163
166
  def my_ip
164
- get("tools/my_ip")
167
+ get('tools/myip')
165
168
  end
166
169
 
167
- # Calculates a honeypot probability score ranging from 0 (not a honeypot) to 1.0 (is a honeypot).
170
+ # Calculates a honeypot probability score ranging
171
+ # from 0 (not a honeypot) to 1.0 (is a honeypot).
168
172
  def honeypot_score(ip)
169
173
  get("labs/honeyscore/#{ip}")
170
174
  end
@@ -177,38 +181,43 @@ module Shodanz
177
181
  # Perform a direct GET HTTP request to the REST API.
178
182
  def get(path, **params)
179
183
  resp = Unirest.get "#{URL}#{path}?key=#{@key}", parameters: params
180
- raise resp if resp.code != 200 #and resp.body.has_key?("error")
184
+ if resp.code != 200
185
+ binding.pry
186
+ raise resp.body['error'] if resp.body.key?('error')
187
+ raise resp
188
+ end
181
189
  resp.body
182
190
  end
183
191
 
184
192
  # Perform a direct POST HTTP request to the REST API.
185
193
  def post(path, **params)
186
194
  resp = Unirest.post "#{URL}#{path}?key=#{@key}", parameters: params
187
- raise resp.body["error"] if resp.code != 200 and resp.body.has_key?("error")
195
+ if resp.code != 200
196
+ raise resp.body['error'] if resp.body.key?('error')
197
+ raise resp
198
+ end
188
199
  resp.body
189
200
  end
190
201
 
191
202
  private
192
203
 
193
204
  def turn_into_query(params)
194
- filters = params.reject { |key, value| key == :query }
205
+ filters = params.reject { |key, _| key == :query }
195
206
  filters.each do |key, value|
196
207
  params[:query] << " #{key}:#{value}"
197
208
  end
198
- params.select { |key, value| key == :query }
209
+ params.select { |key, _| key == :query }
199
210
  end
200
211
 
201
212
  def turn_into_facets(facets)
202
- filters = facets.reject { |key, value| key == :facets }
213
+ filters = facets.reject { |key, _| key == :facets }
203
214
  facets[:facets] = []
204
215
  filters.each do |key, value|
205
216
  facets[:facets] << "#{key}:#{value}"
206
217
  end
207
- facets[:facets] = facets[:facets].join(",")
208
- facets.select { |key, value| key == :facets }
218
+ facets[:facets] = facets[:facets].join(',')
219
+ facets.select { |key, _| key == :facets }
209
220
  end
210
-
211
221
  end
212
-
213
222
  end
214
223
  end
@@ -1,22 +1,22 @@
1
1
  module Shodanz
2
+ # General client container class for all three
3
+ # of Shodan's available API endpoints in a
4
+ # convient place to use.
5
+ #
6
+ # @author Kent 'picat' Gruber
2
7
  class Client
8
+ # @return [Shodanz::API::REST]
9
+ attr_reader :rest_api
10
+ # @return [Shodanz::API::Streaming]
11
+ attr_reader :streaming_api
12
+ # @return [Shodanz::API::Exploits]
13
+ attr_reader :exploits_api
14
+
3
15
  # Create a new client to connect to any of the APIs.
4
16
  def initialize
5
17
  @rest_api = Shodanz.api.rest.new
6
18
  @streaming_api = Shodanz.api.streaming.new
7
- @exploits_api = Shodanz.api.exploits.new
8
- end
9
-
10
- def rest_api
11
- @rest_api
12
- end
13
-
14
- def streaming_api
15
- @streaming_api
16
- end
17
-
18
- def exploits_api
19
- @exploits_api
19
+ @exploits_api = Shodanz.api.exploits.new
20
20
  end
21
21
  end
22
22
  end
@@ -1,3 +1,3 @@
1
1
  module Shodanz
2
- VERSION = "1.0.2"
2
+ VERSION = '1.0.3'.freeze
3
3
  end
@@ -20,10 +20,10 @@ Gem::Specification.new do |spec|
20
20
  spec.require_paths = ["lib"]
21
21
 
22
22
  spec.add_dependency "unirest", "1.1.2"
23
- spec.add_dependency "json", "1.8.6"
24
- spec.add_dependency "oj", "3.3.8"
23
+ spec.add_dependency "json" # specifying version breaks things, what?
24
+ spec.add_dependency "oj", "3.5.0"
25
25
 
26
- spec.add_development_dependency "bundler", "~> 1.15"
27
- spec.add_development_dependency "rake", "~> 10.0"
28
- spec.add_development_dependency "rspec", "~> 3.0"
26
+ spec.add_development_dependency "bundler", "~> 1.16.1"
27
+ spec.add_development_dependency "rake", "~> 12.3.1"
28
+ spec.add_development_dependency "rspec", "~> 3.7.0"
29
29
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: shodanz
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kent 'picatz' Gruber
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-20 00:00:00.000000000 Z
11
+ date: 2018-03-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: unirest
@@ -28,72 +28,72 @@ dependencies:
28
28
  name: json
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.8.6
33
+ version: '0'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 1.8.6
40
+ version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: oj
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - '='
46
46
  - !ruby/object:Gem::Version
47
- version: 3.3.8
47
+ version: 3.5.0
48
48
  type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - '='
53
53
  - !ruby/object:Gem::Version
54
- version: 3.3.8
54
+ version: 3.5.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: bundler
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '1.15'
61
+ version: 1.16.1
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '1.15'
68
+ version: 1.16.1
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - "~>"
74
74
  - !ruby/object:Gem::Version
75
- version: '10.0'
75
+ version: 12.3.1
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - "~>"
81
81
  - !ruby/object:Gem::Version
82
- version: '10.0'
82
+ version: 12.3.1
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: rspec
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.0'
89
+ version: 3.7.0
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.0'
96
+ version: 3.7.0
97
97
  description: Featuring full support for the REST, Streaming and Exploits API
98
98
  email:
99
99
  - kgruber1@emich.edu
@@ -111,6 +111,7 @@ files:
111
111
  - Rakefile
112
112
  - examples/debug.rb
113
113
  - examples/top_10_countries_running.rb
114
+ - examples/top_10_countries_running_apache_chart.rb
114
115
  - lib/shodanz.rb
115
116
  - lib/shodanz/api.rb
116
117
  - lib/shodanz/apis/exploits.rb
@@ -139,7 +140,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
139
140
  version: '0'
140
141
  requirements: []
141
142
  rubyforge_project:
142
- rubygems_version: 2.6.12
143
+ rubygems_version: 2.7.3
143
144
  signing_key:
144
145
  specification_version: 4
145
146
  summary: A modern Ruby gem for Shodan, the world's first search engine for Internet-connected