mihari 7.1.2 → 7.2.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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +1 -1
  3. data/Rakefile +15 -7
  4. data/build_frontend.sh +1 -1
  5. data/lefthook.yml +4 -1
  6. data/lib/mihari/actor.rb +21 -4
  7. data/lib/mihari/analyzers/base.rb +7 -18
  8. data/lib/mihari/analyzers/binaryedge.rb +0 -6
  9. data/lib/mihari/analyzers/censys.rb +0 -9
  10. data/lib/mihari/analyzers/circl.rb +0 -6
  11. data/lib/mihari/analyzers/fofa.rb +0 -6
  12. data/lib/mihari/analyzers/greynoise.rb +0 -6
  13. data/lib/mihari/analyzers/hunterhow.rb +0 -6
  14. data/lib/mihari/analyzers/onyphe.rb +0 -6
  15. data/lib/mihari/analyzers/otx.rb +0 -6
  16. data/lib/mihari/analyzers/passivetotal.rb +0 -4
  17. data/lib/mihari/analyzers/pulsedive.rb +0 -6
  18. data/lib/mihari/analyzers/securitytrails.rb +0 -4
  19. data/lib/mihari/analyzers/shodan.rb +0 -6
  20. data/lib/mihari/analyzers/urlscan.rb +0 -6
  21. data/lib/mihari/analyzers/virustotal.rb +0 -4
  22. data/lib/mihari/analyzers/virustotal_intelligence.rb +7 -6
  23. data/lib/mihari/analyzers/zoomeye.rb +0 -6
  24. data/lib/mihari/commands/web.rb +4 -4
  25. data/lib/mihari/concerns/falsepositive_normalizable.rb +30 -0
  26. data/lib/mihari/concerns/falsepositive_validatable.rb +1 -17
  27. data/lib/mihari/config.rb +1 -1
  28. data/lib/mihari/database.rb +18 -1
  29. data/lib/mihari/emitters/database.rb +0 -6
  30. data/lib/mihari/emitters/misp.rb +0 -6
  31. data/lib/mihari/emitters/slack.rb +5 -21
  32. data/lib/mihari/emitters/the_hive.rb +0 -6
  33. data/lib/mihari/enrichers/whois.rb +5 -7
  34. data/lib/mihari/entities/artifact.rb +6 -2
  35. data/lib/mihari/entities/autonomous_system.rb +1 -1
  36. data/lib/mihari/entities/cpe.rb +1 -1
  37. data/lib/mihari/entities/port.rb +1 -1
  38. data/lib/mihari/entities/vulnerability.rb +10 -0
  39. data/lib/mihari/errors.rb +16 -1
  40. data/lib/mihari/models/artifact.rb +65 -30
  41. data/lib/mihari/models/vulnerability.rb +12 -0
  42. data/lib/mihari/rule.rb +18 -24
  43. data/lib/mihari/schemas/rule.rb +7 -0
  44. data/lib/mihari/services/builders.rb +22 -3
  45. data/lib/mihari/services/enrichers.rb +2 -0
  46. data/lib/mihari/services/feed.rb +2 -5
  47. data/lib/mihari/services/proxies.rb +3 -3
  48. data/lib/mihari/structs/censys.rb +2 -2
  49. data/lib/mihari/structs/config.rb +3 -20
  50. data/lib/mihari/structs/greynoise.rb +1 -1
  51. data/lib/mihari/structs/onyphe.rb +1 -1
  52. data/lib/mihari/structs/shodan.rb +59 -21
  53. data/lib/mihari/version.rb +1 -1
  54. data/lib/mihari/web/endpoints/artifacts.rb +4 -2
  55. data/lib/mihari/web/endpoints/rules.rb +1 -1
  56. data/lib/mihari/web/public/assets/{index-Guw2aMpk.js → index-GWurHG1o.js} +60 -40
  57. data/lib/mihari/web/public/assets/{index-dVaNxqTC.css → index-ReF8ffd-.css} +1 -1
  58. data/lib/mihari/web/public/index.html +2 -2
  59. data/lib/mihari/web/public/redoc-static.html +385 -385
  60. data/lib/mihari.rb +3 -0
  61. metadata +11 -51
  62. data/test.json.jbuilder +0 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 52d1c8320fdb5233c9738f3b4599868260fef892599cdfb42da6c3af17583b75
