mihari 5.2.2 → 5.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/build_frontend.sh +1 -9
  3. data/frontend/.browserslistrc +3 -0
  4. data/frontend/.eslintrc.js +33 -0
  5. data/frontend/.gitignore +25 -0
  6. data/frontend/README.md +3 -0
  7. data/frontend/babel.config.js +3 -0
  8. data/frontend/index.html +21 -0
  9. data/frontend/jest.config.js +9 -0
  10. data/frontend/package-lock.json +13216 -0
  11. data/frontend/package.json +54 -0
  12. data/frontend/public/favicon.ico +0 -0
  13. data/frontend/scripts/swagger_doc_to_yaml.rb +23 -0
  14. data/frontend/src/App.vue +27 -0
  15. data/frontend/src/api-helper.ts +113 -0
  16. data/frontend/src/api.ts +105 -0
  17. data/frontend/src/components/ErrorMessage.vue +32 -0
  18. data/frontend/src/components/Loading.vue +15 -0
  19. data/frontend/src/components/Navbar.vue +59 -0
  20. data/frontend/src/components/Pagination.vue +126 -0
  21. data/frontend/src/components/alert/Alert.vue +92 -0
  22. data/frontend/src/components/alert/Alerts.vue +66 -0
  23. data/frontend/src/components/alert/AlertsWithPagination.vue +91 -0
  24. data/frontend/src/components/alert/AlertsWrapper.vue +141 -0
  25. data/frontend/src/components/alert/Form.vue +185 -0
  26. data/frontend/src/components/artifact/AS.vue +29 -0
  27. data/frontend/src/components/artifact/Artifact.vue +321 -0
  28. data/frontend/src/components/artifact/ArtifactTag.vue +70 -0
  29. data/frontend/src/components/artifact/ArtifactTags.vue +29 -0
  30. data/frontend/src/components/artifact/ArtifactWrapper.vue +62 -0
  31. data/frontend/src/components/artifact/CPEs.vue +23 -0
  32. data/frontend/src/components/artifact/DnsRecords.vue +38 -0
  33. data/frontend/src/components/artifact/Ports.vue +23 -0
  34. data/frontend/src/components/artifact/ReverseDnsNames.vue +31 -0
  35. data/frontend/src/components/artifact/Tags.vue +29 -0
  36. data/frontend/src/components/artifact/WhoisRecord.vue +49 -0
  37. data/frontend/src/components/config/Configs.vue +68 -0
  38. data/frontend/src/components/config/ConfigsWrapper.vue +40 -0
  39. data/frontend/src/components/link/Link.vue +32 -0
  40. data/frontend/src/components/link/Links.vue +47 -0
  41. data/frontend/src/components/rule/EditRule.vue +74 -0
  42. data/frontend/src/components/rule/EditRuleWrapper.vue +56 -0
  43. data/frontend/src/components/rule/Form.vue +160 -0
  44. data/frontend/src/components/rule/InputForm.vue +80 -0
  45. data/frontend/src/components/rule/NewRule.vue +60 -0
  46. data/frontend/src/components/rule/Rule.vue +108 -0
  47. data/frontend/src/components/rule/RuleWrapper.vue +62 -0
  48. data/frontend/src/components/rule/Rules.vue +88 -0
  49. data/frontend/src/components/rule/RulesWrapper.vue +130 -0
  50. data/frontend/src/components/rule/YAML.vue +47 -0
  51. data/frontend/src/components/tag/Tag.vue +73 -0
  52. data/frontend/src/components/tag/Tags.vue +37 -0
  53. data/frontend/src/countries.ts +350 -0
  54. data/frontend/src/index.ts +23 -0
  55. data/frontend/src/links/anyrun.ts +19 -0
  56. data/frontend/src/links/base.ts +14 -0
  57. data/frontend/src/links/censys.ts +20 -0
  58. data/frontend/src/links/crtsh.ts +20 -0
  59. data/frontend/src/links/dnslytics.ts +38 -0
  60. data/frontend/src/links/greynoise.ts +20 -0
  61. data/frontend/src/links/index.ts +40 -0
  62. data/frontend/src/links/intezer.ts +20 -0
  63. data/frontend/src/links/otx.ts +33 -0
  64. data/frontend/src/links/securitytrails.ts +38 -0
  65. data/frontend/src/links/shodan.ts +20 -0
  66. data/frontend/src/links/urlscan.ts +50 -0
  67. data/frontend/src/links/virustotal.ts +72 -0
  68. data/frontend/src/main.ts +11 -0
  69. data/frontend/src/router/index.ts +57 -0
  70. data/frontend/src/rule.ts +14 -0
  71. data/frontend/src/shims-vue.d.ts +6 -0
  72. data/frontend/src/swagger.yaml +737 -0
  73. data/frontend/src/types.ts +188 -0
  74. data/frontend/src/utils.ts +60 -0
  75. data/frontend/src/views/Alerts.vue +20 -0
  76. data/frontend/src/views/Artifact.vue +44 -0
  77. data/frontend/src/views/Configs.vue +20 -0
  78. data/frontend/src/views/EditRule.vue +44 -0
  79. data/frontend/src/views/NewRule.vue +26 -0
  80. data/frontend/src/views/Rule.vue +44 -0
  81. data/frontend/src/views/Rules.vue +20 -0
  82. data/frontend/tests/unit/utils.spec.ts +7 -0
  83. data/frontend/tsconfig.json +40 -0
  84. data/frontend/vite.config.js +24 -0
  85. data/lefthook.yml +10 -0
  86. data/lib/mihari/analyzers/base.rb +22 -5
  87. data/lib/mihari/analyzers/binaryedge.rb +0 -1
  88. data/lib/mihari/analyzers/censys.rb +7 -2
  89. data/lib/mihari/analyzers/circl.rb +1 -1
  90. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  91. data/lib/mihari/analyzers/rule.rb +43 -73
  92. data/lib/mihari/analyzers/virustotal_intelligence.rb +1 -2
  93. data/lib/mihari/clients/base.rb +1 -1
  94. data/lib/mihari/commands/database.rb +12 -11
  95. data/lib/mihari/commands/rule.rb +47 -45
  96. data/lib/mihari/commands/search.rb +73 -45
  97. data/lib/mihari/commands/version.rb +8 -6
  98. data/lib/mihari/commands/web.rb +26 -23
  99. data/lib/mihari/emitters/base.rb +14 -1
  100. data/lib/mihari/emitters/database.rb +3 -10
  101. data/lib/mihari/emitters/misp.rb +16 -5
  102. data/lib/mihari/emitters/slack.rb +13 -15
  103. data/lib/mihari/emitters/the_hive.rb +17 -19
  104. data/lib/mihari/emitters/webhook.rb +23 -23
  105. data/lib/mihari/enrichers/whois.rb +1 -0
  106. data/lib/mihari/entities/rule.rb +1 -1
  107. data/lib/mihari/entities/tag.rb +1 -1
  108. data/lib/mihari/feed/parser.rb +1 -0
  109. data/lib/mihari/feed/reader.rb +29 -14
  110. data/lib/mihari/mixins/configurable.rb +13 -4
  111. data/lib/mihari/schemas/analyzer.rb +2 -7
  112. data/lib/mihari/schemas/rule.rb +1 -1
  113. data/lib/mihari/structs/censys.rb +96 -82
  114. data/lib/mihari/structs/config.rb +46 -21
  115. data/lib/mihari/structs/google_public_dns.rb +27 -23
  116. data/lib/mihari/structs/greynoise.rb +44 -38
  117. data/lib/mihari/structs/onyphe.rb +34 -30
  118. data/lib/mihari/structs/rule.rb +1 -1
  119. data/lib/mihari/structs/shodan.rb +77 -69
  120. data/lib/mihari/structs/urlscan.rb +42 -36
  121. data/lib/mihari/structs/virustotal_intelligence.rb +57 -49
  122. data/lib/mihari/type_checker.rb +10 -8
  123. data/lib/mihari/version.rb +1 -1
  124. data/lib/mihari/web/public/assets/index-ac4e5ffa.js +50 -0
  125. data/lib/mihari/web/public/index.html +1 -1
  126. data/mihari.gemspec +8 -8
  127. metadata +103 -22
  128. data/.gitmodules +0 -0
  129. data/.overcommit.yml +0 -12
  130. data/lib/mihari/web/public/assets/index-cbe1734c.js +0 -50
