mihari 3.6.0 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (139) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/Steepfile +32 -0
  4. data/lib/mihari/analyzers/base.rb +7 -22
  5. data/lib/mihari/analyzers/binaryedge.rb +13 -0
  6. data/lib/mihari/analyzers/censys.rb +5 -0
  7. data/lib/mihari/analyzers/circl.rb +15 -0
  8. data/lib/mihari/analyzers/crtsh.rb +5 -0
  9. data/lib/mihari/analyzers/dnpedia.rb +5 -0
  10. data/lib/mihari/analyzers/dnstwister.rb +17 -0
  11. data/lib/mihari/analyzers/onyphe.rb +20 -4
  12. data/lib/mihari/analyzers/otx.rb +20 -0
  13. data/lib/mihari/analyzers/passivetotal.rb +25 -0
  14. data/lib/mihari/analyzers/pulsedive.rb +10 -0
  15. data/lib/mihari/analyzers/rule.rb +18 -0
  16. data/lib/mihari/analyzers/securitytrails.rb +25 -0
  17. data/lib/mihari/analyzers/shodan.rb +13 -0
  18. data/lib/mihari/analyzers/spyse.rb +20 -0
  19. data/lib/mihari/analyzers/urlscan.rb +10 -0
  20. data/lib/mihari/analyzers/virustotal.rb +20 -0
  21. data/lib/mihari/analyzers/zoomeye.rb +38 -0
  22. data/lib/mihari/database.rb +13 -0
  23. data/lib/mihari/emitters/base.rb +1 -1
  24. data/lib/mihari/emitters/misp.rb +38 -5
  25. data/lib/mihari/emitters/slack.rb +20 -2
  26. data/lib/mihari/emitters/the_hive.rb +16 -3
  27. data/lib/mihari/emitters/webhook.rb +18 -3
  28. data/lib/mihari/enrichers/base.rb +18 -0
  29. data/lib/mihari/enrichers/ipinfo.rb +49 -0
  30. data/lib/mihari/mixins/autonomous_system.rb +19 -0
  31. data/lib/mihari/mixins/disallowed_data_value.rb +1 -1
  32. data/lib/mihari/models/artifact.rb +42 -3
  33. data/lib/mihari/models/autonomous_system.rb +18 -1
  34. data/lib/mihari/models/dns.rb +2 -0
  35. data/lib/mihari/models/geolocation.rb +21 -1
  36. data/lib/mihari/models/reverse_dns.rb +2 -0
  37. data/lib/mihari/models/whois.rb +1 -1
  38. data/lib/mihari/status.rb +7 -2
  39. data/lib/mihari/structs/ipinfo.rb +39 -0
  40. data/lib/mihari/structs/onyphe.rb +2 -2
  41. data/lib/mihari/type_checker.rb +9 -9
  42. data/lib/mihari/version.rb +1 -1
  43. data/lib/mihari/web/controllers/artifacts_controller.rb +27 -1
  44. data/lib/mihari/web/controllers/ip_address_controller.rb +4 -19
  45. data/lib/mihari/web/public/index.html +1 -1
  46. data/lib/mihari/web/public/redoc-static.html +7 -6
  47. data/lib/mihari/web/public/static/js/app.06d5cf1c.js +36 -0
  48. data/lib/mihari/web/public/static/js/app.06d5cf1c.js.map +1 -0
  49. data/lib/mihari.rb +40 -26
  50. data/mihari.gemspec +7 -4
  51. data/sig/lib/mihari/analyzers/base.rbs +90 -0
  52. data/sig/lib/mihari/analyzers/basic.rbs +17 -0
  53. data/sig/lib/mihari/analyzers/binaryedge.rbs +25 -0
  54. data/sig/lib/mihari/analyzers/censys.rbs +38 -0
  55. data/sig/lib/mihari/analyzers/circl.rbs +29 -0
  56. data/sig/lib/mihari/analyzers/crtsh.rbs +19 -0
  57. data/sig/lib/mihari/analyzers/dnpedia.rbs +18 -0
  58. data/sig/lib/mihari/analyzers/dnstwister.rbs +27 -0
  59. data/sig/lib/mihari/analyzers/onyphe.rbs +33 -0
  60. data/sig/lib/mihari/analyzers/otx.rbs +33 -0
  61. data/sig/lib/mihari/analyzers/passivetotal.rbs +33 -0
  62. data/sig/lib/mihari/analyzers/pulsedive.rbs +27 -0
  63. data/sig/lib/mihari/analyzers/rule.rbs +68 -0
  64. data/sig/lib/mihari/analyzers/securitytrails.rbs +33 -0
  65. data/sig/lib/mihari/analyzers/shodan.rbs +33 -0
  66. data/sig/lib/mihari/analyzers/spyse.rbs +29 -0
  67. data/sig/lib/mihari/analyzers/urlscan.rbs +28 -0
  68. data/sig/lib/mihari/analyzers/virustotal.rbs +31 -0
  69. data/sig/lib/mihari/analyzers/zoomeye.rbs +33 -0
  70. data/sig/lib/mihari/cli/analyzer.rbs +39 -0
  71. data/sig/lib/mihari/cli/base.rbs +11 -0
  72. data/sig/lib/mihari/cli/init.rbs +7 -0
  73. data/sig/lib/mihari/cli/main.rbs +9 -0
  74. data/sig/lib/mihari/cli/mixins/utils.rbs +50 -0
  75. data/sig/lib/mihari/cli/validator.rbs +7 -0
  76. data/sig/lib/mihari/commands/binaryedge.rbs +7 -0
  77. data/sig/lib/mihari/commands/censys.rbs +7 -0
  78. data/sig/lib/mihari/commands/circl.rbs +7 -0
  79. data/sig/lib/mihari/commands/crtsh.rbs +7 -0
  80. data/sig/lib/mihari/commands/dnpedia.rbs +7 -0
  81. data/sig/lib/mihari/commands/dnstwister.rbs +7 -0
  82. data/sig/lib/mihari/commands/init.rbs +11 -0
  83. data/sig/lib/mihari/commands/json.rbs +7 -0
  84. data/sig/lib/mihari/commands/onyphe.rbs +7 -0
  85. data/sig/lib/mihari/commands/otx.rbs +7 -0
  86. data/sig/lib/mihari/commands/passivetotal.rbs +7 -0
  87. data/sig/lib/mihari/commands/pulsedive.rbs +7 -0
  88. data/sig/lib/mihari/commands/search.rbs +35 -0
  89. data/sig/lib/mihari/commands/securitytrails.rbs +7 -0
  90. data/sig/lib/mihari/commands/shodan.rbs +7 -0
  91. data/sig/lib/mihari/commands/spyse.rbs +7 -0
  92. data/sig/lib/mihari/commands/urlscan.rbs +7 -0
  93. data/sig/lib/mihari/commands/validator.rbs +11 -0
  94. data/sig/lib/mihari/commands/virustotal.rbs +7 -0
  95. data/sig/lib/mihari/commands/web.rbs +7 -0
  96. data/sig/lib/mihari/commands/zoomeye.rbs +7 -0
  97. data/sig/lib/mihari/constants.rbs +3 -0
  98. data/sig/lib/mihari/database.rbs +25 -0
  99. data/sig/lib/mihari/emitters/base.rbs +18 -0
  100. data/sig/lib/mihari/emitters/database.rbs +9 -0
  101. data/sig/lib/mihari/emitters/misp.rbs +28 -0
  102. data/sig/lib/mihari/emitters/slack.rbs +58 -0
  103. data/sig/lib/mihari/emitters/stdout.rbs +9 -0
  104. data/sig/lib/mihari/emitters/the_hive.rbs +24 -0
  105. data/sig/lib/mihari/emitters/webhook.rbs +20 -0
  106. data/sig/lib/mihari/enrichers/base.rbs +12 -0
  107. data/sig/lib/mihari/enrichers/ipinfo.rbs +16 -0
  108. data/sig/lib/mihari/errors.rbs +10 -0
  109. data/sig/lib/mihari/mixins/autonomous_system.rbs +14 -0
  110. data/sig/lib/mihari/mixins/configurable.rbs +26 -0
  111. data/sig/lib/mihari/mixins/configuration.rbs +45 -0
  112. data/sig/lib/mihari/mixins/disallowed_data_value.rbs +25 -0
  113. data/sig/lib/mihari/mixins/hash.rbs +14 -0
  114. data/sig/lib/mihari/mixins/refang.rbs +14 -0
  115. data/sig/lib/mihari/mixins/retriable.rbs +15 -0
  116. data/sig/lib/mihari/mixins/rule.rbs +41 -0
  117. data/sig/lib/mihari/models/alert.rbs +46 -0
  118. data/sig/lib/mihari/models/artifact.rbs +65 -0
  119. data/sig/lib/mihari/models/autonomous_system.rbs +14 -0
  120. data/sig/lib/mihari/models/dns.rbs +19 -0
  121. data/sig/lib/mihari/models/geolocation.rbs +15 -0
  122. data/sig/lib/mihari/models/reverse_dns.rbs +14 -0
  123. data/sig/lib/mihari/models/tag.rbs +5 -0
  124. data/sig/lib/mihari/models/tagging.rbs +4 -0
  125. data/sig/lib/mihari/models/whois.rbs +66 -0
  126. data/sig/lib/mihari/notifiers/base.rbs +18 -0
  127. data/sig/lib/mihari/notifiers/exception_notifier.rbs +75 -0
  128. data/sig/lib/mihari/notifiers/slack.rbs +50 -0
  129. data/sig/lib/mihari/status.rbs +25 -0
  130. data/sig/lib/mihari/structs/censys.rbs +50 -0
  131. data/sig/lib/mihari/structs/ipinfo.rbs +17 -0
  132. data/sig/lib/mihari/structs/onyphe.rbs +25 -0
  133. data/sig/lib/mihari/structs/shodan.rbs +28 -0
  134. data/sig/lib/mihari/type_checker.rbs +48 -0
  135. data/sig/lib/mihari/types.rbs +17 -0
  136. data/sig/lib/mihari/version.rbs +3 -0
  137. data/sig/lib/mihari/web/app.rbs +5 -0
  138. data/sig/lib/mihari.rbs +59 -0
  139. metadata +148 -10