4
- data.tar.gz: 625cd92558eff5a4d5613e588cc5ee85b9b714a9af211788da1a294d8d54ac45
3
+ metadata.gz: 6b91d99562526b653b793f71e8ef5575f113d26859ca86b91f1980d1c44e898c
4
+ data.tar.gz: 07c302ce446b0f0986bfc82dd575ebde203f4b25b73a1aee72a2ce37a08b9b87
5
5
  SHA512:
6
- metadata.gz: 96811d3ebfffcb27a7577b814be280916dd46bd3477233374ffafd2bf784d9e5133f89b1d7650c722c25e2f678f82380f5ced2eff8f9b7e1f3c96583f54a1114
7
- data.tar.gz: 5c13581e670c7aff158e93335fe9c626294cad622f153e61a338f31bb5a1e459302f34a3a9ddf18e0bb322e1359c43a6b782387cdc800f9b047c04e5521f4c70
6
+ metadata.gz: 67d607a09ab2992b6721358b9e96e0c049a355221b2e97358440d70f96ef4933ac86b337bcc12bdc4b2aafccf4e5d6cf8cd68f4b2bbe567523bfba22b7fbd88c
7
+ data.tar.gz: 6f73de19824d31e21bae4ee7ce456c1b15fa0a875d1f07025c33ac0356ef257ac2eb819ffd8b685bf8914a472da04f691e5ae02a361397da9a83253d5345b108
data/Dockerfile CHANGED
@@ -2,7 +2,7 @@ FROM ruby:3.2.2-alpine3.19
2
2
 
3
3
  ARG MIHARI_VERSION=0.0.0
4
4
 
5
- RUN apk --no-cache add build-base ruby-dev libpq-dev && \
5
+ RUN apk --no-cache add build-base ruby-dev libpq-dev whois && \
6
6
  echo 'gem: --no-document' >> /usr/local/etc/gemrc && \
7
7
  gem install pg && \
8
8
  gem install mihari -v ${MIHARI_VERSION} && \
data/Rakefile CHANGED
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "time"
4
+
3
5
  require "rspec/core/rake_task"
4
6
  require "standard/rake"
5
7
 
@@ -46,18 +48,24 @@ namespace :build do
46
48
  desc "Build Swagger doc"
47
49
  task :swagger, [:path] do |_t, args|
48
50
  args.with_defaults(path: "./frontend/swagger.yaml")
51
+
52
+ started_at = Time.now
49
53
  build_swagger_doc args.path
54
+ elapsed = (Time.now - started_at).floor(2)
55
+
56
+ puts "Swagger doc is built in #{elapsed}s"
50
57
  end
51
58
  end
52
59
 
53
- def ci?
54
- ENV.fetch("CI", false)
55
- end
60
+ task :build do
61
+ Rake::Task["build:swagger"].invoke
56
62
 
57
- unless ci?
58
- task :build do
59
- sh "./build_frontend.sh"
60
- end
63
+ # Build ReDocs docs & frontend assets
64
+ sh "cd frontend && npm install && npm run docs && npm run build-only"
65
+ # Copy built assets into ./lib/web/public/
66
+ sh "rm -rf ./lib/mihari/web/public/"
67
+ sh "mkdir -p ./lib/mihari/web/public/"
68
+ sh "cp -r frontend/dist/* ./lib/mihari/web/public"
61
69
  end
62
70
 
63
71
  # require it later enables doing pre-build step (= build the frontend app)
data/build_frontend.sh CHANGED
@@ -3,7 +3,7 @@
3
3
  CURRENT_DIR=${PWD}
4
4
 
5
5
  cd frontend
6
- npm ci
6
+ npm install
7
7
  npm run build
8
8
 
9
9
  trash -r ${CURRENT_DIR}/lib/mihari/web/public/
data/lefthook.yml CHANGED
@@ -1,5 +1,4 @@
1
1
  pre-commit:
2
- parallel: true
3
2
  commands:
4
3
  standard:
5
4
  glob: "*.rb"
@@ -15,6 +14,10 @@ pre-commit:
15
14
  glob: "*.{js,ts,vue}"
16
15
  run: npx prettier --write {staged_files}
17
16
  stage_fixed: true
17
+ type-check:
18
+ root: "frontend/"
19
+ glob: "*.{js,ts,vue}"
20
+ run: npm run type-check
18
21
  actionlint:
19
22
  glob: ".github/workflows/*.yaml"
20
23
  run: actionlint