@@ -121,11 +121,16 @@ module Mihari
121
121
  # @return [String]
122
122
  attr_reader :username
123
123
 
124
- def initialize(*args, **kwargs)
125
- super(*args, **kwargs)
124
+ #
125
+ # @param [Array<Mihari::Artifact>] artifacts
126
+ # @param [Mihari::Structs::Rule] rule
127
+ # @param [Hash] **_options
128
+ #
129
+ def initialize(artifacts:, rule:, **options)
130
+ super(artifacts: artifacts, rule: rule, **options)
126
131
 
127
- @webhook_url = kwargs[:webhook_url] || Mihari.config.slack_webhook_url
128
- @channel = kwargs[:channel] || Mihari.config.slack_channel || DEFAULT_CHANNEL
132
+ @webhook_url = options[:webhook_url] || Mihari.config.slack_webhook_url
133
+ @channel = options[:channel] || Mihari.config.slack_channel || DEFAULT_CHANNEL
129
134
  @username = DEFAULT_USERNAME
130
135
  end
131
136
 
@@ -152,13 +157,11 @@ module Mihari
152
157
  end
153
158
 
154
159
  #
155
- # Build attachements
156
- #
157
- # @param [Array<Mihari::Artifact>] artifacts
160
+ # Build attachments
158
161
  #
