mihari 7.1.3 → 7.3.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 (73) hide show
  1. checksums.yaml +4 -4
  2. data/Dockerfile +2 -2
  3. data/Rakefile +8 -1
  4. data/lefthook.yml +4 -1
  5. data/lib/mihari/actor.rb +16 -0
  6. data/lib/mihari/analyzers/base.rb +7 -25
  7. data/lib/mihari/analyzers/binaryedge.rb +0 -6
  8. data/lib/mihari/analyzers/censys.rb +0 -9
  9. data/lib/mihari/analyzers/circl.rb +0 -6
  10. data/lib/mihari/analyzers/fofa.rb +0 -6
  11. data/lib/mihari/analyzers/greynoise.rb +0 -6
  12. data/lib/mihari/analyzers/hunterhow.rb +0 -6
  13. data/lib/mihari/analyzers/onyphe.rb +0 -6
  14. data/lib/mihari/analyzers/otx.rb +0 -6
  15. data/lib/mihari/analyzers/passivetotal.rb +0 -4
  16. data/lib/mihari/analyzers/pulsedive.rb +0 -6
  17. data/lib/mihari/analyzers/securitytrails.rb +0 -4
  18. data/lib/mihari/analyzers/shodan.rb +0 -6
  19. data/lib/mihari/analyzers/urlscan.rb +0 -6
  20. data/lib/mihari/analyzers/virustotal.rb +0 -4
  21. data/lib/mihari/analyzers/virustotal_intelligence.rb +7 -6
  22. data/lib/mihari/analyzers/zoomeye.rb +0 -6
  23. data/lib/mihari/commands/web.rb +1 -1
  24. data/lib/mihari/concerns/falsepositive_normalizable.rb +30 -0
  25. data/lib/mihari/concerns/falsepositive_validatable.rb +1 -17
  26. data/lib/mihari/config.rb +1 -1
  27. data/lib/mihari/database.rb +18 -1
  28. data/lib/mihari/emitters/database.rb +0 -6
  29. data/lib/mihari/emitters/misp.rb +0 -6
  30. data/lib/mihari/emitters/slack.rb +5 -21
  31. data/lib/mihari/emitters/the_hive.rb +0 -6
  32. data/lib/mihari/enrichers/base.rb +54 -12
  33. data/lib/mihari/enrichers/google_public_dns.rb +28 -7
  34. data/lib/mihari/enrichers/mmdb.rb +25 -7
  35. data/lib/mihari/enrichers/shodan.rb +35 -4
  36. data/lib/mihari/enrichers/whois.rb +37 -31
  37. data/lib/mihari/entities/artifact.rb +6 -2
  38. data/lib/mihari/entities/autonomous_system.rb +1 -1
  39. data/lib/mihari/entities/cpe.rb +1 -1
  40. data/lib/mihari/entities/port.rb +1 -1
  41. data/lib/mihari/entities/vulnerability.rb +10 -0
  42. data/lib/mihari/errors.rb +2 -0
  43. data/lib/mihari/models/alert.rb +12 -0
  44. data/lib/mihari/models/artifact.rb +118 -159
  45. data/lib/mihari/models/rule.rb +21 -0
  46. data/lib/mihari/models/vulnerability.rb +12 -0
  47. data/lib/mihari/rule.rb +44 -29
  48. data/lib/mihari/schemas/alert.rb +3 -3
  49. data/lib/mihari/schemas/analyzer.rb +27 -27
  50. data/lib/mihari/schemas/emitter.rb +9 -9
  51. data/lib/mihari/schemas/macros.rb +2 -2
  52. data/lib/mihari/schemas/options.rb +2 -5
  53. data/lib/mihari/schemas/rule.rb +19 -12
  54. data/lib/mihari/services/builders.rb +0 -134
  55. data/lib/mihari/services/enrichers.rb +3 -1
  56. data/lib/mihari/services/feed.rb +2 -5
  57. data/lib/mihari/services/getters.rb +1 -1
  58. data/lib/mihari/services/proxies.rb +3 -3
  59. data/lib/mihari/structs/censys.rb +2 -2
  60. data/lib/mihari/structs/greynoise.rb +1 -1
  61. data/lib/mihari/structs/onyphe.rb +1 -1
  62. data/lib/mihari/structs/shodan.rb +59 -21
  63. data/lib/mihari/version.rb +1 -1
  64. data/lib/mihari/web/endpoints/artifacts.rb +4 -2
  65. data/lib/mihari/web/endpoints/rules.rb +1 -1
  66. data/lib/mihari/web/public/assets/{index-TOeU8PE2.js → index-JHS0L8KZ.js} +47 -47
  67. data/lib/mihari/web/public/assets/{index-dVaNxqTC.css → index-ReF8ffd-.css} +1 -1
  68. data/lib/mihari/web/public/index.html +2 -2
  69. data/lib/mihari/web/public/redoc-static.html +17 -17
  70. data/lib/mihari.rb +3 -0
  71. data/mihari.gemspec +2 -2
  72. data/requirements.txt +1 -1
  73. metadata +11 -8
