mihari 3.4.1 → 3.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (181) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/README.md +2 -0
  4. data/Steepfile +32 -0
  5. data/config.ru +1 -0
  6. data/lib/mihari/analyzers/base.rb +24 -11
  7. data/lib/mihari/analyzers/binaryedge.rb +13 -0
  8. data/lib/mihari/analyzers/censys.rb +42 -9
  9. data/lib/mihari/analyzers/circl.rb +15 -0
  10. data/lib/mihari/analyzers/crtsh.rb +5 -0
  11. data/lib/mihari/analyzers/dnpedia.rb +5 -0
  12. data/lib/mihari/analyzers/dnstwister.rb +17 -0
  13. data/lib/mihari/analyzers/onyphe.rb +50 -9
  14. data/lib/mihari/analyzers/otx.rb +20 -0
  15. data/lib/mihari/analyzers/passivetotal.rb +25 -0
  16. data/lib/mihari/analyzers/pulsedive.rb +10 -0
  17. data/lib/mihari/analyzers/rule.rb +18 -0
  18. data/lib/mihari/analyzers/securitytrails.rb +25 -0
  19. data/lib/mihari/analyzers/shodan.rb +39 -5
  20. data/lib/mihari/analyzers/spyse.rb +20 -0
  21. data/lib/mihari/analyzers/urlscan.rb +10 -0
  22. data/lib/mihari/analyzers/virustotal.rb +20 -0
  23. data/lib/mihari/analyzers/zoomeye.rb +38 -0
  24. data/lib/mihari/cli/analyzer.rb +1 -0
  25. data/lib/mihari/cli/base.rb +0 -2
  26. data/lib/mihari/commands/init.rb +1 -1
  27. data/lib/mihari/commands/search.rb +1 -0
  28. data/lib/mihari/commands/web.rb +1 -0
  29. data/lib/mihari/{constraints.rb → constants.rb} +0 -0
  30. data/lib/mihari/database.rb +55 -3
  31. data/lib/mihari/emitters/base.rb +1 -1
  32. data/lib/mihari/emitters/misp.rb +38 -5
  33. data/lib/mihari/emitters/slack.rb +20 -2
  34. data/lib/mihari/emitters/the_hive.rb +16 -3
  35. data/lib/mihari/emitters/webhook.rb +18 -3
  36. data/lib/mihari/enrichers/ipinfo.rb +38 -0
  37. data/lib/mihari/mixins/autonomous_system.rb +19 -0
  38. data/lib/mihari/mixins/disallowed_data_value.rb +1 -1
  39. data/lib/mihari/models/alert.rb +28 -10
  40. data/lib/mihari/models/artifact.rb +94 -0
  41. data/lib/mihari/models/autonomous_system.rb +28 -0
  42. data/lib/mihari/models/dns.rb +55 -0
  43. data/lib/mihari/models/geolocation.rb +29 -0
  44. data/lib/mihari/models/reverse_dns.rb +26 -0
  45. data/lib/mihari/models/whois.rb +119 -0
  46. data/lib/mihari/schemas/configuration.rb +1 -0
  47. data/lib/mihari/schemas/rule.rb +2 -15
  48. data/lib/mihari/serializers/alert.rb +6 -4
  49. data/lib/mihari/serializers/artifact.rb +11 -2
  50. data/lib/mihari/serializers/autonomous_system.rb +9 -0
  51. data/lib/mihari/serializers/dns.rb +11 -0
  52. data/lib/mihari/serializers/geolocation.rb +11 -0
  53. data/lib/mihari/serializers/reverse_dns.rb +11 -0
  54. data/lib/mihari/serializers/tag.rb +4 -2
  55. data/lib/mihari/serializers/whois.rb +11 -0
  56. data/lib/mihari/structs/censys.rb +92 -0
  57. data/lib/mihari/structs/ipinfo.rb +36 -0
  58. data/lib/mihari/structs/onyphe.rb +47 -0
  59. data/lib/mihari/structs/shodan.rb +53 -0
  60. data/lib/mihari/type_checker.rb +9 -9
  61. data/lib/mihari/types.rb +21 -0
  62. data/lib/mihari/version.rb +1 -1
  63. data/lib/mihari/web/app.rb +2 -0
  64. data/lib/mihari/web/controllers/alerts_controller.rb +3 -4
  65. data/lib/mihari/web/controllers/artifacts_controller.rb +73 -3
  66. data/lib/mihari/web/controllers/ip_address_controller.rb +21 -0
  67. data/lib/mihari/web/controllers/sources_controller.rb +2 -2
  68. data/lib/mihari/web/controllers/tags_controller.rb +3 -1
  69. data/lib/mihari/web/public/index.html +1 -1
  70. data/lib/mihari/web/public/redoc-static.html +14 -11
  71. data/lib/mihari/web/public/static/fonts/fa-brands-400.1a575a41.woff +0 -0
  72. data/lib/mihari/web/public/static/fonts/fa-brands-400.513aa607.ttf +0 -0
  73. data/lib/mihari/web/public/static/fonts/fa-brands-400.592643a8.eot +0 -0
  74. data/lib/mihari/web/public/static/fonts/fa-brands-400.ed311c7a.woff2 +0 -0
  75. data/lib/mihari/web/public/static/fonts/fa-regular-400.766913e6.ttf +0 -0
  76. data/lib/mihari/web/public/static/fonts/fa-regular-400.b0e2db3b.eot +0 -0
  77. data/lib/mihari/web/public/static/fonts/fa-regular-400.b91d376b.woff2 +0 -0
  78. data/lib/mihari/web/public/static/fonts/fa-regular-400.d1d7e3b4.woff +0 -0
  79. data/lib/mihari/web/public/static/fonts/fa-solid-900.0c6bfc66.eot +0 -0
  80. data/lib/mihari/web/public/static/fonts/fa-solid-900.b9625119.ttf +0 -0
  81. data/lib/mihari/web/public/static/fonts/fa-solid-900.d745348d.woff +0 -0
  82. data/lib/mihari/web/public/static/fonts/fa-solid-900.d824df7e.woff2 +0 -0
  83. data/lib/mihari/web/public/static/img/fa-brands-400.1d5619cd.svg +3717 -0
  84. data/lib/mihari/web/public/static/img/fa-regular-400.c5d109be.svg +801 -0
  85. data/lib/mihari/web/public/static/img/fa-solid-900.37bc7099.svg +5034 -0
  86. data/lib/mihari/web/public/static/js/app.06d5cf1c.js +36 -0
  87. data/lib/mihari/web/public/static/js/app.06d5cf1c.js.map +1 -0
  88. data/lib/mihari/web/public/static/js/app.8e3e5150.js +36 -0
  89. data/lib/mihari/web/public/static/js/app.8e3e5150.js.map +1 -0
  90. data/lib/mihari/web/public/static/js/app.b5914c39.js +36 -0
  91. data/lib/mihari/web/public/static/js/app.b5914c39.js.map +1 -0
  92. data/lib/mihari.rb +30 -4
  93. data/mihari.gemspec +10 -1
  94. data/sig/lib/mihari/analyzers/base.rbs +90 -0
  95. data/sig/lib/mihari/analyzers/basic.rbs +17 -0
  96. data/sig/lib/mihari/analyzers/binaryedge.rbs +25 -0
  97. data/sig/lib/mihari/analyzers/censys.rbs +38 -0
  98. data/sig/lib/mihari/analyzers/circl.rbs +29 -0
  99. data/sig/lib/mihari/analyzers/crtsh.rbs +19 -0
  100. data/sig/lib/mihari/analyzers/dnpedia.rbs +18 -0
  101. data/sig/lib/mihari/analyzers/dnstwister.rbs +27 -0
  102. data/sig/lib/mihari/analyzers/onyphe.rbs +33 -0
  103. data/sig/lib/mihari/analyzers/otx.rbs +33 -0
  104. data/sig/lib/mihari/analyzers/passivetotal.rbs +33 -0
  105. data/sig/lib/mihari/analyzers/pulsedive.rbs +27 -0
  106. data/sig/lib/mihari/analyzers/rule.rbs +68 -0
  107. data/sig/lib/mihari/analyzers/securitytrails.rbs +33 -0
  108. data/sig/lib/mihari/analyzers/shodan.rbs +33 -0
  109. data/sig/lib/mihari/analyzers/spyse.rbs +29 -0
  110. data/sig/lib/mihari/analyzers/urlscan.rbs +28 -0
  111. data/sig/lib/mihari/analyzers/virustotal.rbs +31 -0
  112. data/sig/lib/mihari/analyzers/zoomeye.rbs +33 -0
  113. data/sig/lib/mihari/cli/analyzer.rbs +39 -0
  114. data/sig/lib/mihari/cli/base.rbs +11 -0
  115. data/sig/lib/mihari/cli/init.rbs +7 -0
  116. data/sig/lib/mihari/cli/main.rbs +9 -0
  117. data/sig/lib/mihari/cli/mixins/utils.rbs +50 -0
  118. data/sig/lib/mihari/cli/validator.rbs +7 -0
  119. data/sig/lib/mihari/commands/binaryedge.rbs +7 -0
  120. data/sig/lib/mihari/commands/censys.rbs +7 -0
  121. data/sig/lib/mihari/commands/circl.rbs +7 -0
  122. data/sig/lib/mihari/commands/crtsh.rbs +7 -0
  123. data/sig/lib/mihari/commands/dnpedia.rbs +7 -0
  124. data/sig/lib/mihari/commands/dnstwister.rbs +7 -0
  125. data/sig/lib/mihari/commands/init.rbs +11 -0
  126. data/sig/lib/mihari/commands/json.rbs +7 -0
  127. data/sig/lib/mihari/commands/onyphe.rbs +7 -0
  128. data/sig/lib/mihari/commands/otx.rbs +7 -0
  129. data/sig/lib/mihari/commands/passivetotal.rbs +7 -0
  130. data/sig/lib/mihari/commands/pulsedive.rbs +7 -0
  131. data/sig/lib/mihari/commands/search.rbs +35 -0
  132. data/sig/lib/mihari/commands/securitytrails.rbs +7 -0
  133. data/sig/lib/mihari/commands/shodan.rbs +7 -0
  134. data/sig/lib/mihari/commands/spyse.rbs +7 -0
  135. data/sig/lib/mihari/commands/urlscan.rbs +7 -0
  136. data/sig/lib/mihari/commands/validator.rbs +11 -0
  137. data/sig/lib/mihari/commands/virustotal.rbs +7 -0
  138. data/sig/lib/mihari/commands/web.rbs +7 -0
  139. data/sig/lib/mihari/commands/zoomeye.rbs +7 -0
  140. data/sig/lib/mihari/constants.rbs +3 -0
  141. data/sig/lib/mihari/database.rbs +25 -0
  142. data/sig/lib/mihari/emitters/base.rbs +18 -0
  143. data/sig/lib/mihari/emitters/database.rbs +9 -0
  144. data/sig/lib/mihari/emitters/misp.rbs +28 -0
  145. data/sig/lib/mihari/emitters/slack.rbs +58 -0
  146. data/sig/lib/mihari/emitters/stdout.rbs +9 -0
  147. data/sig/lib/mihari/emitters/the_hive.rbs +24 -0
  148. data/sig/lib/mihari/emitters/webhook.rbs +20 -0
  149. data/sig/lib/mihari/enrichers/ipinfo.rbs +14 -0
  150. data/sig/lib/mihari/errors.rbs +10 -0
  151. data/sig/lib/mihari/mixins/autonomous_system.rbs +14 -0
  152. data/sig/lib/mihari/mixins/configurable.rbs +26 -0
  153. data/sig/lib/mihari/mixins/configuration.rbs +45 -0
  154. data/sig/lib/mihari/mixins/disallowed_data_value.rbs +25 -0
  155. data/sig/lib/mihari/mixins/hash.rbs +14 -0
  156. data/sig/lib/mihari/mixins/refang.rbs +14 -0
  157. data/sig/lib/mihari/mixins/retriable.rbs +15 -0
  158. data/sig/lib/mihari/mixins/rule.rbs +41 -0
  159. data/sig/lib/mihari/models/alert.rbs +46 -0
  160. data/sig/lib/mihari/models/artifact.rbs +65 -0
  161. data/sig/lib/mihari/models/autonomous_system.rbs +14 -0
  162. data/sig/lib/mihari/models/dns.rbs +19 -0
  163. data/sig/lib/mihari/models/geolocation.rbs +15 -0
  164. data/sig/lib/mihari/models/reverse_dns.rbs +14 -0
  165. data/sig/lib/mihari/models/tag.rbs +5 -0
  166. data/sig/lib/mihari/models/tagging.rbs +4 -0
  167. data/sig/lib/mihari/models/whois.rbs +66 -0
  168. data/sig/lib/mihari/notifiers/base.rbs +18 -0
  169. data/sig/lib/mihari/notifiers/exception_notifier.rbs +75 -0
  170. data/sig/lib/mihari/notifiers/slack.rbs +50 -0
  171. data/sig/lib/mihari/status.rbs +25 -0
  172. data/sig/lib/mihari/structs/censys.rbs +50 -0
  173. data/sig/lib/mihari/structs/ipinfo.rbs +17 -0
  174. data/sig/lib/mihari/structs/onyphe.rbs +25 -0
  175. data/sig/lib/mihari/structs/shodan.rbs +28 -0
  176. data/sig/lib/mihari/type_checker.rbs +48 -0
  177. data/sig/lib/mihari/types.rbs +17 -0
  178. data/sig/lib/mihari/version.rbs +3 -0
  179. data/sig/lib/mihari/web/app.rbs +5 -0
  180. data/sig/lib/mihari.rbs +57 -0
  181. metadata +259 -5