159
162
  # @return [Array<Mihari::Emitters::Attachment>]
160
163
  #
161
- def to_attachments(artifacts)
164
+ def attachments
162
165
  artifacts.map do |artifact|
163
166
  Attachment.new(data: artifact.data, data_type: artifact.data_type).to_a
164
167
  end.flatten
@@ -167,11 +170,9 @@ module Mihari
167
170
  #
168
171
  # Build a text
169
172
  #
170
- # @param [Mihari::Structs::Rule] rule
171
- #
172
173
  # @return [String]
173
174
  #
174
- def to_text(rule)
175
+ def text
175
176
  tags = rule.tags
176
177
  tags = ["N/A"] if tags.empty?
177
178
 
@@ -182,12 +183,9 @@ module Mihari
182
183
  ].join("\n")
183
184
  end
184
185
 
185
- def emit(rule:, artifacts:, **_options)
186
+ def emit
186
187
  return if artifacts.empty?
187
188
 
188
- attachments = to_attachments(artifacts)
189
- text = to_text(rule)
190
-
191
189
  notifier.post(text: text, attachments: attachments, mrkdwn: true)
192
190
  end
193
191
 
@@ -12,12 +12,17 @@ module Mihari
12
12
  # @return [String, nil]
13
13
  attr_reader :api_version
14
14
 
15
- def initialize(*args, **kwargs)
16
- super(*args, **kwargs)
15
+ #
16
+ # @param [Array<Mihari::Artifact>] artifacts
17
+ # @param [Mihari::Structs::Rule] rule
18
+ # @param [Hash] **options
19
+ #
20
+ def initialize(artifacts:, rule:, **options)
21
+ super(artifacts: artifacts, rule: rule, **options)
17
22
 
18
- @url = kwargs[:url] || Mihari.config.thehive_url
19
- @api_key = kwargs[:api_key] || Mihari.config.thehive_api_key
20
- @api_version = kwargs[:api_version] || Mihari.config.thehive_api_version
23
+ @url = options[:url] || Mihari.config.thehive_url
24
+ @api_key = options[:api_key] || Mihari.config.thehive_api_key
25
+ @api_version = options[:api_version] || Mihari.config.thehive_api_version
21
26
  end
22
27
 
23
28
  # @return [Boolean]
@@ -39,15 +44,11 @@ module Mihari
39
44
  #
40
45
  # Create a Hive alert
41
46
  #
42
- # @param [Arra<Mihari::Artifact>] artifacts
43
- # @param [Mihari::Structs::Rule] rule
44
- #
45
47
  # @return [::MISP::Event]
46
48
  #
47
- def emit(rule:, artifacts:, **_options)
49
+ def emit
48
50
  return if artifacts.empty?
49
51
 
50
- payload = payload(rule: rule, artifacts: artifacts)
51
52
  client.alert(payload)
52
53
  end
53
54
 
@@ -102,18 +103,15 @@ module Mihari
102
103
  #