@@ -7,14 +7,22 @@ module Mihari
7
7
  #
8
8
  class GooglePublicDNS < Base
9
9
  #
10
- # Query Google Public DNS
10
+ # @param [Mihari::Models::Artifact] artifact
11
11
  #
12
- # @param [String] name
12
+ # @return [Mihari::Models::Artifact]
13
13
  #
14
- # @return [Mihari::Structs::GooglePublicDNS::Response]
15
- #
16
- def call(name)
17
- client.query_all name
14
+ def call(artifact)
15
+ return if artifact.domain.nil?
16
+
17
+ res = client.query_all(artifact.domain)
18
+
19
+ artifact.tap do |tapped|
20
+ if tapped.dns_records.empty?
21
+ tapped.dns_records = res.answers.map do |answer|
22
+ Models::DnsRecord.new(resource: answer.resource_type, value: answer.data)
23
+ end
24
+ end
25
+ end
18
26
  end
19
27
 
20
28
  class << self
@@ -28,8 +36,21 @@ module Mihari
28
36
 
29
37
  private
30
38
 
39
+ #
40
+ # @param [Mihari::Models::Artifact] artifact
41
+ #
42
+ # @return [Boolean]
43
+ #
44
+ def callable_relationships?(artifact)
45
+ artifact.dns_records.empty?
46
+ end
47
+
48
+ def supported_data_types
49
+ %w[url domain]
50
+ end
51
+
31
52
  def client
32
- Clients::GooglePublicDNS.new(timeout: timeout)
53
+ @client ||= Clients::GooglePublicDNS.new(timeout: timeout)
33
54
  end
34
55
  end
35
56
  end
@@ -7,18 +7,36 @@ module Mihari
7
7
  #
8
8
  class MMDB < Base
9
9
  #
10
- # Query MMDB
10
+ # @param [Mihari::Models::Artifact] artifact
11
11
  #
12
- # @param [String] ip
12
+ def call(artifact)
13
+ res = client.query(artifact.data)
14
+
15
+ artifact.tap do |tapped|
16
+ tapped.autonomous_system ||= Models::AutonomousSystem.new(number: res.asn) if res.asn
17
+ if res.country_code
18
+ tapped.geolocation ||= Models::Geolocation.new(
19
+ country: NormalizeCountry(res.country_code, to: :short),
20
+ country_code: res.country_code
21
+ )
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ #
29
+ # @param [Mihari::Models::Artifact] artifact
13
30
  #
14
- # @return [Mihari::Structs::MMDB::Response]
31
+ # @return [Boolean]
15
32
  #
16
- def call(ip)
17
- client.query ip
33
+ def callable_relationships?(artifact)
34
+ artifact.geolocation.nil? || artifact.autonomous_system.nil?
18
35
  end
19
- memo_wise :call
20
36
 
21
- private
37
+ def supported_data_types
38
+ %w[ip]
39
+ end
22
40
 
23
41
  def client
24
42
  @client ||= Clients::MMDB.new(timeout: timeout)
@@ -9,17 +9,48 @@ module Mihari
9
9
  #
10
10
  # Query Shodan Internet DB
11
11
  #
12
- # @param [String] ip
12
+ # @param [Mihari::Models::Artifact] artifact
13
13
  #
14
14
  # @return [Mihari::Structs::Shodan::InternetDBResponse, nil]
15
15
  #
