mihari 7.1.3 → 7.3.0

Sign up to get free protection for your applications and to get access to all the features.
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