data/lib/mihari/actor.rb CHANGED
@@ -53,10 +53,10 @@ module Mihari
53
53
  def validate_configuration!
54
54
  return if configured?
55
55
 
56
- joined = self.class.configuration_keys.join(", ")
57
- be = (self.class.configuration_keys.length > 1) ? "are" : "is"
58
- message = "#{self.class.key} is not configured correctly. #{joined} #{be} missing."
59
- raise ConfigurationError, message
56
+ message = "#{self.class.type.capitalize}:#{self.class.key} is not configured correctly"
57
+ detail = self.class.configuration_keys.map { |key| "#{key.upcase} is missing" }
58
+
59
+ raise ConfigurationError.new(message, detail)
60
60
  end
61
61
 
62
62
  def call(*args, **kwargs)
@@ -92,6 +92,23 @@ module Mihari
92
92
  def keys
93
93
  ([key] + [key_aliases]).flatten.compact.map(&:downcase)
94
94
  end
95
+
96
+ def configuration_keys
97
+ # Automatically generate configuration keys based on key
98
+ # For example,
99
+ # - Shodan analyzer's key is "shodan"
100
+ # - Mihari.config has "shodan_api_key"
101
+ # - Select "shodan_api_key" by using "#{key}_" prefix
102
+ Mihari.config.keys.select { |config_key| config_key.start_with?("#{key}_") }
103
+ end
104
+
105
+ def type
106
+ return "analyzer" if ancestors.include?(Mihari::Analyzers::Base)
107
+ return "emitter" if ancestors.include?(Mihari::Emitters::Base)
108
+ return "enricher" if ancestors.include?(Mihari::Enrichers::Base)
109
+
110
+ nil
111
+ end
95
112
  end
96
113
  end
97
114
  end
@@ -63,12 +63,10 @@ module Mihari
63
63
  artifacts.compact.sort.map do |artifact|
64
64
  # No need to set data_type manually
65
65
  # It is set automatically in #initialize
66
- artifact = artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)
67
-
68
- artifact.source = self.class.key
69
- artifact.query = query
70
-
71
- artifact
66
+ (artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)).tap do |normalized|
67
+ normalized.source = self.class.key
68
+ normalized.query = query
69
+ end
72
70
  end.select(&:valid?).uniq(&:data)
73
71
  end
74
72
 
@@ -118,18 +116,9 @@ module Mihari
118
116
  #
119
117
  # @return [Mihari::Analyzers::Base]
120
118
  #
121
- def from_query(params)
122
- copied = params.deep_dup
123
-
124
- # convert params into arguments for initialization
125
- query = copied[:query]
126
-
127
- # delete analyzer and query
128
- %i[analyzer query].each { |key| copied.delete key }
129
-
130
- copied[:options] = copied[:options] || nil
131
-
132
- new(query, **copied)
119
+ def from_params(params)
120
+ query = params.delete(:query)
121
+ new(query, **params)
133
122
  end
134
123
 
135
124
  def inherited(child)
@@ -24,12 +24,6 @@ module Mihari
24
24
  client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
25
25
  end
26
26
 
27
- class << self
28
- def configuration_keys
29
- %w[binaryedge_api_key]
30
- end
31
- end
32
-
33
27
  private
34
28
 
35
29
  #
@@ -41,15 +41,6 @@ module Mihari
41
41
  configuration_keys? || (id? && secret?)
42
42
  end
43
43
 
44
- class << self
45
- #
46
- # @return [Array<String>]
47
- #
48
- def configuration_keys
49
- %w[censys_id censys_secret]
50
- end
51
- end
52
-
53
44
  private
54
45
 
55
46
  #
@@ -47,12 +47,6 @@ module Mihari
47
47
  configuration_keys? || (username? && password?)
48
48
  end
49
49
 
50
- class << self
51
- def configuration_keys
52
- %w[circl_passive_password circl_passive_username]
53
- end
54
- end
55
-
56
50
  private
57
51
 
58
52
  def client
@@ -35,12 +35,6 @@ module Mihari
35
35
  api_key? && email?
36
36
  end
37
37
 
38
- class << self
39
- def configuration_keys
40
- %w[fofa_api_key fofa_email]
41
- end
42
- end
43
-
44
38
  private
45
39
 
46
40
  def email?
@@ -27,12 +27,6 @@ module Mihari
27
27
  ).map(&:artifacts).flatten
28
28
  end
29
29
 