@@ -13,6 +13,7 @@ module Mihari
13
13
  optional(:censys_secret).value(:string)
14
14
  optional(:circl_passive_password).value(:string)
15
15
  optional(:circl_passive_username).value(:string)
16
+ optional(:ipinfo_api_key).value(:string)
16
17
  optional(:misp_api_endpoint).value(:string)
17
18
  optional(:misp_api_key).value(:string)
18
19
  optional(:onyphe_api_key).value(:string)
@@ -2,26 +2,13 @@
2
2
 
3
3
  require "dry/schema"
4
4
  require "dry/validation"
5
- require "dry/types"
6
5
 
7
6
  require "mihari/schemas/macros"
8
7
 
9
8
  module Mihari
10
- module Types
11
- include Dry.Types()
12
- end
13
-
14
- DataTypes = Types::String.enum(*ALLOWED_DATA_TYPES)
15
-
16
- AnalyzerTypes = Types::String.enum(
17
- "binaryedge", "censys", "circl", "dnpedia", "dnstwister",
18
- "onyphe", "otx", "passivetotal", "pulsedive", "securitytrails",
19
- "shodan", "virustotal"
20
- )
21
-
22
9
  module Schemas
23
10
  Analyzer = Dry::Schema.Params do
24
- required(:analyzer).value(AnalyzerTypes)
11
+ required(:analyzer).value(Types::AnalyzerTypes)
25
12
  required(:query).value(:string)