16
- def call(ip)
17
- client.query ip
16
+ def call(artifact)
17
+ res = client.query(artifact.data)
18
+
19
+ artifact.tap do |tapped|
20
+ tapped.cpes = (res&.cpes || []).map { |cpe| Models::CPE.new(name: cpe) } if tapped.cpes.empty?
21
+ tapped.ports = (res&.ports || []).map { |port| Models::Port.new(number: port) } if tapped.ports.empty?
22
+ if tapped.reverse_dns_names.empty?
23
+ tapped.reverse_dns_names = (res&.hostnames || []).map do |name|
24
+ Models::ReverseDnsName.new(name: name)
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ #
31
+ # @param [Mihari::Models::Artifact] artifact
32
+ #
33
+ # @return [Boolean]
34
+ #
35
+ def callable?(artifact)
36
+ false unless supported_data_types.include?(artifact.data_type)
18
37
  end
19
- memo_wise :call
20
38
 
21
39
  private
22
40
 
41
+ #
42
+ # @param [Mihari::Models::Artifact] artifact
43
+ #
44
+ # @return [Boolean]
45
+ #
46
+ def callable_relationships?(artifact)
47
+ artifact.cpes.empty? || artifact.ports.empty? || artifact.reverse_dns_names.empty?
48
+ end
49
+
50
+ def supported_data_types
51
+ %w[ip]
52
+ end
53
+
23
54
  def client
24
55
  @client ||= Clients::ShodanInternetDB.new(timeout: timeout)
25
56
  end
@@ -8,58 +8,64 @@ module Mihari
8
8
  # Whois enricher
9
9
  #
10
10
  class Whois < Base
11
+ prepend MemoWise
12
+
13
+ #
14
+ # Query IAIA Whois API
11
15
  #
12
- # @param [Hash, nil] options
16
+ # @param [Mihari::Models::Artifact] artifact
13
17
  #
14
- def initialize(options: nil)
15
- super(options: options)
18
+ def call(artifact)
19
+ return if artifact.domain.nil?
20
+
21
+ domain = PublicSuffix.domain(artifact.domain)
22
+ record = memoized_lookup(domain)
23
+ return if record.parser.available?
24
+
25
+ artifact.whois_record ||= Models::WhoisRecord.new(
26
+ domain: domain,
27
+ created_on: get_created_on(record.parser),
28
+ updated_on: get_updated_on(record.parser),
29
+ expires_on: get_expires_on(record.parser),
30
+ registrar: get_registrar(record.parser),
31
+ contacts: get_contacts(record.parser)
32
+ )
16
33
  end
17
34
 
35
+ private
36
+
18
37
  #
19
- # Query IAIA Whois API
20
- #
21
- # @param [String] domain
38
+ # @param [Mihari::Models::Artifact] artifact
22
39
  #
23
- # @return [Mihari::Models::WhoisRecord, nil]
40
+ # @return [Boolean]
24
41
  #
25
- def call(domain)
26
- memoized_call PublicSuffix.domain(domain)
42
+ def callable_relationships?(artifact)
43
+ artifact.whois_record.nil?
27
44
  end
28
45
 
29
- private
46
+ def supported_data_types
47
+ %w[url domain]
48
+ end
30
49
 
31
50
  #
32
51
  # @param [String] domain
33
52
  #
34
53
  # @return [Mihari::Models::WhoisRecord, nil]
35
54
  #
36
- def memoized_call(domain)
37
- record = whois.lookup(domain)
38
- parser = record.parser
39
- return nil if parser.available?
40
-
41
- Models::WhoisRecord.new(
42
- domain: domain,
43
- created_on: get_created_on(parser),
44
- updated_on: get_updated_on(parser),
45
- expires_on: get_expires_on(parser),
46
- registrar: get_registrar(parser),
47
- contacts: get_contacts(parser)
48
- )
55
+ def memoized_lookup(domain)
56
+ whois.lookup domain
49
57
  end
50
- memo_wise :memoized_call
58
+ memo_wise :memoized_lookup
51
59
 
52
60
  #
53
61
  # @return [::Whois::Client]
54
62
  #
55
63
  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
64
+ @whois ||= lambda do
65
+ return ::Whois::Client.new if timeout.nil?
66
+
67
+ ::Whois::Client.new(timeout: timeout)
68
+ end.call
63
69
  end
64
70
 
65
71
  #
@@ -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
@@ -3,7 +3,7 @@
3
3
  module Mihari
4
4
  module Entities
5
5
  class Port < Grape::Entity
6
- expose :port, documentation: { type: Integer, required: true }
6
+ expose :number, documentation: { type: Integer, required: true }
7
7
  expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