@@ -6,7 +6,7 @@ require "net/ping"
6
6
  module Mihari
7
7
  module Emitters
8
8
  class TheHive < Base
9
- # @return [true, false]
9
+ # @return [Boolean]
10
10
  def valid?
11
11
  api_endpont? && api_key? && ping?
12
12
  end
@@ -34,16 +34,29 @@ module Mihari
34
34
  @api ||= Hachi::API.new(api_endpoint: Mihari.config.thehive_api_endpoint, api_key: Mihari.config.thehive_api_key)
35
35
  end
36
36
 
37
- # @return [true, false]
37
+ #
38
+ # Check whether an API endpoint is set or not
39
+ #
40
+ # @return [Boolean]
41
+ #
38
42
  def api_endpont?
39
43
  !Mihari.config.thehive_api_endpoint.nil?
40
44
  end
41
45
 
42
- # @return [true, false]
46
+ #
47
+ # Check whether an API key is set or not
48
+ #
49
+ # @return [Boolean]
50
+ # ]
43
51
  def api_key?
44
52
  !Mihari.config.thehive_api_key.nil?
45
53
  end
46
54
 
55
+ #
56
+ # Check whether an API endpoint is reachable or not
57
+ #
58
+ # @return [Boolean]
59
+ #
47
60
  def ping?
