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 +5 -5
- data/README.md +2 -3
- data/examples/debug.rb +5 -3
- data/examples/top_10_countries_running_apache_chart.rb +28 -0
- data/lib/shodanz.rb +10 -5
- data/lib/shodanz/api.rb +16 -14
- data/lib/shodanz/apis/exploits.rb +25 -22
- data/lib/shodanz/apis/rest.rb +30 -21
- data/lib/shodanz/client.rb +13 -13
- data/lib/shodanz/version.rb +1 -1
- data/shodanz.gemspec +5 -5
- metadata +16 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: e5da697873b94e412d3732b7a6ed529f83b9aa70bc2e14ae4b9a3ac8738659d4
|
|
4
|
+
data.tar.gz: f6636ec96aa077123f9e312e14259e1ddfadf6709225bc7c9b3b64b06c0ef611
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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("
|
|
58
|
-
client.rest_api.host_count("
|
|
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
|
data/examples/debug.rb
CHANGED
|
@@ -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
|
data/lib/shodanz.rb
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
require
|
|
2
|
-
require
|
|
3
|
-
require
|
|
4
|
-
require
|
|
5
|
-
require
|
|
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
|
data/lib/shodanz/api.rb
CHANGED
|
@@ -1,29 +1,31 @@
|
|
|
1
|
-
require_relative
|
|
2
|
-
require_relative
|
|
3
|
-
require_relative
|
|
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 =
|
|
16
|
+
URL = 'https://exploits.shodan.io/api/'.freeze
|
|
17
17
|
|
|
18
|
-
# @param key [String] SHODAN API key, defaulted to
|
|
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
|
|
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
|
|
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 =
|
|
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(
|
|
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 =
|
|
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(
|
|
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
|
-
|
|
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,
|
|
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,
|
|
74
|
+
params.select { |key, _| key == :query }
|
|
70
75
|
end
|
|
71
76
|
|
|
72
77
|
def turn_into_facets(facets)
|
|
73
|
-
filters = facets.reject { |key,
|
|
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,
|
|
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
|
data/lib/shodanz/apis/rest.rb
CHANGED
|
@@ -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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
150
|
+
get('dns/resolve', hostnames: hostnames.join(","))
|
|
150
151
|
end
|
|
151
152
|
|
|
152
|
-
# Look up the hostnames that have been defined for the
|
|
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(
|
|
156
|
+
get('dns/reverse', ips: ips.join(","))
|
|
155
157
|
end
|
|
156
158
|
|
|
157
|
-
# Shows the HTTP headers that your client sends when
|
|
159
|
+
# Shows the HTTP headers that your client sends when
|
|
160
|
+
# connecting to a webserver.
|
|
158
161
|
def http_headers
|
|
159
|
-
get(
|
|
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(
|
|
167
|
+
get('tools/myip')
|
|
165
168
|
end
|
|
166
169
|
|
|
167
|
-
# Calculates a honeypot probability score ranging
|
|
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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
209
|
+
params.select { |key, _| key == :query }
|
|
199
210
|
end
|
|
200
211
|
|
|
201
212
|
def turn_into_facets(facets)
|
|
202
|
-
filters = facets.reject { |key,
|
|
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,
|
|
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
|
data/lib/shodanz/client.rb
CHANGED
|
@@ -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
|
data/lib/shodanz/version.rb
CHANGED
data/shodanz.gemspec
CHANGED
|
@@ -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",
|
|
24
|
-
spec.add_dependency "oj", "3.
|
|
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.
|
|
27
|
-
spec.add_development_dependency "rake", "~>
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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.
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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.
|
|
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
|