8
8
  end
9
9
  end
@@ -0,0 +1,10 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Entities
5
+ class Vulnerability < Grape::Entity
6
+ expose :name, documentation: { type: String, required: true }
7
+ expose :created_at, documentation: { type: DateTime, required: true }, as: :createdAt
8
+ end
9
+ end
10
+ end
data/lib/mihari/errors.rb CHANGED
@@ -7,6 +7,8 @@ module Mihari
7
7
 
8
8
  class ValueError < Error; end
9
9
 
10
+ class UnenrichableError < Error; end
11
+
10
12
  class ConfigurationError < Error
11
13
  # @return [Array<String>, nil]
12
14
  attr_reader :detail
@@ -6,6 +6,18 @@ module Mihari
6
6
  # Alert model
7
7
  #
8
8
  class Alert < ActiveRecord::Base
9
+ # @!attribute [r] id
10
+ # @return [Integer, nil]
11
+
12
+ # @!attribute [rw] created_at
13
+ # @return [DateTime]
14
+
15
+ # @!attribute [r] rule
16
+ # @return [Mihari::Models::Rule]
17
+
18
+ # @!attribute [r] artifacts
19
+ # @return [Array<Mihari::Models::Artifact>]
20
+
9
21
  belongs_to :rule
10
22
 
11
23
  has_many :artifacts, dependent: :destroy
@@ -17,6 +17,90 @@ module Mihari
17
17
  # Artifact model
18
18
  #
19
19
  class Artifact < ActiveRecord::Base
20
+ # @!attribute [r] id
21
+ # @return [Integer, nil]
22
+
23
+ # @!attribute [rw] data
24
+ # @return [String]
25
+
26
+ # @!attribute [rw] data_type
27
+ # @return [String]
28
+
29
+ # @!attribute [rw] source
30
+ # @return [String, nil]
31
+
32
+ # @!attribute [rw] query
33
+ # @return [String, nil]
34
+
35
+ # @!attribute [rw] metadata
36
+ # @return [Hash, nil]
37
+
38
+ # @!attribute [rw] created_at
39
+ # @return [DateTime]
40
+
41
+ # @!attribute [r] alert
42
+ # @return [Mihari::Models::Alert]
43
+
44
+ # @!attribute [r] rule
45
+ # @return [Mihari::Models::Rule]
46
+
47
+ # @!attribute [rw] autonomous_system
48
+ # @return [Mihari::Models::AutonomousSystem, nil]
49
+
50
+ # @!attribute [rw] geolocation
51
+ # @return [Mihari::Models::Geolocation, nil]
52
+
53
+ # @!attribute [rw] whois_record
54
+ # @return [Mihari::Models::WhoisRecord, nil]
55
+
56
+ # @!attribute [rw] cpes
57
+ # @return [Array<Mihari::Models::CPE>]
58
+
59
+ # @!attribute [rw] dns_records
60
+ # @return [Array<Mihari::Models::DnsRecord>]
61
+
62
+ # @!attribute [rw] ports
63
+ # @return [Array<Mihari::Models::Port>]
64
+
65
+ # @!attribute [rw] reverse_dns_names
66
+ # @return [Array<Mihari::Models::ReverseDnsName>]
67
+
68
+ # @!attribute [rw] vulnerabilities
69
+ # @return [Array<Mihari::Models::Vulnerability>]
70
+
71
+ # @!attribute [r] alert
72
+ # @return [Mihari::Models::Alert]
73
+
74
+ # @!attribute [r] rule
75
+ # @return [Mihari::Models::Rule]
76
+
77
+ # @!attribute [rw] autonomous_system
78
+ # @return [Mihari::Models::AutonomousSystem, nil]
79
+
80
+ # @!attribute [rw] geolocation
81
+ # @return [Mihari::Models::Geolocation, nil]
82
+
83
+ # @!attribute [rw] whois_record
84
+ # @return [Mihari::Models::WhoisRecord, nil]
85
+
86
+ # @!attribute [rw] cpes
87
+ # @return [Array<Mihari::Models::CPE>]
88
+
89
+ # @!attribute [rw] dns_records
90
+ # @return [Array<Mihari::Models::DnsRecord>]
91
+
92
+ # @!attribute [rw] ports
93
+ # @return [Array<Mihari::Models::Port>]
94
+
95
+ # @!attribute [rw] reverse_dns_names
96
+ # @return [Array<Mihari::Models::ReverseDnsName>]
97
+
98
+ # @!attribute [rw] vulnerabilities
99
+ # @return [Array<Mihari::Models::Vulnerability>]
100
+
101
+ # @!attribute [rw] tags
102
+ # @return [Array<Mihari::Models::Tag>]
103
+
20
104
  belongs_to :alert