30
- class << self
31
- def configuration_keys
32
- %w[greynoise_api_key]
33
- end
34
- end
35
-
36
30
  private
37
31
 
38
32
  def client
@@ -44,12 +44,6 @@ module Mihari
44
44
  end.flatten
45
45
  end
46
46
 
47
- class << self
48
- def configuration_keys
49
- %w[hunterhow_api_key]
50
- end
51
- end
52
-
53
47
  private
54
48
 
55
49
  def client
@@ -29,12 +29,6 @@ module Mihari
29
29
  ).map(&:artifacts).flatten
30
30
  end
31
31
 
32
- class << self
33
- def configuration_keys
34
- %w[onyphe_api_key]
35
- end
36
- end
37
-
38
32
  private
39
33
 
40
34
  def client
@@ -38,12 +38,6 @@ module Mihari
38
38
  end
39
39
  end
40
40
 
41
- class << self
42
- def configuration_keys
43
- %w[otx_api_key]
44
- end
45
- end
46
-
47
41
  private
48
42
 
49
43
  def client
@@ -50,10 +50,6 @@ module Mihari
50
50
  end
51
51
 
52
52
  class << self
53
- def configuration_keys
54
- %w[passivetotal_username passivetotal_api_key]
55
- end
56
-
57
53
  #
58
54
  # @return [Array<String>, nil]
59
55
  #
@@ -43,12 +43,6 @@ module Mihari
43
43
  end
44
44
  end
45
45
 
46
- class << self
47
- def configuration_keys
48
- %w[pulsedive_api_key]
49
- end
50
- end
51
-
52
46
  private
53
47
 
54
48
  def client
@@ -44,10 +44,6 @@ module Mihari
44
44
  end
45
45
 
46
46
  class << self
47
- def configuration_keys
48
- %w[securitytrails_api_key]
49
- end
50
-
51
47
  #
52
48
  # @return [Array<String>, nil]
53
49
  #
@@ -27,12 +27,6 @@ module Mihari
27
27
  ).map(&:artifacts).flatten.uniq(&:data)
28
28
  end
29
29
 
30
- class << self
31
- def configuration_keys
32
- %w[shodan_api_key]
33
- end
34
- end
35
-
36
30
  private
37
31
 
38
32
  #
@@ -37,12 +37,6 @@ module Mihari
37
37
  artifacts.select { |artifact| allowed_data_types.include? artifact.data_type }
38
38
  end
39
39
 
40
- class << self
41
- def configuration_keys
42
- %w[urlscan_api_key]
43
- end
44
- end
45
-
46
40
  private
47
41
 
48
42
  def client
@@ -39,10 +39,6 @@ module Mihari
39
39
  end
40
40
 
41
41
  class << self
42
- def configuration_keys
43
- %w[virustotal_api_key]
44
- end
45
-
46
42
  #
47
43
  # @return [Array<String>, nil]
48
44
  #
@@ -24,12 +24,6 @@ module Mihari
24
24
  client.intel_search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
25
25
  end
26
26
 
27
- class << self
28
- def configuration_keys
29
- %w[virustotal_api_key]
30
- end
31
- end
32
-
33
27
  class << self
34
28
  #
35
29
  # @return [String]
@@ -44,6 +38,13 @@ module Mihari
44
38
  def key_aliases
45
39
  ["vt_intel"]
46
40
  end
41
+
42
+ #
43
+ # @return [Array<String>]
44
+ #
45
+ def configuration_keys
46
+ %w[virustotal_api_key]
47
+ end
47
48
  end
48
49
 
49
50
  private
@@ -40,12 +40,6 @@ module Mihari
40
40
  end
41
41
  end
42
42
 
43
- class << self
44
- def configuration_keys
45
- %w[zoomeye_api_key]
46
- end
47
- end
48
-
49
43
  private
50
44
 
51
45
  #
@@ -10,10 +10,10 @@ module Mihari
10
10
  def included(thor)
11
11
  thor.class_eval do
12
12
  desc "web", "Start the web app"
13
- method_option :port, type: :numeric, default: 9292, desc: "Hostname to listen on"
14
- method_option :host, type: :string, default: "localhost", desc: "Port to listen on"
15
- method_option :threads, type: :string, default: "0:5", desc: "min:max threads to use"
16
- method_option :verbose, type: :boolean, default: true, desc: "Report each request"
13
+ method_option :port, type: :numeric, default: 9292, desc: "Port to listen on"
14
+ method_option :host, type: :string, default: "localhost", desc: "Hostname to listen on"
15
+ method_option :threads, type: :string, default: "0:3", desc: "min:max threads to use"
16
+ method_option :verbose, type: :boolean, default: false, desc: "Don't report each request"
17
17
  method_option :worker_timeout, type: :numeric, default: 60, desc: "Worker timeout value (in seconds)"