48
61
  base_url = Mihari.config.thehive_api_endpoint
49
62
  base_url = base_url.end_with?("/") ? base_url[0..-2] : base_url
@@ -7,7 +7,7 @@ require "uri"
7
7
  module Mihari
8
8
  module Emitters
9
9
  class Webhook < Base
10
- # @return [true, false]
10
+ # @return [Boolean]
11
11
  def valid?
12
12
  webhook_url?
13
13
  end
@@ -24,7 +24,7 @@ module Mihari
24
24
  tags: tags
25
25
  }
26
26
 
27
- if use_json_body
27
+ if use_json_body?
28
28
  Net::HTTP.post(uri, data.to_json, "Content-Type" => "application/json")
29
29
  else
30
30
  Net::HTTP.post_form(uri, data)
@@ -37,15 +37,30 @@ module Mihari
37
37
  %w[webhook_url]
38
38
  end
39
39
 
40
+ #
41
+ # Webhook URL
42
+ #
43
+ # @return [String, nil]
44
+ #
40
45
  def webhook_url
41
46
  @webhook_url ||= Mihari.config.webhook_url
42
47
  end
43
48
 
49
+ #
50
+ # Check whether a webhook URL is set or not
51
+ #
52
+ # @return [<Type>] <description>
53
+ #
44
54
  def webhook_url?
45
55
  !webhook_url.nil?