26
13
  end
27
14
 
@@ -62,7 +49,7 @@ module Mihari
62
49
 
63
50
  required(:queries).value(:array).each { Analyzer | Spyse | ZoomEye | Urlscan | Crtsh }
64
51
 
65
- optional(:allowed_data_types).value(array[DataTypes]).default(ALLOWED_DATA_TYPES)
52
+ optional(:allowed_data_types).value(array[Types::DataTypes]).default(ALLOWED_DATA_TYPES)
66
53
  optional(:disallowed_data_values).value(array[:string]).default([])
67
54
 
68
55
  optional(:ignore_old_artifacts).value(:bool).default(false)
@@ -3,10 +3,12 @@
3
3
  require "active_model_serializers"
4
4
 
5
5
  module Mihari
6
- class AlertSerializer < ActiveModel::Serializer
7
- attributes :id, :title, :description, :source, :created_at
6
+ module Serializers
7
+ class AlertSerializer < ActiveModel::Serializer
8
+ attributes :id, :title, :description, :source, :created_at
8
9
 
9
- has_many :artifacts
10
- has_many :tags, through: :taggings
10
+ has_many :artifacts, serializer: ArtifactSerializer
11
+ has_many :tags, through: :taggings, serializer: TagSerializer
12
+ end
11
13
  end