103
104
  # Build payload for alert
104
105
  #
105
- # @param [Arra<Mihari::Artifact>] artifacts
106
- # @param [Mihari::Structs::Rule] rule
107
- #
108
- # @return [<Type>] <description>
106
+ # @return [Hash]
109
107
  #
110
- def payload(rule:, artifacts:)
111
- return v4_payload(rule: rule, artifacts: artifacts) if normalized_api_version.nil?
108
+ def payload
109
+ return v4_payload if normalized_api_version.nil?
112
110
 
113
- v5_payload(rule: rule, artifacts: artifacts)
111
+ v5_payload
114
112
  end
115
113
 
116
- def v4_payload(rule:, artifacts:)
114
+ def v4_payload
117
115
  {
118
116
  title: rule.title,
119
117
  description: rule.description,
@@ -130,7 +128,7 @@ module Mihari
130
128
  }
131
129
  end
132
130
 
133
- def v5_payload(rule:, artifacts:)
131
+ def v5_payload
134
132
  {
135
133
  title: rule.title,
136
134
  description: rule.description,
@@ -55,30 +55,26 @@ module Mihari
55
55
  # @return [String, nil]
56
56
  attr_reader :template
57
57
 
58
- def initialize(*args, **kwargs)
59
- super(*args, **kwargs)
60
-
61
- url = kwargs[:url]
62
- headers = kwargs[:headers] || {}
63
- method = kwargs[:method] || "POST"
64
- template = kwargs[:template]
65
-
66
- @url = Addressable::URI.parse(url)
67
- @headers = headers
68
- @method = method
69
- @template = template
58
+ #
59
+ # @param [Array<Mihari::Artifact>] artifacts
60
+ # @param [Mihari::Structs::Rule] rule
61
+ # @param [Hash] **options
62
+ #
63
+ def initialize(artifacts:, rule:, **options)
64
+ super(artifacts: artifacts, rule: rule, **options)
65
+
66
+ @url = Addressable::URI.parse(options[:url])
67
+ @headers = options[:headers] || {}
68
+ @method = options[:method] || "POST"
69
+ @template = options[:template]
70
70
  end
71
71
 
72
- def emit(artifacts:, rule:)
72
+ def emit
73
73
  return if artifacts.empty?
74
74
 
75
- res = nil
76
-
77
- payload_ = payload_as_string(artifacts: artifacts, rule: rule)
78
- payload = JSON.parse(payload_)
79
-
80
75
  client = Mihari::HTTP.new(url, headers: headers)
81
76
 
77
+ res = nil
82
78
  case method
83
79
  when "GET"
84
80
  res = client.get
@@ -100,13 +96,10 @@ module Mihari
100
96
  #
101
97
  # Convert payload into string
102
98
  #
103
- # @param [Array<Mihari::Artifact>] artifacts
104
- # @param [Mihari::Structs::Rule] rule
105
- #
106
99
  # @return [String]
107
100
  #
108
- def payload_as_string(artifacts:, rule:)
109
- @payload_as_string ||= [].tap do |out|
101
+ def payload_as_string
102
+ [].tap do |out|
110
103
  options = {}
111
104
  options[:template] = File.read(template) unless template.nil?
112
105
 
@@ -118,6 +111,13 @@ module Mihari
118
111
  out << payload_template.result
119
112
  end.first
120
113
  end
114
+
115
+ #
116
+ # @return [Hash]
117
+ #
118
+ def payload
119
+ JSON.parse payload_as_string
120
+ end
121
121
  end
122
122
  end
123
123
  end
@@ -5,6 +5,7 @@ require "whois-parser"
5
5
  module Mihari
6
6
  module Enrichers
7
7
  class Whois < Base
8
+ # @type [Hash]
8
9
  @memo = {}
9
10
 
10
11
  # @return [Boolean]
@@ -31,7 +31,7 @@ module Mihari
31
31
  end
32
32
 
33
33
  class RuleIDs < Grape::Entity
34
- expose :rule_ids, documentation: { type: Array[String], required: true }, as: :ruleIds
34
+ expose :rule_ids, documentation: { type: [String], required: true }, as: :ruleIds
35
35
  end
36
36
  end
37
37
  end
@@ -7,7 +7,7 @@ module Mihari
7
7
  end
8
8
 
9
9
  class Tags < Grape::Entity
10
- expose :tags, documentation: { type: Array[String], required: true }
10
+ expose :tags, documentation: { type: [String], required: true }
11
11
  end
12
12
  end
13
13
  end
@@ -5,6 +5,7 @@ require "jr/cli/core_ext"
5
5
  module Mihari
6
6
  module Feed
7
7
  class Parser
8
+ # @return [Array<Hash>, Array<Array<String>>]
8
9
  attr_reader :data
9
10
 
10
11
  #
@@ -6,7 +6,23 @@ require "insensitive_hash"
6
6
  module Mihari
7
7
  module Feed
8
8
  class Reader
9
- attr_reader :url, :headers, :params, :json, :data, :method
9
+ # @return [String]
10
+ attr_reader :url
11
+
12
+ # @return [Hash]
13
+ attr_reader :headers
14
+
15
+ # @return [Hash, nil]
16
+ attr_reader :params
17
+
18
+ # @return [Hash, nil]
19
+ attr_reader :json
20
+
21
+ # @return [Hash, nil]
22
+ attr_reader :data
23
+
24
+ # @return [String]
25
+ attr_reader :method
10
26
 
11
27
  def initialize(url, headers: {}, method: "GET", params: nil, json: nil, data: nil)
12
28
  @url = Addressable::URI.parse(url)
@@ -20,6 +36,9 @@ module Mihari
20
36
  headers["content-type"] = "application/json" unless json.nil?
21
37
  end
22
38
 
39
+ #
40
+ # @return [Array<Hash>]
41
+ #
23
42
  def read
24
43
  return read_file(url.path) if url.scheme == "file"
25
44
 
@@ -33,11 +52,9 @@ module Mihari
33
52
 
34
53
  body = res.body
35
54
  content_type = res["Content-Type"].to_s
36
- if content_type.include?("application/json")
37
- convert_as_json(body)
38
- else
39
- convert_as_csv(body)
40
- end
55
+ return convert_as_json(body) if content_type.include?("application/json")
56
+
57
+ convert_as_csv(body)
41
58
  end
42
59
 
43
60
  #
@@ -48,10 +65,10 @@ module Mihari
48
65
  # @return [Array<Hash>]
49
66
  #
50
67
  def convert_as_json(text)
51
- data = JSON.parse(text, symbolize_names: true)
52
- return data if data.is_a?(Array)
68
+ parsed = JSON.parse(text, symbolize_names: true)
69
+ return parsed if parsed.is_a?(Array)
53
70
 
54
- [data]
71
+ [parsed]
55
72
  end
56
73
 
57
74
  #
@@ -77,11 +94,9 @@ module Mihari
77
94
  def read_file(path)
78
95
  text = File.read(path)
79
96
 
80
- if path.end_with?(".json")
81
- convert_as_json text
82
- else
83
- convert_as_csv text
84
- end
97
+ return convert_as_json(text) if path.end_with?(".json")
98
+
99
+ convert_as_csv text
85
100
  end
86
101
  end
87
102
  end
@@ -4,14 +4,23 @@ module Mihari
4
4
  module Mixins
5
5
  module Configurable
6
6
  #
7
- # Check whether it is configured or not
7
+ # Check whether there are configuration key-values or not
8
8
  #
9
9
  # @return [Boolean]
10
10
  #
11
- def configured?
11
+ def configuration_keys?
12
12
  return true if configuration_keys.empty?
13
13
 
14
- configuration_keys.all? { |key| Mihari.config.send(key) } || api_key?
14
+ configuration_keys.all? { |key| Mihari.config.send(key) }
15
+ end
16
+
17
+ #
18
+ # Check whether it is configured or not
19
+ #
20
+ # @return [Boolean]
21
+ #
22
+ def configured?
23
+ configuration_keys? || api_key?
15
24
  end
16
25
 
17
26
  #
@@ -32,7 +41,7 @@ module Mihari
32
41
  #
33
42
  # Configuration keys
34
43
  #
35
- # @return [Array<String>] A list of cofiguration keys
44
+ # @return [Array<String>] A list of configuration keys
36
45
  #
37
46
  def configuration_keys
38
47
  []
@@ -7,7 +7,7 @@ module Mihari
7
7
  end
8
8
 
9
9
  AnalyzerWithoutAPIKey = Dry::Schema.Params do
10
- required(:analyzer).value(Types::String.enum("crtsh", "dnpedia", "dnstwister"))
10
+ required(:analyzer).value(Types::String.enum("dnstwister"))
11
11
  required(:query).value(:string)
12
12
  optional(:options).hash(AnalyzerOptions)
13
13
  end
@@ -23,6 +23,7 @@ module Mihari
23
23
  "securitytrails",
24
24
  "shodan",
25
25
  "st",
26
+ "urlscan",
26
27
  "virustotal_intelligence",
27
28
  "virustotal",
28
29
  "vt_intel",
@@ -72,12 +73,6 @@ module Mihari
72
73
  optional(:options).hash(AnalyzerOptions)
73
74
  end
74
75
 
75
- Urlscan = Dry::Schema.Params do
76
- required(:analyzer).value(Types::String.enum("urlscan"))
77
- required(:query).value(:string)
78
- optional(:options).hash(AnalyzerOptions)
79
- end
80
-
81
76
  Feed = Dry::Schema.Params do
82
77
  required(:analyzer).value(Types::String.enum("feed"))
83
78
  required(:query).value(:string)
@@ -22,7 +22,7 @@ module Mihari
22
22
  optional(:updated_on).value(:date)
23
23
 
24
24
  required(:queries).value(:array).each do
25
- AnalyzerWithoutAPIKey | AnalyzerWithAPIKey | Censys | CIRCL | PassiveTotal | ZoomEye | Urlscan | Crtsh | Feed
25
+ AnalyzerWithoutAPIKey | AnalyzerWithAPIKey | Censys | CIRCL | PassiveTotal | ZoomEye | Crtsh | Feed
26
26
  end
27
27
 
28
28
  optional(:emitters).value(:array).each { Database | MISP | TheHive | Slack | Webhook }.default(DEFAULT_EMITTERS)
@@ -22,16 +22,18 @@ module Mihari
22
22
  Mihari::AutonomousSystem.new(asn: normalize_asn(asn))
23
23
  end
24
24
 
25
- #
26
- # @param [Hash] d
27
- #
28
- # @return [AutonomousSystem]
29
- #
30
- def self.from_dynamic!(d)
31
- d = Types::Hash[d]
32
- new(
33
- asn: d.fetch("asn")
34
- )
25
+ class << self
26
+ #
27
+ # @param [Hash] d
28
+ #
29
+ # @return [AutonomousSystem]
30
+ #
31
+ def from_dynamic!(d)
32
+ d = Types::Hash[d]
33
+ new(
34
+ asn: d.fetch("asn")
35
+ )
36
+ end
35
37
  end
36
38
  end
37
39
 
@@ -67,17 +69,19 @@ module Mihari
67
69
  )
