mihari 1.3.2 → 2.0.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 +4 -4
- data/.github/workflows/test.yml +68 -0
- data/README.md +20 -270
- data/Rakefile +1 -0
- data/build_frontend.sh +14 -0
- data/docker/Dockerfile +3 -2
- data/{screenshots → images}/alert.png +0 -0
- data/{screenshots → images}/eyecatch.png +0 -0
- data/images/logo.png +0 -0
- data/{screenshots → images}/misp.png +0 -0
- data/{screenshots → images}/slack.png +0 -0
- data/images/web_alerts.png +0 -0
- data/images/web_config.png +0 -0
- data/lib/mihari.rb +2 -2
- data/lib/mihari/analyzers/base.rb +1 -1
- data/lib/mihari/analyzers/basic.rb +3 -4
- data/lib/mihari/analyzers/binaryedge.rb +4 -7
- data/lib/mihari/analyzers/censys.rb +3 -7
- data/lib/mihari/analyzers/circl.rb +3 -5
- data/lib/mihari/analyzers/crtsh.rb +2 -6
- data/lib/mihari/analyzers/dnpedia.rb +3 -6
- data/lib/mihari/analyzers/dnstwister.rb +4 -9
- data/lib/mihari/analyzers/free_text.rb +2 -6
- data/lib/mihari/analyzers/http_hash.rb +3 -11
- data/lib/mihari/analyzers/onyphe.rb +3 -6
- data/lib/mihari/analyzers/otx.rb +4 -9
- data/lib/mihari/analyzers/passive_dns.rb +4 -9
- data/lib/mihari/analyzers/passive_ssl.rb +4 -9
- data/lib/mihari/analyzers/passivetotal.rb +9 -14
- data/lib/mihari/analyzers/pulsedive.rb +7 -12
- data/lib/mihari/analyzers/reverse_whois.rb +4 -9
- data/lib/mihari/analyzers/securitytrails.rb +12 -17
- data/lib/mihari/analyzers/securitytrails_domain_feed.rb +3 -7
- data/lib/mihari/analyzers/shodan.rb +9 -8
- data/lib/mihari/analyzers/spyse.rb +6 -11
- data/lib/mihari/analyzers/ssh_fingerprint.rb +2 -6
- data/lib/mihari/analyzers/urlscan.rb +21 -9
- data/lib/mihari/analyzers/virustotal.rb +6 -11
- data/lib/mihari/analyzers/zoomeye.rb +7 -11
- data/lib/mihari/cli.rb +20 -28
- data/lib/mihari/config.rb +1 -25
- data/lib/mihari/configurable.rb +4 -5
- data/lib/mihari/database.rb +7 -1
- data/lib/mihari/emitters/misp.rb +4 -2
- data/lib/mihari/emitters/slack.rb +18 -7
- data/lib/mihari/emitters/the_hive.rb +2 -2
- data/lib/mihari/errors.rb +2 -0
- data/lib/mihari/models/alert.rb +51 -0
- data/lib/mihari/models/artifact.rb +1 -1
- data/lib/mihari/notifiers/exception_notifier.rb +5 -5
- data/lib/mihari/serializers/alert.rb +1 -1
- data/lib/mihari/serializers/artifact.rb +1 -1
- data/lib/mihari/serializers/tag.rb +1 -1
- data/lib/mihari/status.rb +10 -10
- data/lib/mihari/type_checker.rb +4 -4
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +126 -0
- data/lib/mihari/web/public/index.html +21 -0
- data/lib/mihari/web/public/static/favicon.ico +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.099a9556.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.30cc681d.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.3b89dd10.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-brands-400.f7307680.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.1f77739c.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.7124eb50.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.7630483d.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-regular-400.f0f82301.woff2 +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.1042e8ca.eot +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.605ed792.ttf +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.9fe5a17c.woff +0 -0
- data/lib/mihari/web/public/static/fonts/fa-solid-900.e8a427e1.woff2 +0 -0
- data/lib/mihari/web/public/static/img/fa-brands-400.ba7ed552.svg +3717 -0
- data/lib/mihari/web/public/static/img/fa-regular-400.0bb42845.svg +801 -0
- data/lib/mihari/web/public/static/img/fa-solid-900.376c1f97.svg +5034 -0
- data/lib/mihari/web/public/static/js/app.58b32d15.js +12 -0
- data/lib/mihari/web/public/static/js/app.58b32d15.js.map +1 -0
- data/mihari.gemspec +30 -25
- metadata +163 -56
- data/.travis.yml +0 -13
- data/lib/mihari/alert_viewer.rb +0 -23
File without changes
|
File without changes
|
Binary file
|
Binary file
|
data/lib/mihari.rb
CHANGED
@@ -42,7 +42,7 @@ module Mihari
|
|
42
42
|
|
43
43
|
def run_emitter(emitter)
|
44
44
|
emitter.run(title: title, description: description, artifacts: unique_artifacts, source: source, tags: tags)
|
45
|
-
rescue
|
45
|
+
rescue => e
|
46
46
|
puts "Emission by #{emitter.class} is failed: #{e}"
|
47
47
|
end
|
48
48
|
|
@@ -4,12 +4,11 @@ module Mihari
|
|
4
4
|
module Analyzers
|
5
5
|
class Basic < Base
|
6
6
|
attr_accessor :title
|
7
|
-
attr_reader :description
|
8
|
-
attr_reader :artifacts
|
9
|
-
attr_reader :source
|
10
|
-
attr_reader :tags
|
7
|
+
attr_reader :description, :artifacts, :source, :tags
|
11
8
|
|
12
9
|
def initialize(title:, description:, artifacts:, source:, tags: [])
|
10
|
+
super()
|
11
|
+
|
13
12
|
@title = title
|
14
13
|
@description = description
|
15
14
|
@artifacts = artifacts
|
@@ -5,10 +5,7 @@ require "binaryedge"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class BinaryEdge < Base
|
8
|
-
attr_reader :title
|
9
|
-
attr_reader :description
|
10
|
-
attr_reader :query
|
11
|
-
attr_reader :tags
|
8
|
+
attr_reader :title, :description, :query, :tags
|
12
9
|
|
13
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
14
11
|
super()
|
@@ -24,7 +21,7 @@ module Mihari
|
|
24
21
|
return [] unless results || results.empty?
|
25
22
|
|
26
23
|
results.map do |result|
|
27
|
-
events = result
|
24
|
+
events = result["events"] || []
|
28
25
|
events.map do |event|
|
29
26
|
event.dig "target", "ip"
|
30
27
|
end.compact
|
@@ -47,7 +44,7 @@ module Mihari
|
|
47
44
|
responses = []
|
48
45
|
(1..Float::INFINITY).each do |page|
|
49
46
|
res = search_with_page(query, page: page)
|
50
|
-
total = res
|
47
|
+
total = res["total"].to_i
|
51
48
|
|
52
49
|
responses << res
|
53
50
|
break if total <= page * PAGE_SIZE
|
@@ -56,7 +53,7 @@ module Mihari
|
|
56
53
|
end
|
57
54
|
|
58
55
|
def config_keys
|
59
|
-
%w
|
56
|
+
%w[binaryedge_api_key]
|
60
57
|
end
|
61
58
|
|
62
59
|
def api
|
@@ -5,11 +5,7 @@ require "censu"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class Censys < Base
|
8
|
-
attr_reader :title
|
9
|
-
attr_reader :description
|
10
|
-
attr_reader :query
|
11
|
-
attr_reader :tags
|
12
|
-
attr_reader :type
|
8
|
+
attr_reader :title, :description, :query, :tags, :type
|
13
9
|
|
14
10
|
def initialize(query, title: nil, description: nil, tags: [], type: "ipv4")
|
15
11
|
super()
|
@@ -37,7 +33,7 @@ module Mihari
|
|
37
33
|
private
|
38
34
|
|
39
35
|
def valid_type?
|
40
|
-
%w
|
36
|
+
%w[ipv4 websites certificates].include? type
|
41
37
|
end
|
42
38
|
|
43
39
|
def normalize(domain)
|
@@ -86,7 +82,7 @@ module Mihari
|
|
86
82
|
end
|
87
83
|
|
88
84
|
def config_keys
|
89
|
-
%w
|
85
|
+
%w[censys_id censys_secret]
|
90
86
|
end
|
91
87
|
|
92
88
|
def api
|
@@ -5,9 +5,7 @@ require "passive_circl"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class CIRCL < Base
|
8
|
-
attr_reader :title
|
9
|
-
attr_reader :description
|
10
|
-
attr_reader :tags
|
8
|
+
attr_reader :title, :description, :tags
|
11
9
|
|
12
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
13
11
|
super()
|
@@ -27,7 +25,7 @@ module Mihari
|
|
27
25
|
private
|
28
26
|
|
29
27
|
def config_keys
|
30
|
-
%w
|
28
|
+
%w[circl_passive_password circl_passive_username]
|
31
29
|
end
|
32
30
|
|
33
31
|
def api
|
@@ -41,7 +39,7 @@ module Mihari
|
|
41
39
|
when "hash"
|
42
40
|
passive_ssl_lookup
|
43
41
|
else
|
44
|
-
raise InvalidInputError, "#{@query}(type: #{@type ||
|
42
|
+
raise InvalidInputError, "#{@query}(type: #{@type || "unknown"}) is not supported."
|
45
43
|
end
|
46
44
|
end
|
47
45
|
|
@@ -5,11 +5,7 @@ require "crtsh"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class Crtsh < Base
|
8
|
-
attr_reader :title
|
9
|
-
attr_reader :description
|
10
|
-
attr_reader :query
|
11
|
-
attr_reader :tags
|
12
|
-
attr_reader :exclude_expired
|
8
|
+
attr_reader :title, :description, :query, :tags, :exclude_expired
|
13
9
|
|
14
10
|
def initialize(query, title: nil, description: nil, tags: [], exclude_expired: nil)
|
15
11
|
super()
|
@@ -24,7 +20,7 @@ module Mihari
|
|
24
20
|
|
25
21
|
def artifacts
|
26
22
|
results = search
|
27
|
-
name_values = results.map { |result| result
|
23
|
+
name_values = results.map { |result| result["name_value"] }.compact
|
28
24
|
name_values.map(&:lines).flatten.uniq.map(&:chomp)
|
29
25
|
end
|
30
26
|
|
@@ -5,10 +5,7 @@ require "dnpedia"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class DNPedia < Base
|
8
|
-
attr_reader :query
|
9
|
-
attr_reader :title
|
10
|
-
attr_reader :description
|
11
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :title, :description, :tags
|
12
9
|
|
13
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
14
11
|
super()
|
@@ -31,9 +28,9 @@ module Mihari
|
|
31
28
|
|
32
29
|
def lookup
|
33
30
|
res = api.search(query)
|
34
|
-
rows = res
|
31
|
+
rows = res["rows"] || []
|
35
32
|
rows.map do |row|
|
36
|
-
[row
|
33
|
+
[row["name"], row["zoneid"]].join(".")
|
37
34
|
end
|
38
35
|
end
|
39
36
|
end
|
@@ -7,12 +7,7 @@ require "parallel"
|
|
7
7
|
module Mihari
|
8
8
|
module Analyzers
|
9
9
|
class DNSTwister < Base
|
10
|
-
attr_reader :query
|
11
|
-
attr_reader :type
|
12
|
-
|
13
|
-
attr_reader :title
|
14
|
-
attr_reader :description
|
15
|
-
attr_reader :tags
|
10
|
+
attr_reader :query, :type, :title, :description, :tags
|
16
11
|
|
17
12
|
def initialize(query, title: nil, description: nil, tags: [])
|
18
13
|
super()
|
@@ -47,11 +42,11 @@ module Mihari
|
|
47
42
|
end
|
48
43
|
|
49
44
|
def lookup
|
50
|
-
raise InvalidInputError, "#{query}(type: #{type ||
|
45
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
51
46
|
|
52
47
|
res = api.fuzz(query)
|
53
|
-
fuzzy_domains = res
|
54
|
-
domains = fuzzy_domains.map { |domain| domain
|
48
|
+
fuzzy_domains = res["fuzzy_domains"] || []
|
49
|
+
domains = fuzzy_domains.map { |domain| domain["domain"] }
|
55
50
|
Parallel.map(domains) do |domain|
|
56
51
|
resolvable?(domain) ? domain : nil
|
57
52
|
end.compact
|
@@ -5,15 +5,11 @@ require "parallel"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class FreeText < Base
|
8
|
-
attr_reader :query
|
9
|
-
|
10
|
-
attr_reader :title
|
11
|
-
attr_reader :description
|
12
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :title, :description, :tags
|
13
9
|
|
14
10
|
ANALYZERS = [
|
15
11
|
Mihari::Analyzers::BinaryEdge,
|
16
|
-
Mihari::Analyzers::Censys
|
12
|
+
Mihari::Analyzers::Censys
|
17
13
|
].freeze
|
18
14
|
|
19
15
|
def initialize(query, title: nil, description: nil, tags: [])
|
@@ -5,15 +5,7 @@ require "parallel"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class HTTPHash < Base
|
8
|
-
attr_reader :md5
|
9
|
-
attr_reader :sha256
|
10
|
-
attr_reader :mmh3
|
11
|
-
|
12
|
-
attr_reader :html
|
13
|
-
|
14
|
-
attr_reader :title
|
15
|
-
attr_reader :description
|
16
|
-
attr_reader :tags
|
8
|
+
attr_reader :md5, :sha256, :mmh3, :html, :title, :description, :tags
|
17
9
|
|
18
10
|
def initialize(_query, md5: nil, sha256: nil, mmh3: nil, html: nil, title: nil, description: nil, tags: [])
|
19
11
|
super()
|
@@ -57,7 +49,7 @@ module Mihari
|
|
57
49
|
[
|
58
50
|
md5 ? "md5:#{md5}" : nil,
|
59
51
|
sha256 ? "sha256:#{sha256}" : nil,
|
60
|
-
mmh3 ? "mmh3:#{mmh3}" : nil
|
52
|
+
mmh3 ? "mmh3:#{mmh3}" : nil
|
61
53
|
].compact.join(",")
|
62
54
|
end
|
63
55
|
|
@@ -92,7 +84,7 @@ module Mihari
|
|
92
84
|
binary_edge,
|
93
85
|
censys,
|
94
86
|
onyphe,
|
95
|
-
shodan
|
87
|
+
shodan
|
96
88
|
].compact
|
97
89
|
end
|
98
90
|
|
@@ -5,10 +5,7 @@ require "onyphe"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class Onyphe < Base
|
8
|
-
attr_reader :title
|
9
|
-
attr_reader :description
|
10
|
-
attr_reader :query
|
11
|
-
attr_reader :tags
|
8
|
+
attr_reader :title, :description, :query, :tags
|
12
9
|
|
13
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
14
11
|
super()
|
@@ -35,7 +32,7 @@ module Mihari
|
|
35
32
|
PAGE_SIZE = 10
|
36
33
|
|
37
34
|
def config_keys
|
38
|
-
%w
|
35
|
+
%w[onyphe_api_key]
|
39
36
|
end
|
40
37
|
|
41
38
|
def api
|
@@ -51,7 +48,7 @@ module Mihari
|
|
51
48
|
(1..Float::INFINITY).each do |page|
|
52
49
|
res = search_with_page(query, page: page)
|
53
50
|
responses << res
|
54
|
-
total = res
|
51
|
+
total = res["total"].to_i
|
55
52
|
break if total <= page * PAGE_SIZE
|
56
53
|
end
|
57
54
|
responses
|
data/lib/mihari/analyzers/otx.rb
CHANGED
@@ -5,12 +5,7 @@ require "otx_ruby"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class OTX < Base
|
8
|
-
attr_reader :query
|
9
|
-
attr_reader :type
|
10
|
-
|
11
|
-
attr_reader :title
|
12
|
-
attr_reader :description
|
13
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :type, :title, :description, :tags
|
14
9
|
|
15
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
16
11
|
super()
|
@@ -30,7 +25,7 @@ module Mihari
|
|
30
25
|
private
|
31
26
|
|
32
27
|
def config_keys
|
33
|
-
%w
|
28
|
+
%w[otx_api_key]
|
34
29
|
end
|
35
30
|
|
36
31
|
def domain_client
|
@@ -42,7 +37,7 @@ module Mihari
|
|
42
37
|
end
|
43
38
|
|
44
39
|
def valid_type?
|
45
|
-
%w
|
40
|
+
%w[ip domain].include? type
|
46
41
|
end
|
47
42
|
|
48
43
|
def lookup
|
@@ -52,7 +47,7 @@ module Mihari
|
|
52
47
|
when "ip"
|
53
48
|
ip_lookup
|
54
49
|
else
|
55
|
-
raise InvalidInputError, "#{query}(type: #{type ||
|
50
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
@@ -5,12 +5,7 @@ require "parallel"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class PassiveDNS < Base
|
8
|
-
attr_reader :query
|
9
|
-
attr_reader :type
|
10
|
-
|
11
|
-
attr_reader :title
|
12
|
-
attr_reader :description
|
13
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :type, :title, :description, :tags
|
14
9
|
|
15
10
|
ANALYZERS = [
|
16
11
|
Mihari::Analyzers::CIRCL,
|
@@ -18,7 +13,7 @@ module Mihari
|
|
18
13
|
Mihari::Analyzers::PassiveTotal,
|
19
14
|
Mihari::Analyzers::Pulsedive,
|
20
15
|
Mihari::Analyzers::SecurityTrails,
|
21
|
-
Mihari::Analyzers::VirusTotal
|
16
|
+
Mihari::Analyzers::VirusTotal
|
22
17
|
].freeze
|
23
18
|
|
24
19
|
def initialize(query, title: nil, description: nil, tags: [])
|
@@ -41,11 +36,11 @@ module Mihari
|
|
41
36
|
private
|
42
37
|
|
43
38
|
def valid_type?
|
44
|
-
%w
|
39
|
+
%w[ip domain].include? type
|
45
40
|
end
|
46
41
|
|
47
42
|
def analyzers
|
48
|
-
raise InvalidInputError, "#{query}(type: #{type ||
|
43
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
49
44
|
|
50
45
|
ANALYZERS.map do |klass|
|
51
46
|
klass.new(query)
|
@@ -5,16 +5,11 @@ require "parallel"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class PassiveSSL < Base
|
8
|
-
attr_reader :query
|
9
|
-
attr_reader :type
|
10
|
-
|
11
|
-
attr_reader :title
|
12
|
-
attr_reader :description
|
13
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :type, :title, :description, :tags
|
14
9
|
|
15
10
|
ANALYZERS = [
|
16
11
|
Mihari::Analyzers::CIRCL,
|
17
|
-
Mihari::Analyzers::PassiveTotal
|
12
|
+
Mihari::Analyzers::PassiveTotal
|
18
13
|
].freeze
|
19
14
|
|
20
15
|
def initialize(query, title: nil, description: nil, tags: [])
|
@@ -37,11 +32,11 @@ module Mihari
|
|
37
32
|
private
|
38
33
|
|
39
34
|
def valid_type?
|
40
|
-
%w
|
35
|
+
%w[sha1].include? type
|
41
36
|
end
|
42
37
|
|
43
38
|
def analyzers
|
44
|
-
raise InvalidInputError, "#{query}(type: #{type ||
|
39
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
45
40
|
|
46
41
|
ANALYZERS.map do |klass|
|
47
42
|
klass.new(query)
|
@@ -5,12 +5,7 @@ require "passivetotal"
|
|
5
5
|
module Mihari
|
6
6
|
module Analyzers
|
7
7
|
class PassiveTotal < Base
|
8
|
-
attr_reader :query
|
9
|
-
attr_reader :type
|
10
|
-
|
11
|
-
attr_reader :title
|
12
|
-
attr_reader :description
|
13
|
-
attr_reader :tags
|
8
|
+
attr_reader :query, :type, :title, :description, :tags
|
14
9
|
|
15
10
|
def initialize(query, title: nil, description: nil, tags: [])
|
16
11
|
super()
|
@@ -30,7 +25,7 @@ module Mihari
|
|
30
25
|
private
|
31
26
|
|
32
27
|
def config_keys
|
33
|
-
%w
|
28
|
+
%w[passivetotal_username passivetotal_api_key]
|
34
29
|
end
|
35
30
|
|
36
31
|
def api
|
@@ -38,7 +33,7 @@ module Mihari
|
|
38
33
|
end
|
39
34
|
|
40
35
|
def valid_type?
|
41
|
-
%w
|
36
|
+
%w[ip domain mail].include? type
|
42
37
|
end
|
43
38
|
|
44
39
|
def lookup
|
@@ -52,28 +47,28 @@ module Mihari
|
|
52
47
|
when "hash"
|
53
48
|
ssl_lookup
|
54
49
|
else
|
55
|
-
raise InvalidInputError, "#{query}(type: #{type ||
|
50
|
+
raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
56
51
|
end
|
57
52
|
end
|
58
53
|
|
59
54
|
def passive_dns_lookup
|
60
55
|
res = api.dns.passive_unique(query)
|
61
|
-
res
|
56
|
+
res["results"] || []
|
62
57
|
end
|
63
58
|
|
64
59
|
def reverse_whois_lookup
|
65
60
|
res = api.whois.search(query: query, field: "email")
|
66
|
-
results = res
|
61
|
+
results = res["results"] || []
|
67
62
|
results.map do |result|
|
68
|
-
result
|
63
|
+
result["domain"]
|
69
64
|
end.flatten.compact.uniq
|
70
65
|
end
|
71
66
|
|
72
67
|
def ssl_lookup
|
73
68
|
res = api.ssl.history(query)
|
74
|
-
results = res
|
69
|
+
results = res["results"] || []
|
75
70
|
results.map do |result|
|
76
|
-
result
|
71
|
+
result["ipAddresses"]
|
77
72
|
end.flatten.compact.uniq
|
78
73
|
end
|
79
74
|
end
|