12
14
  end
@@ -3,7 +3,16 @@
3
3
  require "active_model_serializers"
4
4
 
5
5
  module Mihari
6
- class ArtifactSerializer < ActiveModel::Serializer
7
- attributes :id, :data, :data_type, :source
6
+ module Serializers
7
+ class ArtifactSerializer < ActiveModel::Serializer
8
+ attributes :id, :data, :data_type, :source
9
+
10
+ has_one :autonomous_system, serializer: AutonomousSystemSerializer
11
+ has_one :geolocation, serializer: GeolocationSerializer
12
+ has_one :whois_record, serializer: WhoisRecordSerializer
13
+
14
+ has_many :dns_records, serializer: DnsRecordSerializer
15
+ has_many :reverse_dns_names, serializer: ReverseDnsNameSerializer
16
+ end
8
17
  end
9
18
  end
@@ -0,0 +1,9 @@
1
+ require "active_model_serializers"
2
+
3
+ module Mihari
4
+ module Serializers
5
+ class AutonomousSystemSerializer < ActiveModel::Serializer
6
+ attributes :asn
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model_serializers"
4
+
5
+ module Mihari
6
+ module Serializers
7
+ class DnsRecordSerializer < ActiveModel::Serializer
8
+ attributes :resource, :value
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model_serializers"
4
+
5
+ module Mihari
6
+ module Serializers
7
+ class GeolocationSerializer < ActiveModel::Serializer
8
+ attributes :country, :country_code
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model_serializers"
4
+
5
+ module Mihari
6
+ module Serializers
7
+ class ReverseDnsNameSerializer < ActiveModel::Serializer
8
+ attributes :name
9
+ end
10
+ end
11
+ end
@@ -3,7 +3,9 @@
3
3
  require "active_model_serializers"