68
70
  end
69
71
 
70
- #
71
- # @param [Hash] d
72
- #
73
- # @return [Location]
74
- #
75
- def self.from_dynamic!(d)
76
- d = Types::Hash[d]
77
- new(
78
- country: d["country"],
79
- country_code: d["country_code"]
80
- )
72
+ class << self
73
+ #
74
+ # @param [Hash] d
75
+ #
76
+ # @return [Location]
77
+ #
78
+ def from_dynamic!(d)
79
+ d = Types::Hash[d]
80
+ new(
81
+ country: d["country"],
82
+ country_code: d["country_code"]
83
+ )
84
+ end
81
85
  end
82
86
  end
83
87
 
@@ -98,16 +102,18 @@ module Mihari
98
102
  Port.new(port: port)
99
103
  end
100
104
 
101
- #
102
- # @param [Hash] d
103
- #
104
- # @return [Service]
105
- #
106
- def self.from_dynamic!(d)
107
- d = Types::Hash[d]
108
- new(
109
- port: d.fetch("port")
110
- )
105
+ class << self
106
+ #
107
+ # @param [Hash] d
108
+ #
109
+ # @return [Service]
110
+ #
111
+ def from_dynamic!(d)
112
+ d = Types::Hash[d]
113
+ new(
114
+ port: d.fetch("port")
115
+ )
116
+ end
111
117
  end