21
105
 
22
106
  has_one :autonomous_system, dependent: :destroy
@@ -28,6 +112,8 @@ module Mihari
28
112
  has_many :dns_records, dependent: :destroy
29
113
  has_many :ports, dependent: :destroy
30
114
  has_many :reverse_dns_names, dependent: :destroy
115
+ has_many :vulnerabilities, dependent: :destroy
116
+
31
117
  has_many :tags, through: :alert
32
118
 
33
119
  include ActiveModel::Validations
@@ -38,13 +124,14 @@ module Mihari
38
124
  attributes :id, :data, :data_type, :source, :query, :created_at, "alert.id", "rule.id", "rule.title",
39
125
  "rule.description"
40
126
  attributes tag: "tags.name"
41
- attributes asn: "autonomous_system.asn"
127
+ attributes asn: "autonomous_system.number"
42
128
  attributes country_code: "geolocation.country_code"
43
129
  attributes "dns_record.value": "dns_records.value"
44
130
  attributes "dns_record.resource": "dns_records.resource"
45
131
  attributes reverse_dns_name: "reverse_dns_names.name"
46
132
  attributes cpe: "cpes.name"
47
- attributes port: "ports.port"
133
+ attributes vuln: "vulnerabilities.name"
134
+ attributes port: "ports.number"
48
135
  end
49
136
 
50
137
  validates_with ArtifactValidator
@@ -54,6 +141,14 @@ module Mihari
54
141
  # @return [String, nil]
55
142
  attr_accessor :rule_id
56
143
 
144
+ before_destroy do
145
+ @alert = alert
146
+ end
147
+
148
+ after_destroy do
149
+ @alert.destroy unless @alert.artifacts.any?
150
+ end
151
+
57
152
  #
58
153
  # Check uniqueness
59
154
  #
@@ -79,122 +174,25 @@ module Mihari
79
174
  artifact.created_at < decayed_at
80
175
  end
81
176
 
82
- #
83
- # Enrich whois record
84
- #
85
- # @param [Mihari::Enrichers::Whois] enricher
86
- #
87
- def enrich_whois(enricher = Enrichers::Whois.new)
88
- return unless can_enrich_whois?
89
-
90
- self.whois_record = Services::WhoisRecordBuilder.call(domain, enricher: enricher)
91
- end
92
-
93
- #
94
- # Enrich DNS records
95
- #
96
- # @param [Mihari::Enrichers::GooglePublicDNS] enricher
97
- #
98
- def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
99
- return unless can_enrich_dns?
100
-
101
- self.dns_records = Services::DnsRecordBuilder.call(domain, enricher: enricher)
102
- end
103
-
104
- #
105
- # Enrich reverse DNS names
106
- #
107
- # @param [Mihari::Enrichers::Shodan] enricher
108
- #
109
- def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
110
- return unless can_enrich_reverse_dns?
111
-
112
- self.reverse_dns_names = Services::ReverseDnsNameBuilder.call(data, enricher: enricher)
113
- end
114
-
115
- #
116
- # Enrich geolocation
117
- #
118
- # @param [Mihari::Enrichers::IPInfo] enricher
119
- #
120
- def enrich_geolocation(enricher = Enrichers::MMDB.new)
121
- return unless can_enrich_geolocation?
122
-
123
- self.geolocation = Services::GeolocationBuilder.call(data, enricher: enricher)
124
- end
125
-
126
- #
127
- # Enrich AS
128
- #
129
- # @param [Mihari::Enrichers::IPInfo] enricher
130
- #
131
- def enrich_autonomous_system(enricher = Enrichers::MMDB.new)
132
- return unless can_enrich_autonomous_system?
133
-
134
- self.autonomous_system = Services::AutonomousSystemBuilder.call(data, enricher: enricher)
135
- end
136
-
137
- #
138
- # Enrich ports
139
- #
140
- # @param [Mihari::Enrichers::Shodan] enricher
141
- #
142
- def enrich_ports(enricher = Enrichers::Shodan.new)
143
- return unless can_enrich_ports?
144
-
145
- self.ports = Services::PortBuilder.call(data, enricher: enricher)
177
+ def enrichable?
178
+ !callable_enrichers.empty?
146
179
  end
