mihari 5.4.6 → 5.4.8
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 +4 -4
- data/.gitignore +2 -0
- data/.rubocop.yml +2 -0
- data/docs/analyzers/index.md +5 -0
- data/docs/emitters/misp.md +1 -1
- data/docs/requirements.md +8 -15
- data/frontend/package-lock.json +258 -249
- data/frontend/package.json +12 -12
- data/lib/mihari/analyzers/base.rb +8 -1
- data/lib/mihari/analyzers/binaryedge.rb +1 -1
- data/lib/mihari/analyzers/censys.rb +1 -1
- data/lib/mihari/analyzers/feed.rb +1 -0
- data/lib/mihari/analyzers/greynoise.rb +1 -1
- data/lib/mihari/analyzers/hunterhow.rb +1 -1
- data/lib/mihari/analyzers/onyphe.rb +1 -1
- data/lib/mihari/analyzers/shodan.rb +1 -1
- data/lib/mihari/analyzers/urlscan.rb +1 -1
- data/lib/mihari/analyzers/virustotal_intelligence.rb +1 -1
- data/lib/mihari/analyzers/zoomeye.rb +1 -1
- data/lib/mihari/clients/base.rb +18 -5
- data/lib/mihari/clients/binaryedge.rb +4 -3
- data/lib/mihari/clients/censys.rb +3 -2
- data/lib/mihari/clients/greynoise.rb +3 -2
- data/lib/mihari/clients/hunterhow.rb +3 -2
- data/lib/mihari/clients/onyphe.rb +4 -2
- data/lib/mihari/clients/shodan.rb +3 -2
- data/lib/mihari/clients/urlscan.rb +3 -2
- data/lib/mihari/clients/virustotal.rb +3 -2
- data/lib/mihari/clients/zoomeye.rb +3 -2
- data/lib/mihari/config.rb +13 -0
- data/lib/mihari/database.rb +2 -2
- data/lib/mihari/emitters/webhook.rb +11 -11
- data/lib/mihari/enrichers/google_public_dns.rb +7 -1
- data/lib/mihari/enrichers/ipinfo.rb +13 -6
- data/lib/mihari/enrichers/shodan.rb +7 -1
- data/lib/mihari/errors.rb +0 -2
- data/lib/mihari/feed/reader.rb +15 -10
- data/lib/mihari/http.rb +26 -100
- data/lib/mihari/schemas/analyzer.rb +1 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/public/assets/{index-0a5a47bf.js → index-a92abd57.js} +1 -1
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +400 -400
- data/mihari.gemspec +8 -5
- data/requirements.txt +1 -1
- metadata +57 -15
data/frontend/package.json
CHANGED
@@ -17,9 +17,9 @@
|
|
17
17
|
"@fortawesome/fontawesome-svg-core": "^6.4.2",
|
18
18
|
"@fortawesome/free-solid-svg-icons": "^6.4.2",
|
19
19
|
"@fortawesome/vue-fontawesome": "^3.0.3",
|
20
|
-
"@vueuse/core": "^10.
|
21
|
-
"@vueuse/router": "^10.
|
22
|
-
"ace-builds": "^1.
|
20
|
+
"@vueuse/core": "^10.5.0",
|
21
|
+
"@vueuse/router": "^10.5.0",
|
22
|
+
"ace-builds": "^1.29.0",
|
23
23
|
"axios": "^1.5.1",
|
24
24
|
"bulma": "^0.9.4",
|
25
25
|
"bulma-helpers": "^0.4.3",
|
@@ -38,21 +38,21 @@
|
|
38
38
|
},
|
39
39
|
"devDependencies": {
|
40
40
|
"@redocly/cli": "1.2.0",
|
41
|
-
"@rushstack/eslint-patch": "^1.5.
|
41
|
+
"@rushstack/eslint-patch": "^1.5.1",
|
42
42
|
"@tsconfig/node20": "^20.1.2",
|
43
43
|
"@types/jsdom": "^21.1.3",
|
44
|
-
"@types/node": "^20.
|
44
|
+
"@types/node": "^20.8.5",
|
45
45
|
"@types/url-parse": "^1.4.9",
|
46
|
-
"@typescript-eslint/eslint-plugin": "^6.7.
|
47
|
-
"@typescript-eslint/parser": "^6.7.
|
48
|
-
"@vitejs/plugin-vue": "^4.
|
46
|
+
"@typescript-eslint/eslint-plugin": "^6.7.5",
|
47
|
+
"@typescript-eslint/parser": "^6.7.5",
|
48
|
+
"@vitejs/plugin-vue": "^4.4.0",
|
49
49
|
"@vue/eslint-config-prettier": "^8.0.0",
|
50
50
|
"@vue/eslint-config-typescript": "^12.0.0",
|
51
51
|
"@vue/test-utils": "2.4.1",
|
52
52
|
"@vue/tsconfig": "^0.4.0",
|
53
|
-
"eslint": "^8.
|
53
|
+
"eslint": "^8.51.0",
|
54
54
|
"eslint-config-prettier": "^9.0.0",
|
55
|
-
"eslint-plugin-prettier": "^5.0.
|
55
|
+
"eslint-plugin-prettier": "^5.0.1",
|
56
56
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
57
57
|
"eslint-plugin-vue": "^9.17.0",
|
58
58
|
"husky": "^8.0.3",
|
@@ -60,8 +60,8 @@
|
|
60
60
|
"npm-run-all": "^4.1.5",
|
61
61
|
"prettier": "^3.0.3",
|
62
62
|
"typescript": "~5.2.2",
|
63
|
-
"vite": "^4.4.
|
63
|
+
"vite": "^4.4.11",
|
64
64
|
"vitest": "^0.34.6",
|
65
|
-
"vue-tsc": "^1.8.
|
65
|
+
"vue-tsc": "^1.8.19"
|
66
66
|
}
|
67
67
|
}
|
@@ -61,6 +61,13 @@ module Mihari
|
|
61
61
|
Mihari.config.ignore_error
|
62
62
|
end
|
63
63
|
|
64
|
+
#
|
65
|
+
# @return [Integer, nil]
|
66
|
+
#
|
67
|
+
def timeout
|
68
|
+
options[:timeout]
|
69
|
+
end
|
70
|
+
|
64
71
|
# @return [Array<String>, Array<Mihari::Artifact>]
|
65
72
|
def artifacts
|
66
73
|
raise NotImplementedError, "You must implement #{self.class}##{__method__}"
|
@@ -97,7 +104,7 @@ module Mihari
|
|
97
104
|
self.class.to_s.split("::").last
|
98
105
|
end
|
99
106
|
|
100
|
-
|
107
|
+
alias source class_name
|
101
108
|
|
102
109
|
class << self
|
103
110
|
#
|
@@ -32,7 +32,7 @@ module Mihari
|
|
32
32
|
# @return [Mihari::Clients::BinaryEdge]
|
33
33
|
#
|
34
34
|
def client
|
35
|
-
@client ||= Clients::BinaryEdge.new(api_key: api_key, interval: interval)
|
35
|
+
@client ||= Clients::BinaryEdge.new(api_key: api_key, interval: interval, timeout: timeout)
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
@@ -52,7 +52,7 @@ module Mihari
|
|
52
52
|
# @return [Mihari::Clients::Censys]
|
53
53
|
#
|
54
54
|
def client
|
55
|
-
@client ||= Clients::Censys.new(id: id, secret: secret, interval: interval)
|
55
|
+
@client ||= Clients::Censys.new(id: id, secret: secret, interval: interval, timeout: timeout)
|
56
56
|
end
|
57
57
|
|
58
58
|
#
|
data/lib/mihari/clients/base.rb
CHANGED
@@ -12,14 +12,20 @@ module Mihari
|
|
12
12
|
# @return [Integer, nil]
|
13
13
|
attr_reader :interval
|
14
14
|
|
15
|
+
# @return [Integer, nil]
|
16
|
+
attr_reader :timeout
|
17
|
+
|
15
18
|
#
|
16
19
|
# @param [String] base_url
|
17
20
|
# @param [Hash] headers
|
21
|
+
# @param [Integer, nil] interval
|
22
|
+
# @param [Integer, nil] timeout
|
18
23
|
#
|
19
|
-
def initialize(base_url, headers: {}, interval: nil)
|
24
|
+
def initialize(base_url, headers: {}, interval: nil, timeout: nil)
|
20
25
|
@base_url = base_url
|
21
26
|
@headers = headers || {}
|
22
27
|
@interval = interval
|
28
|
+
@timeout = timeout
|
23
29
|
end
|
24
30
|
|
25
31
|
private
|
@@ -28,6 +34,13 @@ module Mihari
|
|
28
34
|
sleep(interval) if interval
|
29
35
|
end
|
30
36
|
|
37
|
+
#
|
38
|
+
# @return [::HTTP::Client]
|
39
|
+
#
|
40
|
+
def http
|
41
|
+
HTTP::Factory.build headers: headers, timeout: timeout
|
42
|
+
end
|
43
|
+
|
31
44
|
#
|
32
45
|
# @param [String] path
|
33
46
|
#
|
@@ -41,20 +54,20 @@ module Mihari
|
|
41
54
|
# @param [String] path
|
42
55
|
# @param [Hash, nil] params
|
43
56
|
#
|
44
|
-
# @return [
|
57
|
+
# @return [::HTTP::Response]
|
45
58
|
#
|
46
59
|
def get(path, params: nil)
|
47
|
-
|
60
|
+
http.get(url_for(path), params: params)
|
48
61
|
end
|
49
62
|
|
50
63
|
#
|
51
64
|
# @param [String] path
|
52
65
|
# @param [Hash, nil] json
|
53
66
|
#
|
54
|
-
# @return [
|
67
|
+
# @return [::HTTP::Response]
|
55
68
|
#
|
56
69
|
def post(path, json: {})
|
57
|
-
|
70
|
+
http.post(url_for(path), json: json)
|
58
71
|
end
|
59
72
|
end
|
60
73
|
end
|
@@ -7,14 +7,15 @@ module Mihari
|
|
7
7
|
# @param [String] base_url
|
8
8
|
# @param [String, nil] api_key
|
9
9
|
# @param [Hash] headers
|
10
|
-
# @param [Integer
|
10
|
+
# @param [Integer, nil] interval
|
11
|
+
# @param [Integer, nil] timeout
|
11
12
|
#
|
12
|
-
def initialize(base_url = "https://api.binaryedge.io/v2", api_key:, headers: {}, interval: nil)
|
13
|
+
def initialize(base_url = "https://api.binaryedge.io/v2", api_key:, headers: {}, interval: nil, timeout: nil)
|
13
14
|
raise(ArgumentError, "'api_key' argument is required") unless api_key
|
14
15
|
|
15
16
|
headers["x-key"] = api_key
|
16
17
|
|
17
|
-
super(base_url, headers: headers, interval: interval)
|
18
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
18
19
|
end
|
19
20
|
|
20
21
|
#
|
@@ -11,14 +11,15 @@ module Mihari
|
|
11
11
|
# @param [String, nil] secret
|
12
12
|
# @param [Hash] headers
|
13
13
|
# @param [Integer, nil] interval
|
14
|
+
# @param [Integer, nil] timeout
|
14
15
|
#
|
15
|
-
def initialize(base_url = "https://search.censys.io", id:, secret:, headers: {}, interval: nil)
|
16
|
+
def initialize(base_url = "https://search.censys.io", id:, secret:, headers: {}, interval: nil, timeout: nil)
|
16
17
|
raise(ArgumentError, "'id' argument is required") if id.nil?
|
17
18
|
raise(ArgumentError, "'secret' argument is required") if secret.nil?
|
18
19
|
|
19
20
|
headers["authorization"] = "Basic #{Base64.strict_encode64("#{id}:#{secret}")}"
|
20
21
|
|
21
|
-
super(base_url, headers: headers, interval: interval)
|
22
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
22
23
|
end
|
23
24
|
|
24
25
|
#
|
@@ -10,12 +10,13 @@ module Mihari
|
|
10
10
|
# @param [String, nil] api_key
|
11
11
|
# @param [Hash] headers
|
12
12
|
# @param [Integer, nil] interval
|
13
|
+
# @param [Integer, nil] timeout
|
13
14
|
#
|
14
|
-
def initialize(base_url = "https://api.greynoise.io", api_key:, headers: {}, interval: nil)
|
15
|
+
def initialize(base_url = "https://api.greynoise.io", api_key:, headers: {}, interval: nil, timeout: nil)
|
15
16
|
raise(ArgumentError, "'api_key' argument is required") unless api_key
|
16
17
|
|
17
18
|
headers["key"] = api_key
|
18
|
-
super(base_url, headers: headers, interval: interval)
|
19
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
19
20
|
end
|
20
21
|
|
21
22
|
#
|
@@ -15,11 +15,12 @@ module Mihari
|
|
15
15
|
# @param [String, nil] api_key
|
16
16
|
# @param [Hash] headers
|
17
17
|
# @param [Integer, nil] interval
|
18
|
+
# @param [Integer, nil] timeout
|
18
19
|
#
|
19
|
-
def initialize(base_url = "https://api.hunter.how/", api_key:, headers: {}, interval: nil)
|
20
|
+
def initialize(base_url = "https://api.hunter.how/", api_key:, headers: {}, interval: nil, timeout: nil)
|
20
21
|
raise(ArgumentError, "'api_key' argument is required") unless api_key
|
21
22
|
|
22
|
-
super(base_url, headers: headers, interval: interval)
|
23
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
23
24
|
|
24
25
|
@api_key = api_key
|
25
26
|
end
|
@@ -12,11 +12,13 @@ module Mihari
|
|
12
12
|
# @param [String] base_url
|
13
13
|
# @param [String, nil] api_key
|
14
14
|
# @param [Hash] headers
|
15
|
+
# @param [Integer, nil] interval
|
16
|
+
# @param [Integer, nil] timeout
|
15
17
|
#
|
16
|
-
def initialize(base_url = "https://www.onyphe.io", api_key:, headers: {}, interval: nil)
|
18
|
+
def initialize(base_url = "https://www.onyphe.io", api_key:, headers: {}, interval: nil, timeout: nil)
|
17
19
|
raise(ArgumentError, "'api_key' argument is required") if api_key.nil?
|
18
20
|
|
19
|
-
super(base_url, headers: headers, interval: interval)
|
21
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
20
22
|
|
21
23
|
@api_key = api_key
|
22
24
|
end
|
@@ -13,11 +13,12 @@ module Mihari
|
|
13
13
|
# @param [String, nil] api_key
|
14
14
|
# @param [Hash] headers
|
15
15
|
# @param [Integer, nil] interval
|
16
|
+
# @param [Integer, nil] timeout
|
16
17
|
#
|
17
|
-
def initialize(base_url = "https://api.shodan.io", api_key:, headers: {}, interval: nil)
|
18
|
+
def initialize(base_url = "https://api.shodan.io", api_key:, headers: {}, interval: nil, timeout: nil)
|
18
19
|
raise(ArgumentError, "'api_key' argument is required") unless api_key
|
19
20
|
|
20
|
-
super(base_url, headers: headers, interval: interval)
|
21
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
21
22
|
|
22
23
|
@api_key = api_key
|
23
24
|
end
|
@@ -8,13 +8,14 @@ module Mihari
|
|
8
8
|
# @param [String, nil] api_key
|
9
9
|
# @param [Hash] headers
|
10
10
|
# @param [Interval, nil] interval
|
11
|
+
# @param [Interval, nil] timeout
|
11
12
|
#
|
12
|
-
def initialize(base_url = "https://urlscan.io", api_key:, headers: {}, interval: nil)
|
13
|
+
def initialize(base_url = "https://urlscan.io", api_key:, headers: {}, interval: nil, timeout: nil)
|
13
14
|
raise(ArgumentError, "'api_key' argument is required") if api_key.nil?
|
14
15
|
|
15
16
|
headers["api-key"] = api_key
|
16
17
|
|
17
|
-
super(base_url, headers: headers, interval: interval)
|
18
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
18
19
|
end
|
19
20
|
|
20
21
|
#
|
@@ -8,13 +8,14 @@ module Mihari
|
|
8
8
|
# @param [String, nil] api_key
|
9
9
|
# @param [Hash] headers
|
10
10
|
# @param [Integer, nil] interval
|
11
|
+
# @param [Integer, nil] timeout
|
11
12
|
#
|
12
|
-
def initialize(base_url = "https://www.virustotal.com", api_key:, headers: {}, interval: nil)
|
13
|
+
def initialize(base_url = "https://www.virustotal.com", api_key:, headers: {}, interval: nil, timeout: nil)
|
13
14
|
raise(ArgumentError, "'api_key' argument is required") if api_key.nil?
|
14
15
|
|
15
16
|
headers["x-apikey"] = api_key
|
16
17
|
|
17
|
-
super(base_url, headers: headers, interval: interval)
|
18
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
18
19
|
end
|
19
20
|
|
20
21
|
#
|
@@ -12,12 +12,13 @@ module Mihari
|
|
12
12
|
# @param [String, nil] api_key
|
13
13
|
# @param [Hash] headers
|
14
14
|
# @param [Integer, nil] interval
|
15
|
+
# @param [Integer, nil] timeout
|
15
16
|
#
|
16
|
-
def initialize(base_url = "https://api.zoomeye.org", api_key:, headers: {}, interval: nil)
|
17
|
+
def initialize(base_url = "https://api.zoomeye.org", api_key:, headers: {}, interval: nil, timeout: nil)
|
17
18
|
raise(ArgumentError, "'api_key' argument is required") unless api_key
|
18
19
|
|
19
20
|
headers["api-key"] = api_key
|
20
|
-
super(base_url, headers: headers, interval: interval)
|
21
|
+
super(base_url, headers: headers, interval: interval, timeout: timeout)
|
21
22
|
end
|
22
23
|
|
23
24
|
#
|
data/lib/mihari/config.rb
CHANGED
@@ -97,6 +97,10 @@ module Mihari
|
|
97
97
|
attr_reader :ignore_error
|
98
98
|
|
99
99
|
def initialize
|
100
|
+
load
|
101
|
+
end
|
102
|
+
|
103
|
+
def load
|
100
104
|
@binaryedge_api_key = ENV.fetch("BINARYEDGE_API_KEY", nil)
|
101
105
|
|
102
106
|
@censys_id = ENV.fetch("CENSYS_ID", nil)
|
@@ -153,5 +157,14 @@ module Mihari
|
|
153
157
|
|
154
158
|
@ignore_error = ENV.fetch("IGNORE_ERROR", false)
|
155
159
|
end
|
160
|
+
|
161
|
+
#
|
162
|
+
# @return [Array<String>]
|
163
|
+
#
|
164
|
+
def keys
|
165
|
+
instance_variables.map do |key|
|
166
|
+
key[1..].to_s.upcase
|
167
|
+
end
|
168
|
+
end
|
156
169
|
end
|
157
170
|
end
|
data/lib/mihari/database.rb
CHANGED
@@ -13,7 +13,7 @@ def development_env?
|
|
13
13
|
env == "development"
|
14
14
|
end
|
15
15
|
|
16
|
-
class V5Schema < ActiveRecord::Migration[7.
|
16
|
+
class V5Schema < ActiveRecord::Migration[7.1]
|
17
17
|
def change
|
18
18
|
create_table :rules, id: :string, if_not_exists: true do |t|
|
19
19
|
t.string :title, null: false
|
@@ -162,7 +162,7 @@ module Mihari
|
|
162
162
|
def close
|
163
163
|
return unless ActiveRecord::Base.connected?
|
164
164
|
|
165
|
-
ActiveRecord::Base.clear_active_connections!
|
165
|
+
ActiveRecord::Base.connection_handler.clear_active_connections!
|
166
166
|
end
|
167
167
|
|
168
168
|
def with_db_connection
|
@@ -72,17 +72,13 @@ module Mihari
|
|
72
72
|
def emit
|
73
73
|
return if artifacts.empty?
|
74
74
|
|
75
|
-
|
76
|
-
|
77
|
-
res = nil
|
75
|
+
# returns body to prevent Parallel issue (Parallel fails to handle HTTP:Response object)
|
78
76
|
case method
|
79
77
|
when "GET"
|
80
|
-
|
78
|
+
http.get(url).body.to_s
|
81
79
|
when "POST"
|
82
|
-
|
80
|
+
http.post(url, json: json).body.to_s
|
83
81
|
end
|
84
|
-
|
85
|
-
res
|
86
82
|
end
|
87
83
|
|
88
84
|
def valid?
|
@@ -93,12 +89,16 @@ module Mihari
|
|
93
89
|
|
94
90
|
private
|
95
91
|
|
92
|
+
def http
|
93
|
+
HTTP::Factory.build headers: headers
|
94
|
+
end
|
95
|
+
|
96
96
|
#
|
97
|
-
#
|
97
|
+
# Render template
|
98
98
|
#
|
99
99
|
# @return [String]
|
100
100
|
#
|
101
|
-
def
|
101
|
+
def rendered_template
|
102
102
|
[].tap do |out|
|
103
103
|
options = {}
|
104
104
|
options[:template] = File.read(template) unless template.nil?
|
@@ -115,8 +115,8 @@ module Mihari
|
|
115
115
|
#
|
116
116
|
# @return [Hash]
|
117
117
|
#
|
118
|
-
def
|
119
|
-
JSON.parse
|
118
|
+
def json
|
119
|
+
JSON.parse rendered_template
|
120
120
|
end
|
121
121
|
end
|
122
122
|
end
|
@@ -37,7 +37,7 @@ module Mihari
|
|
37
37
|
def query_by_type(name, resource_type)
|
38
38
|
url = "https://dns.google/resolve"
|
39
39
|
params = { name: name, type: resource_type }
|
40
|
-
res =
|
40
|
+
res = http.get(url, params: params)
|
41
41
|
|
42
42
|
data = JSON.parse(res.body.to_s)
|
43
43
|
|
@@ -45,6 +45,12 @@ module Mihari
|
|
45
45
|
rescue HTTPError
|
46
46
|
nil
|
47
47
|
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def http
|
52
|
+
HTTP::Factory.build
|
53
|
+
end
|
48
54
|
end
|
49
55
|
end
|
50
56
|
end
|
@@ -28,18 +28,25 @@ module Mihari
|
|
28
28
|
# @return [Mihari::Structs::IPInfo::Response, nil]
|
29
29
|
#
|
30
30
|
def query(ip)
|
31
|
-
headers = {}
|
32
|
-
|
33
|
-
token = Mihari.config.ipinfo_api_key
|
34
|
-
headers[:authorization] = "Bearer #{token}" unless token.nil?
|
35
|
-
|
36
31
|
url = "https://ipinfo.io/#{ip}/json"
|
37
|
-
res =
|
32
|
+
res = http.get(url)
|
38
33
|
data = JSON.parse(res.body.to_s)
|
39
34
|
|
40
35
|
Structs::IPInfo::Response.from_dynamic! data
|
41
36
|
end
|
42
37
|
memoize :query
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def headers
|
42
|
+
token = Mihari.config.ipinfo_api_key
|
43
|
+
authorization = token.nil? ? nil : "Bearer #{token}"
|
44
|
+
{ authorization: authorization }.compact
|
45
|
+
end
|
46
|
+
|
47
|
+
def http
|
48
|
+
HTTP::Factory.build headers: headers
|
49
|
+
end
|
43
50
|
end
|
44
51
|
end
|
45
52
|
end
|
@@ -23,12 +23,18 @@ module Mihari
|
|
23
23
|
#
|
24
24
|
def query(ip)
|
25
25
|
url = "https://internetdb.shodan.io/#{ip}"
|
26
|
-
res =
|
26
|
+
res = http.get(url)
|
27
27
|
data = JSON.parse(res.body.to_s)
|
28
28
|
|
29
29
|
Structs::Shodan::InternetDBResponse.from_dynamic! data
|
30
30
|
end
|
31
31
|
memoize :query
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def http
|
36
|
+
HTTP::Factory.build
|
37
|
+
end
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
data/lib/mihari/errors.rb
CHANGED
data/lib/mihari/feed/reader.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "csv"
|
4
|
-
require "insensitive_hash"
|
5
4
|
|
6
5
|
module Mihari
|
7
6
|
module Feed
|
@@ -24,16 +23,18 @@ module Mihari
|
|
24
23
|
# @return [String]
|
25
24
|
attr_reader :method
|
26
25
|
|
27
|
-
|
26
|
+
# @return [Integer, nil]
|
27
|
+
attr_reader :timeout
|
28
|
+
|
29
|
+
def initialize(url, headers: {}, method: "GET", params: nil, json: nil, data: nil, timeout: nil)
|
28
30
|
@url = Addressable::URI.parse(url)
|
29
|
-
@headers = headers
|
31
|
+
@headers = headers
|
30
32
|
@method = method
|
33
|
+
@timeout = timeout
|
31
34
|
|
32
35
|
@params = params
|
33
36
|
@json = json
|
34
37
|
@data = data
|
35
|
-
|
36
|
-
headers["content-type"] = "application/json" unless json.nil?
|
37
38
|
end
|
38
39
|
|
39
40
|
#
|
@@ -43,14 +44,12 @@ module Mihari
|
|
43
44
|
return read_file(url.path) if url.scheme == "file"
|
44
45
|
|
45
46
|
res = nil
|
46
|
-
|
47
|
-
|
48
|
-
res = client.get(params: params) if method == "GET"
|
49
|
-
res = client.post(params: params, json: json, data: data) if method == "POST"
|
47
|
+
res = http.get(url, params: params) if method == "GET"
|
48
|
+
res = http.post(url, params: params, json: json, form: data) if method == "POST"
|
50
49
|
|
51
50
|
return [] if res.nil?
|
52
51
|
|
53
|
-
body = res.body
|
52
|
+
body = res.body.to_s
|
54
53
|
content_type = res["Content-Type"].to_s
|
55
54
|
return convert_as_json(body) if content_type.include?("application/json")
|
56
55
|
|
@@ -98,6 +97,12 @@ module Mihari
|
|
98
97
|
|
99
98
|
convert_as_csv text
|
100
99
|
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def http
|
104
|
+
HTTP::Factory.build headers: headers, timeout: timeout
|
105
|
+
end
|
101
106
|
end
|
102
107
|
end
|
103
108
|
end
|