46
56
  end
47
57
 
48
- def use_json_body
58
+ #
59
+ # Check whether to use JSON body or NOT
60
+ #
61
+ # @return [<Type>] <description>
62
+ #
63
+ def use_json_body?
49
64
  @use_json_body ||= Mihari.config.webhook_use_json_body
50
65
  end
51
66
  end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Enrichers
5
+ class Base
6
+ include Mixins::Configurable
7
+
8
+ def self.inherited(child)
9
+ Mihari.enrichers << child
10
+ end
11
+
12
+ # @return [Boolean]
13
+ def valid?
14
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,49 @@
1
+ require "http"
2
+ require "json"
3
+ require "memist"
4
+
5
+ module Mihari
6
+ module Enrichers
7
+ class IPInfo < Base
8
+ # @return [Boolean]
9
+ def valid?
10
+ Mihari.config.ipinfo_api_key.nil?
11
+ end
12
+
13
+ private
14
+
15
+ def configuration_keys
16
+ %w[ipinfo_api_key]
17
+ end
18
+
19
+ class << self
20
+ include Memist::Memoizable
21
+
22
+ #
23
+ # Query IPInfo
24
+ #
25
+ # @param [String] ip
26
+ #
27
+ # @return [Mihari::Structs::IPInfo::Response, nil]
28
+ #
29
+ def query(ip)
30
+ headers = {}
31
+ token = Mihari.config.ipinfo_api_key
32
+ unless token.nil?
33
+ headers[:authorization] = "Bearer #{token}"
34
+ end
35
+
36
+ begin
37
+ res = HTTP.headers(headers).get("https://ipinfo.io/#{ip}/json")
38
+ data = JSON.parse(res.body.to_s)
39
+
40
+ Structs::IPInfo::Response.from_dynamic! data
41
+ rescue HTTP::Error
42
+ nil
43
+ end
44
+ end
45
+ memoize :query
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,19 @@
1
+ module Mihari
2
+ module Mixins
3
+ module AutonomousSystem
4
+ #
5
+ # Normalize ASN value
6
+ #
7
+ # @param [String, Integer] asn
8
+ #
9
+ # @return [Integer]
10
+ #
11
+ def normalize_asn(asn)
12
+ return asn if asn.is_a?(Integer)
13
+ return asn.to_i unless asn.start_with?("AS")
14
+
15
+ asn.delete_prefix("AS").to_i
16
+ end
17
+ end
18
+ end
19
+ end
@@ -17,7 +17,7 @@ module Mihari
17
17
 
18
18
  # if a value is surrounded by slashes, take it as a regexp
19
19
  value_without_slashes = value[1..-2]
20
- Regexp.compile value_without_slashes
20
+ Regexp.compile value_without_slashes.to_s
21
21
  end
22
22
 
23
23
  memoize :normalize_disallowed_data_value
@@ -16,6 +16,8 @@ end
16
16
 
17
17
  module Mihari
18
18
  class Artifact < ActiveRecord::Base
19
+ belongs_to :alert
20
+
19
21
  has_one :autonomous_system, dependent: :destroy
20
22
  has_one :geolocation, dependent: :destroy
21
23
  has_one :whois_record, dependent: :destroy
@@ -80,6 +82,35 @@ module Mihari
80
82
  self.reverse_dns_names = ReverseDnsName.build_by_ip(data)
81
83
  end
82
84
 
85
+ #
86
+ # Enrich(add) geolocation
87
+ #
88
+ def enrich_geolocation
89
+ return unless can_enrich_geolocation?
90
+
91
+ self.geolocation = Geolocation.build_by_ip(data)
92
+ end
93
+
94
+ #
95
+ # Enrich(add) geolocation
96
+ #
97
+ def enrich_autonomous_system
98
+ return unless can_enrich_autonomous_system?
99
+
100
+ self.autonomous_system = AutonomousSystem.build_by_ip(data)
101
+ end
102
+
103
+ #
104
+ # Enrich all the enrichable relationships of the artifact
105
+ #
106
+ def enrich_all
107
+ enrich_autonomous_system
108
+ enrich_dns
109
+ enrich_geolocation
110
+ enrich_reverse_dns
111
+ enrich_whois
112
+ end
113
+
83
114
  private
84
115
 
85
116
  def normalize_as_domain(url_or_domain)