147
180
 
148
- #
149
- # Enrich CPEs
150
- #
151
- # @param [Mihari::Enrichers::Shodan] enricher
152
- #
153
- def enrich_cpes(enricher = Enrichers::Shodan.new)
154
- return unless can_enrich_cpes?
155
-
156
- self.cpes = Services::CPEBuilder.call(data, enricher: enricher)
181
+ def enrich
182
+ callable_enrichers.each { |enricher| enricher.result self }
157
183
  end
158
184
 
159
185
  #
160
- # Enrich all the enrichable relationships of the artifact
161
- #
162
- def enrich_all
163
- enrich_autonomous_system mmdb
164
- enrich_dns
165
- enrich_geolocation mmdb
166
- enrich_reverse_dns shodan
167
- enrich_whois
168
- enrich_ports shodan
169
- enrich_cpes shodan
170
- end
171
-
172
- ENRICH_METHODS_BY_ENRICHER = {
173
- Enrichers::Whois => %i[
174
- enrich_whois
175
- ],
176
- Enrichers::MMDB => %i[
177
- enrich_autonomous_system
178
- enrich_geolocation
179
- ],
180
- Enrichers::Shodan => %i[
181
- enrich_ports
182
- enrich_cpes
183
- enrich_reverse_dns
184
- ],
185
- Enrichers::GooglePublicDNS => %i[
186
- enrich_dns
187
- ]
188
- }.freeze
189
-
190
- #
191
- # Enrich by name of enricher
192
- #
193
- # @param [Mihari::Enrichers::Base] enricher
186
+ # @return [String, nil]
194
187
  #
195
- def enrich_by_enricher(enricher)
196
- methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
197
- methods.each { |method| send(method, enricher) if respond_to?(method) }
188
+ def domain
189
+ case data_type
190
+ when "domain"
191
+ data
192
+ when "url"
193
+ host = Addressable::URI.parse(data).host
194
+ (DataType.type(host) == "ip") ? nil : host
195
+ end
198
196
  end
199
197
 
200
198
  class << self
@@ -209,60 +207,21 @@ module Mihari
209
207
 
210
208
  private
211
209
 
212
- def set_data_type
213
- self.data_type = DataType.type(data)
214
- end
215
-
216
- def set_rule_id
217
- @set_rule_id ||= nil
218
- end
219
-
220
- def mmdb
221
- @mmdb ||= Enrichers::MMDB.new
222
- end
223
-
224
- def shodan
225
- @shodan ||= Enrichers::Shodan.new
226
- end
227
-
228
210
  #
229
- # @return [String, nil]
211
+ # @return [Array<Mihari::Enrichers::Base>]
230
212
  #
231
- def domain
232
- case data_type
233
- when "domain"
234
- data
235
- when "url"
236
- Addressable::URI.parse(data).host
213
+ def callable_enrichers
214
+ @callable_enrichers ||= Mihari.enrichers.map(&:new).select do |enricher|
215
+ enricher.callable?(self)
237
216
  end
238
217
  end
239
218
 
240
- def can_enrich_whois?
241
- %w[domain url].include?(data_type) && whois_record.nil?
242
- end
243
-
244
- def can_enrich_dns?
245
- %w[domain url].include?(data_type) && dns_records.empty?
246
- end
247
-
248
- def can_enrich_reverse_dns?
249
- data_type == "ip" && reverse_dns_names.empty?
250
- end
251
-
252
- def can_enrich_geolocation?
253
- data_type == "ip" && geolocation.nil?
254
- end
255
-
256
- def can_enrich_autonomous_system?
257
- data_type == "ip" && autonomous_system.nil?
258
- end
259
-
260
- def can_enrich_ports?
261
- data_type == "ip" && ports.empty?
219
+ def set_data_type
220
+ self.data_type = DataType.type(data)
262
221
  end
263
222
 
264
- def can_enrich_cpes?
265
- data_type == "ip" && cpes.empty?
223
+ def set_rule_id
224
+ @set_rule_id ||= nil
266
225
  end
267
226
  end
268
227
  end