112
118
  end
113
119
 
@@ -173,20 +179,22 @@ module Mihari
173
179
  )
174
180
  end
175
181
 
176
- #
177
- # @param [Hash] d
178
- #
179
- # @return [Hit]
180
- #
181
- def self.from_dynamic!(d)
182
- d = Types::Hash[d]
183
- new(
184
- ip: d.fetch("ip"),
185
- location: Location.from_dynamic!(d.fetch("location")),
186
- autonomous_system: AutonomousSystem.from_dynamic!(d.fetch("autonomous_system")),
187
- metadata: d,
188
- services: d.fetch("services", []).map { |x| Service.from_dynamic!(x) }
189
- )
182
+ class << self
183
+ #
184
+ # @param [Hash] d
185
+ #
186
+ # @return [Hit]
187
+ #
188
+ def from_dynamic!(d)
189
+ d = Types::Hash[d]
190
+ new(
191
+ ip: d.fetch("ip"),
192
+ location: Location.from_dynamic!(d.fetch("location")),
193
+ autonomous_system: AutonomousSystem.from_dynamic!(d.fetch("autonomous_system")),
194
+ metadata: d,
195
+ services: d.fetch("services", []).map { |x| Service.from_dynamic!(x) }
196
+ )
197
+ end
190
198
  end