@@ -89,15 +120,23 @@ module Mihari
89
120
  end
90
121
 
91
122
  def can_enrich_whois?
92
- %w[domain url].include? data_type
123
+ %w[domain url].include?(data_type) && whois_record.nil?
93
124
  end
94
125
 
95
126
  def can_enrich_dns?
96
- %w[domain url].include? data_type
127
+ %w[domain url].include?(data_type) && dns_records.empty?
97
128
  end
98
129
 
99
130
  def can_enrich_revese_dns?
100
- data_type == "ip"
131
+ data_type == "ip" && reverse_dns_names.empty?
132
+ end
133
+
134
+ def can_enrich_geolocation?
135
+ data_type == "ip" && geolocation.nil?
136
+ end
137
+
138
+ def can_enrich_autonomous_system?
139
+ data_type == "ip" && autonomous_system.nil?
101
140
  end
102
141
  end
103
142
  end
@@ -4,6 +4,23 @@ require "active_record"
4
4
 
5
5
  module Mihari
6
6
  class AutonomousSystem < ActiveRecord::Base
7
- has_one :artifact, dependent: :destroy
7
+ belongs_to :artifact
8
+
9
+ class << self
10
+ #
11
+ # Build AS
12
+ #
13
+ # @param [String] ip
14
+ #
15
+ # @return [Mihari::AutonomousSystem, nil]
16
+ #
17
+ def build_by_ip(ip)
18
+ res = Enrichers::IPInfo.query(ip)
19
+
20
+ return nil if res.nil? || res.asn.nil?
21
+
22
+ new(asn: res.asn)
23
+ end
24
+ end
8
25
  end
9
26
  end
@@ -5,6 +5,8 @@ require "resolv"
5
5
 
6
6
  module Mihari
7
7
  class DnsRecord < ActiveRecord::Base
8
+ belongs_to :artifact
9
+
8
10
  class << self
9
11
  #
10
12
  # Build DNS records
@@ -1,9 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record"
4
+ require "normalize_country"
4
5
 
5
6
  module Mihari
6
7
  class Geolocation < ActiveRecord::Base
7
- has_one :artifact, dependent: :destroy
8
+ belongs_to :artifact
9
+
10
+ class << self
11
+ #
12
+ # Build Geolocation
13
+ #
14
+ # @param [String] ip
15
+ #
16
+ # @return [Mihari::Geolocation, nil]
17
+ #
18
+ def build_by_ip(ip)
19
+ res = Enrichers::IPInfo.query(ip)
20
+
21
+ unless res.nil?
22
+ return new(country: NormalizeCountry(res.country_code, to: :short), country_code: res.country_code)
23
+ end
24
+
25
+ nil
26
+ end
27
+ end
8
28
  end
9
29
  end
@@ -5,6 +5,8 @@ require "resolv"
5
5
 
6
6
  module Mihari
7
7
  class ReverseDnsName < ActiveRecord::Base
8
+ belongs_to :artifact
9
+
8
10
  class << self
9
11
  #
10
12
  # Build reverse DNS names
@@ -6,7 +6,7 @@ require "public_suffix"
6
6
 
7
7
  module Mihari
8
8
  class WhoisRecord < ActiveRecord::Base
9
- has_one :artifact, dependent: :destroy
9
+ belongs_to :artifact
10
10
 
11
11
  @memo = {}
12
12
 
data/lib/mihari/status.rb CHANGED
@@ -18,7 +18,7 @@ module Mihari
18
18
  # @return [Array<Hash>]
19
19
  #
20
20
  def statuses
21
- (Mihari.analyzers + Mihari.emitters).map do |klass|
21
+ (Mihari.analyzers + Mihari.emitters + Mihari.enrichers).map do |klass|
22
22
  name = klass.to_s.split("::").last.to_s
23
23
 
24
24
  [name, build_status(klass)]
@@ -36,11 +36,16 @@ module Mihari
36
36
  return nil if klass == Mihari::Analyzers::Rule
37
37
 
38
38
  is_analyzer = klass.ancestors.include?(Mihari::Analyzers::Base)
39
+ is_emitter = klass.ancestors.include?(Mihari::Emitters::Base)
40
+ is_enricher = klass.ancestors.include?(Mihari::Enrichers::Base)
39
41
 
40
42
  instance = is_analyzer ? klass.new("dummy") : klass.new
41
43
  is_configured = instance.configured?