4
4
 
5
5
  module Mihari
6
- class TagSerializer < ActiveModel::Serializer
7
- attributes :id, :name
6
+ module Serializers
7
+ class TagSerializer < ActiveModel::Serializer
8
+ attributes :id, :name
9
+ end
8
10
  end
9
11
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_model_serializers"
4
+
5
+ module Mihari
6
+ module Serializers
7
+ class WhoisRecordSerializer < ActiveModel::Serializer
8
+ attributes :domain, :created_on, :updated_on, :expires_on, :registrar, :contacts
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,92 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module Censys
7
+ class AutonomousSystem < Dry::Struct
8
+ attribute :asn, Types::Int
9
+
10
+ def self.from_dynamic!(d)
11
+ d = Types::Hash[d]
12
+ new(
13
+ asn: d.fetch("asn")
14
+ )
15
+ end
16
+ end
17
+
18
+ class Location < Dry::Struct
19
+ attribute :country, Types::String.optional
20
+ attribute :country_code, Types::String.optional
21
+
22
+ def self.from_dynamic!(d)
23
+ d = Types::Hash[d]
24
+ new(
25
+ country: d["country"],
26
+ country_code: d["country_code"]
27
+ )
28
+ end
29
+ end
30
+
31
+ class Hit < Dry::Struct
32
+ attribute :ip, Types::String
33
+ attribute :location, Location
34
+ attribute :autonomous_system, AutonomousSystem
35
+
36
+ def self.from_dynamic!(d)
37
+ d = Types::Hash[d]
38
+ new(
39
+ ip: d.fetch("ip"),
40
+ location: Location.from_dynamic!(d.fetch("location")),
41
+ autonomous_system: AutonomousSystem.from_dynamic!(d.fetch("autonomous_system"))
42
+ )
43
+ end
44
+ end
45
+
46
+ class Links < Dry::Struct
47
+ attribute :next, Types::String
48
+ attribute :prev, Types::String
49
+
50
+ def self.from_dynamic!(d)
51
+ d = Types::Hash[d]
52
+ new(
53
+ next: d.fetch("next"),
54
+ prev: d.fetch("prev")
55
+ )
56
+ end
57
+ end
58
+
59
+ class Result < Dry::Struct
60
+ attribute :query, Types::String
61
+ attribute :total, Types::Int
62
+ attribute :hits, Types.Array(Hit)
63
+ attribute :links, Links
64
+
65
+ def self.from_dynamic!(d)
66
+ d = Types::Hash[d]
67
+ new(
68
+ query: d.fetch("query"),
69
+ total: d.fetch("total"),
70
+ hits: d.fetch("hits", []).map { |x| Hit.from_dynamic!(x) },
71
+ links: Links.from_dynamic!(d.fetch("links"))
72
+ )
73
+ end
74
+ end
75
+
76
+ class Response < Dry::Struct
77
+ attribute :code, Types::Int
78
+ attribute :status, Types::String
79
+ attribute :result, Result
80
+
81
+ def self.from_dynamic!(d)
82
+ d = Types::Hash[d]
83
+ new(
84
+ code: d.fetch("code"),
85
+ status: d.fetch("status"),
86
+ result: Result.from_dynamic!(d.fetch("result"))
87
+ )
88
+ end
89
+ end
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,36 @@
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
13
+
14
+ class << self
15
+ include Mixins::AutonomousSystem
16
+
17
+ def from_dynamic!(d)
18
+ d = Types::Hash[d]
19
+
20
+ org = d.fetch("org")
21
+ asn = org.split.first
22
+ asn = normalize_asn(asn)
23
+
24
+ new(
25
+ ip: d.fetch("ip"),
26
+ loc: d.fetch("loc"),
27
+ hostname: d["hostname"],
28
+ country_code: d.fetch("country"),
29
+ asn: asn
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,47 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module Onyphe
7
+ class Result < Dry::Struct
8
+ attribute :asn, Types::String
9
+ attribute :country_code, Types::String.optional
10
+ attribute :ip, Types::String
11
+
12
+ def self.from_dynamic!(d)
13
+ d = Types::Hash[d]
14
+ new(
15
+ asn: d.fetch("asn"),
16
+ ip: d.fetch("ip"),
17
+ # Onyphe's country = 2-letter country code
18
+ country_code: d["country"]
19
+ )
20
+ end
21
+ end
22
+
23
+ class Response < Dry::Struct
24
+ attribute :count, Types::Int
25
+ attribute :error, Types::Int
26
+ attribute :max_page, Types::Int
27
+ attribute :page, Types::String
28
+ attribute :results, Types.Array(Result)
29
+ attribute :status, Types::String
30
+ attribute :total, Types::Int
31
+
32
+ def self.from_dynamic!(d)
33
+ d = Types::Hash[d]
34
+ new(
35
+ count: d.fetch("count"),
36
+ error: d.fetch("error"),
37
+ max_page: d.fetch("max_page"),
38
+ page: d.fetch("page"),
39
+ results: d.fetch("results").map { |x| Result.from_dynamic!(x) },
40
+ status: d.fetch("status"),
41
+ total: d.fetch("total")
42
+ )
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,53 @@
1
+ require "json"
2
+ require "dry/struct"
3
+
4
+ module Mihari
5
+ module Structs
6
+ module Shodan
7
+ class Location < Dry::Struct
8
+ attribute :country_code, Types::String
9
+ attribute :country_name, Types::String
10
+
11
+ def self.from_dynamic!(d)
12
+ d = Types::Hash[d]
13
+ new(
14
+ country_code: d.fetch("country_code"),
15
+ country_name: d.fetch("country_name")
16
+ )
17
+ end
18
+ end
19
+
20
+ class Match < Dry::Struct
21
+ attribute :asn, Types::String
22
+ attribute :hostnames, Types.Array(Types::String)
23
+ attribute :location, Location
24
+ attribute :domains, Types.Array(Types::String)
25
+ attribute :ip_str, Types::String
26
+
27
+ def self.from_dynamic!(d)
28
+ d = Types::Hash[d]
29
+ new(
30
+ asn: d.fetch("asn"),
31
+ hostnames: d.fetch("hostnames"),
32
+ location: Location.from_dynamic!(d.fetch("location")),
33
+ domains: d.fetch("domains"),
34
+ ip_str: d.fetch("ip_str")
35
+ )
36
+ end
37
+ end
38
+
39
+ class Result < Dry::Struct
40
+ attribute :matches, Types.Array(Match)
41
+ attribute :total, Types::Int
42
+
43
+ def self.from_dynamic!(d)
44
+ d = Types::Hash[d]
45
+ new(
46
+ matches: d.fetch("matches", []).map { |x| Match.from_dynamic!(x) },
47
+ total: d.fetch("total")
48
+ )
49
+ end
50
+ end
51
+ end
52
+ end
53
+ 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