191
199
  end
192
200
 
@@ -208,17 +216,19 @@ module Mihari
208
216
  attributes[:prev]
209
217
  end
210
218
 
211
- #
212
- # @param [Hash] d
213
- #
214
- # @return [Links]
215
- #
216
- def self.from_dynamic!(d)
217
- d = Types::Hash[d]
218
- new(
219
- next: d["next"],
220
- prev: d["prev"]
221
- )
219
+ class << self
220
+ #
221
+ # @param [Hash] d
222
+ #
223
+ # @return [Links]
224
+ #
225
+ def from_dynamic!(d)
226
+ d = Types::Hash[d]
227
+ new(
228
+ next: d["next"],
229
+ prev: d["prev"]
230
+ )
231
+ end
222
232
  end
223
233
  end
224
234
 
@@ -260,22 +270,24 @@ module Mihari
260
270
  # @return [Array<Mihari::Artifact>]
261
271
  #
262
272
  def to_artifacts
263
- hits.map { |hit| hit.to_artifact }
273
+ hits.map(&:to_artifact)
264
274
  end
265
275
 
266
- #
267
- # @param [Hash] d
268
- #
269
- # @return [Result]
270
- #
271
- def self.from_dynamic!(d)
272
- d = Types::Hash[d]
273
- new(
274
- query: d.fetch("query"),
275
- total: d.fetch("total"),
276
- hits: d.fetch("hits", []).map { |x| Hit.from_dynamic!(x) },
277
- links: Links.from_dynamic!(d.fetch("links"))
278
- )
276
+ class << self
277
+ #
278
+ # @param [Hash] d
279
+ #
280
+ # @return [Result]
281
+ #
282
+ def from_dynamic!(d)
283
+ d = Types::Hash[d]
284
+ new(
285
+ query: d.fetch("query"),
286
+ total: d.fetch("total"),
287
+ hits: d.fetch("hits", []).map { |x| Hit.from_dynamic!(x) },
288
+ links: Links.from_dynamic!(d.fetch("links"))
289
+ )
290
+ end
279
291
  end
280
292
  end
281
293
 
@@ -305,18 +317,20 @@ module Mihari
305
317
  attributes[:result]
306
318
  end
307
319
 
308
- #
309
- # @param [Hash] d
310
- #
311
- # @return [Response]
312
- #
313
- def self.from_dynamic!(d)
314
- d = Types::Hash[d]
315
- new(
316
- code: d.fetch("code"),
317
- status: d.fetch("status"),
318
- result: Result.from_dynamic!(d.fetch("result"))
319
- )
320
+ class << self
321
+ #
322
+ # @param [Hash] d
323
+ #
324
+ # @return [Response]
325
+ #
326
+ def from_dynamic!(d)
327
+ d = Types::Hash[d]
328
+ new(
329
+ code: d.fetch("code"),
330
+ status: d.fetch("status"),
331
+ result: Result.from_dynamic!(d.fetch("result"))
332
+ )
333
+ end
320
334
  end
321
335
  end
322
336
  end