18
18
  method_option :open, type: :boolean, default: true, desc: "Whether to open the app in browser or not"
19
19
  method_option :env, type: :string, default: "production", desc: "Environment"
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Concerns
5
+ #
6
+ # False positive normalizable concern
7
+ #
8
+ module FalsePositiveNormalizable
9
+ extend ActiveSupport::Concern
10
+
11
+ prepend MemoWise
12
+
13
+ #
14
+ # Normalize a falsepositive value
15
+ #
16
+ # @param [String] value
17
+ #
18
+ # @return [String, Regexp]
19
+ #
20
+ def normalize_falsepositive(value)
21
+ return value if !value.start_with?("/") || !value.end_with?("/")
22
+
23
+ # if a value is surrounded by slashes, take it as a regexp
24
+ value_without_slashes = value[1..-2]
25
+ Regexp.compile value_without_slashes.to_s
26
+ end
27
+ memo_wise :normalize_falsepositive
28
+ end
29
+ end
30
+ end
@@ -8,23 +8,7 @@ module Mihari
8
8
  module FalsePositiveValidatable
9
9
  extend ActiveSupport::Concern
10
10
 
11
- prepend MemoWise
12
-
13
- #
14
- # Normalize a falsepositive value
15
- #
16
- # @param [String] value
17
- #
18
- # @return [String, Regexp]
19
- #
20
- def normalize_falsepositive(value)
21
- return value if !value.start_with?("/") || !value.end_with?("/")
22
-
23
- # if a value is surrounded by slashes, take it as a regexp
24
- value_without_slashes = value[1..-2]
25
- Regexp.compile value_without_slashes.to_s
26
- end
27
- memo_wise :normalize_falsepositive
11
+ include FalsePositiveNormalizable
28
12
 
29
13
  #
30
14
  # Check whether a value is valid format as a disallowed data value
data/lib/mihari/config.rb CHANGED
@@ -170,7 +170,7 @@ module Mihari
170
170
  # @return [Array<String>]
171
171
  #
172
172
  def keys
173
- to_h.keys.map(&:to_s).map(&:upcase)
173
+ @keys ||= to_h.keys.map(&:to_s).map(&:downcase)
174
174
  end
175
175
  end
176
176
  end
@@ -104,11 +104,28 @@ class V7Schema < ActiveRecord::Migration[7.1]
104
104
  end
105
105
  end
106
106
 
107
+ class V72Schema < ActiveRecord::Migration[7.1]
108
+ def change
109
+ create_table :vulnerabilities, if_not_exists: true do |t|
110
+ t.string :name, null: false
111
+ t.datetime :created_at
112
+
113
+ t.belongs_to :artifact, foreign_key: true, null: false
114
+ end
115
+
116
+ rename_column :cpes, :cpe, :name if ActiveRecord::Base.connection.column_exists?(:cpes, :cpe)
117
+ rename_column :autonomous_systems, :asn, :number if ActiveRecord::Base.connection.column_exists?(
118
+ :autonomous_systems, :asn
119
+ )
120
+ rename_column :ports, :port, :number if ActiveRecord::Base.connection.column_exists?(:ports, :port)
121
+ end
122
+ end
123
+
107
124
  #
108
125
  # @return [Array<ActiveRecord::Migration>] schemas
109
126
  #
110
127
  def schemas
111
- [V7Schema]
128
+ [V7Schema, V72Schema]
112
129
  end
113
130
 
114
131
  module Mihari
@@ -24,12 +24,6 @@ module Mihari
24
24
  def target
25
25
  Mihari.config.database_url.host || Mihari.config.database_url.to_s
26
26
  end
27
-
28
- class << self
29
- def configuration_keys
30
- %w[database_url]
31
- end
32
- end
33
27
  end
34
28
  end
35
29
  end
@@ -63,12 +63,6 @@ module Mihari
63
63
  URI(url).host || "N/A"
64
64
  end
65
65
 
66
- class << self
67
- def configuration_keys
68
- %w[misp_url misp_api_key]
69
- end
70
- end
71
-
72
66
  private