42
44
  values = instance.configuration_values
43
- type = is_analyzer ? "Analyzer" : "Emitter"
45
+
46
+ type = "Analyzer"
47
+ type = "Emitter" if is_emitter
48
+ type = "Enricher" if is_enricher
44
49
 
45
50
  values ? { is_configured: is_configured, values: values, type: type } : nil
46
51
  rescue ArgumentError => _e
@@ -0,0 +1,39 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module IPInfo
7
+ class Response < Dry::Struct
8
+ attribute :ip, Types::String
9
+ attribute :hostname, Types::String.optional
10
+ attribute :loc, Types::String
11
+ attribute :country_code, Types::String
12
+ attribute :asn, Types::Integer.optional
13
+
14
+ class << self
15
+ include Mixins::AutonomousSystem
16
+
17
+ def from_dynamic!(d)
18
+ d = Types::Hash[d]
19
+
20
+ asn = nil
21
+ org = d["org"]
22
+ unless org.nil?
23
+ asn = org.split.first
24
+ asn = normalize_asn(asn)
25
+ end
26
+
27
+ new(
28
+ ip: d.fetch("ip"),
29
+ loc: d.fetch("loc"),
30
+ hostname: d["hostname"],
31
+ country_code: d.fetch("country"),
32
+ asn: asn
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -6,7 +6,7 @@ module Mihari
6
6
  module Onyphe
7
7
  class Result < Dry::Struct
8
8
  attribute :asn, Types::String
9
- attribute :country_code, Types::String
9
+ attribute :country_code, Types::String.optional
10
10
  attribute :ip, Types::String
11
11
 
12
12
  def self.from_dynamic!(d)
@@ -15,7 +15,7 @@ module Mihari
15
15
  asn: d.fetch("asn"),
16
16
  ip: d.fetch("ip"),
17
17
  # Onyphe's country = 2-letter country code
18
- country_code: d.fetch("country")
18
+ country_code: d["country"]
19
19
  )
20
20
  end
21
21
  end
@@ -18,12 +18,12 @@ module Mihari
18
18
  raise ArgumentError if data.is_a?(Hash)
19
19
  end
20
20
 
21
- # @return [true, false]
21
+ # @return [Boolean]
22
22
  def hash?
23
23
  md5? || sha1? || sha256? || sha512?
24
24
  end
25
25
 
26
- # @return [true, false]
26
+ # @return [Boolean]
27
27
  def ip?
28
28
  IPAddr.new data
29
29
  true
@@ -31,7 +31,7 @@ module Mihari
31
31
  false
32
32
  end
33
33
 
34
- # @return [true, false]
34
+ # @return [Boolean]
35
35
  def domain?
36
36
  uri = Addressable::URI.parse("http://#{data}")
37
37
  uri.host == data && PublicSuffix.valid?(uri.host)
@@ -39,7 +39,7 @@ module Mihari
39
39
  false
40
40
  end
41
41
 
42
- # @return [true, false]
42
+ # @return [Boolean]
43
43
  def url?
44
44
  uri = Addressable::URI.parse(data)
45
45
  uri.scheme && uri.host && uri.path && PublicSuffix.valid?(uri.host)
@@ -47,7 +47,7 @@ module Mihari
47
47
  false
48
48
  end
49
49
 
50
- # @return [true, false]
50
+ # @return [Boolean]
51
51
  def mail?
52
52
  EmailAddress.valid? data, host_validation: :syntax
53
53
  end
@@ -83,22 +83,22 @@ module Mihari
83
83
 
84
84
  private
85
85
 
86
- # @return [true, false]
86
+ # @return [Boolean]
87
87
  def md5?
88
88
  data.match?(/^[A-Fa-f0-9]{32}$/)
89
89
  end
90
90
 
91
- # @return [true, false]
91
+ # @return [Boolean]
92
92
  def sha1?
93
93
  data.match?(/^[A-Fa-f0-9]{40}$/)
94
94
  end
95
95
 
96
- # @return [true, false]
96
+ # @return [Boolean]
97
97
  def sha256?
98
98
  data.match?(/^[A-Fa-f0-9]{64}$/)
99
99
  end
100
100
 
101
- # @return [true, false]
101
+ # @return [Boolean]
102
102
  def sha512?
103
103
  data.match?(/^[A-Fa-f0-9]{128}$/)
104
104
  end