73
67
 
74
68
  def client
@@ -176,21 +176,11 @@ module Mihari
176
176
  # @return [::Slack::Notifier]
177
177
  #
178
178
  def notifier
179
- @notifier ||= [].tap do |out|
180
- out << if timeout.nil?
181
- ::Slack::Notifier.new(
182
- webhook_url,
183
- channel: channel, username: username
184
- )
185
- else
186
- ::Slack::Notifier.new(
187
- webhook_url,
188
- channel: channel,
189
- username: username,
190
- http_options: { timeout: timeout }
191
- )
192
- end
193
- end.first
179
+ @notifier ||= lambda do
180
+ return ::Slack::Notifier.new(webhook_url, channel: channel, username: username) if timeout.nil?
181
+
182
+ ::Slack::Notifier.new(webhook_url, channel: channel, username: username, http_options: { timeout: timeout })
183
+ end.call
194
184
  end
195
185
 
196
186
  #
@@ -227,12 +217,6 @@ module Mihari
227
217
 
228
218
  notifier.post(text: text, attachments: attachments, mrkdwn: true)
229
219
  end
230
-
231
- class << self
232
- def configuration_keys
233
- %w[slack_webhook_url slack_channel]
234
- end
235
- end
236
220
  end
237
221
  end
238
222
  end
@@ -53,12 +53,6 @@ module Mihari
53
53
  client.alert payload
54
54
  end
55
55
 
56
- class << self
57
- def configuration_keys
58
- %w[thehive_url thehive_api_key]
59
- end
60
- end
61
-
62
56
  private
63
57
 
64
58
  def client
@@ -53,13 +53,11 @@ module Mihari
53
53
  # @return [::Whois::Client]
54
54
  #
55
55
  def whois
56
- @whois ||= [].tap do |out|
57
- out << if timeout.nil?
58
- ::Whois::Client.new
59
- else
60
- ::Whois::Client.new(timeout: timeout)
61
- end
62
- end.last
56
+ @whois ||= lambda do
57
+ return ::Whois::Client.new if timeout.nil?
58
+
59
+ ::Whois::Client.new(timeout: timeout)
60
+ end.call
63
61
  end
64
62
 
65
63
  #
@@ -8,12 +8,12 @@ module Mihari
8
8
  expose :data_type, documentation: { type: String, required: true }, as: :dataType
9
9
  expose :source, documentation: { type: String, required: true }
10
10
  expose :query, documentation: { type: String, required: false }
11
- expose :metadata, documentation: { type: Hash }
12
11
  expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
12
+ expose :tags, using: Entities::Tag, documentation: { type: Entities::Tag, is_array: true, required: true }
13
13
  end
14
14
 
15
15
  class Artifact < BaseArtifact
16
- expose :tags, using: Entities::Tag, documentation: { type: Entities::Tag, is_array: true, required: true }
16
+ expose :metadata, documentation: { type: Hash }
17
17
  expose :autonomous_system, using: Entities::AutonomousSystem,
18
18
  documentation: { type: Entities::AutonomousSystem, required: false }, as: :autonomousSystem
19
19
  expose :geolocation, using: Entities::Geolocation, documentation: { type: Entities::Geolocation, required: false }
@@ -36,6 +36,10 @@ module Mihari
36
36
  as: :ports do |status, _options|
37
37
  status.ports.empty? ? nil : status.ports
38
38
  end
39
+ expose :vulnerabilities, using: Vulnerability, documentation: { type: Vulnerability, is_array: true, required: false },
40
+ as: :vulnerabilities do |status, _options|
41
+ status.vulnerabilities.empty? ? nil : status.vulnerabilities
42
+ end
39
43
  end
40
44
 
41
45
  class ArtifactsWithPagination < Pagination
@@ -3,7 +3,7 @@
3
3
  module Mihari
4
4
  module Entities
5
5
  class AutonomousSystem < Grape::Entity
6
- expose :asn, documentation: { type: Integer, required: true }
6
+ expose :number, documentation: { type: Integer, required: true }
7
7
  end
8
8
  end
9
9
  end
@@ -3,7 +3,7 @@
3
3
  module Mihari
4
4
  module Entities
5
5
  class CPE < Grape::Entity
6
- expose :cpe, documentation: { type: String, required: true }
6
+ expose :name, documentation: { type: String, required: true }
7
7
  expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
8
8
  end
9
9
  end