mihari 5.6.1 → 5.6.2

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 (71) hide show
  1. checksums.yaml +4 -4
  2. data/frontend/package-lock.json +173 -176
  3. data/frontend/package.json +9 -9
  4. data/lib/mihari/{base.rb → actor.rb} +16 -2
  5. data/lib/mihari/analyzers/base.rb +5 -10
  6. data/lib/mihari/analyzers/censys.rb +1 -1
  7. data/lib/mihari/analyzers/hunterhow.rb +1 -1
  8. data/lib/mihari/analyzers/passivetotal.rb +1 -1
  9. data/lib/mihari/analyzers/pulsedive.rb +1 -1
  10. data/lib/mihari/analyzers/securitytrails.rb +1 -1
  11. data/lib/mihari/analyzers/urlscan.rb +1 -1
  12. data/lib/mihari/analyzers/virustotal.rb +5 -5
  13. data/lib/mihari/analyzers/zoomeye.rb +3 -3
  14. data/lib/mihari/clients/crtsh.rb +2 -2
  15. data/lib/mihari/clients/passivetotal.rb +4 -4
  16. data/lib/mihari/clients/securitytrails.rb +3 -3
  17. data/lib/mihari/commands/rule.rb +2 -11
  18. data/lib/mihari/commands/search.rb +1 -1
  19. data/lib/mihari/emitters/base.rb +13 -24
  20. data/lib/mihari/emitters/database.rb +7 -9
  21. data/lib/mihari/emitters/misp.rb +14 -38
  22. data/lib/mihari/emitters/slack.rb +14 -11
  23. data/lib/mihari/emitters/the_hive.rb +16 -44
  24. data/lib/mihari/emitters/webhook.rb +31 -21
  25. data/lib/mihari/enrichers/base.rb +1 -6
  26. data/lib/mihari/enrichers/whois.rb +1 -1
  27. data/lib/mihari/models/alert.rb +75 -73
  28. data/lib/mihari/models/artifact.rb +182 -180
  29. data/lib/mihari/models/autonomous_system.rb +22 -20
  30. data/lib/mihari/models/cpe.rb +21 -19
  31. data/lib/mihari/models/dns.rb +24 -22
  32. data/lib/mihari/models/geolocation.rb +22 -20
  33. data/lib/mihari/models/port.rb +21 -19
  34. data/lib/mihari/models/reverse_dns.rb +21 -19
  35. data/lib/mihari/models/rule.rb +67 -65
  36. data/lib/mihari/models/tag.rb +5 -3
  37. data/lib/mihari/models/tagging.rb +5 -3
  38. data/lib/mihari/models/whois.rb +18 -16
  39. data/lib/mihari/rule.rb +352 -0
  40. data/lib/mihari/schemas/analyzer.rb +94 -87
  41. data/lib/mihari/schemas/emitter.rb +9 -5
  42. data/lib/mihari/schemas/enricher.rb +8 -4
  43. data/lib/mihari/schemas/mixins.rb +15 -0
  44. data/lib/mihari/schemas/rule.rb +3 -10
  45. data/lib/mihari/services/alert_builder.rb +1 -1
  46. data/lib/mihari/services/alert_proxy.rb +10 -6
  47. data/lib/mihari/services/alert_runner.rb +4 -4
  48. data/lib/mihari/services/rule_builder.rb +3 -3
  49. data/lib/mihari/services/rule_runner.rb +5 -5
  50. data/lib/mihari/structs/binaryedge.rb +1 -1
  51. data/lib/mihari/structs/censys.rb +6 -6
  52. data/lib/mihari/structs/config.rb +1 -1
  53. data/lib/mihari/structs/greynoise.rb +5 -5
  54. data/lib/mihari/structs/hunterhow.rb +3 -3
  55. data/lib/mihari/structs/onyphe.rb +5 -5
  56. data/lib/mihari/structs/shodan.rb +6 -6
  57. data/lib/mihari/structs/urlscan.rb +3 -3
  58. data/lib/mihari/structs/virustotal_intelligence.rb +3 -3
  59. data/lib/mihari/version.rb +1 -1
  60. data/lib/mihari/web/endpoints/alerts.rb +4 -4
  61. data/lib/mihari/web/endpoints/artifacts.rb +6 -6
  62. data/lib/mihari/web/endpoints/rules.rb +10 -17
  63. data/lib/mihari/web/endpoints/tags.rb +2 -2
  64. data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-28d4c79d.js} +48 -48
  65. data/lib/mihari/web/public/index.html +1 -1
  66. data/lib/mihari.rb +6 -8
  67. data/mihari.gemspec +1 -2
  68. data/requirements.txt +1 -1
  69. metadata +8 -22
  70. data/lib/mihari/analyzers/rule.rb +0 -232
  71. data/lib/mihari/services/rule_proxy.rb +0 -182
@@ -1,229 +1,231 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- class ArtifactValidator < ActiveModel::Validator
4
- def validate(record)
5
- return if record.data_type
6
-
7
- record.errors.add :data, "#{record.data} is not supported"
8
- end
9
- end
10
-
11
3
  module Mihari
12
- class Artifact < ActiveRecord::Base
13
- belongs_to :alert
4
+ module Models
5
+ class ArtifactValidator < ActiveModel::Validator
6
+ def validate(record)
7
+ return if record.data_type
14
8
 
15
- has_one :autonomous_system, dependent: :destroy
16
- has_one :geolocation, dependent: :destroy
17
- has_one :whois_record, dependent: :destroy
9
+ record.errors.add :data, "#{record.data} is not supported"
10
+ end
11
+ end
18
12
 
19
- has_many :cpes, dependent: :destroy
20
- has_many :dns_records, dependent: :destroy
21
- has_many :ports, dependent: :destroy
22
- has_many :reverse_dns_names, dependent: :destroy
13
+ class Artifact < ActiveRecord::Base
14
+ belongs_to :alert
23
15
 
24
- include ActiveModel::Validations
16
+ has_one :autonomous_system, dependent: :destroy
17
+ has_one :geolocation, dependent: :destroy
18
+ has_one :whois_record, dependent: :destroy
25
19
 
26
- validates_with ArtifactValidator
20
+ has_many :cpes, dependent: :destroy
21
+ has_many :dns_records, dependent: :destroy
22
+ has_many :ports, dependent: :destroy
23
+ has_many :reverse_dns_names, dependent: :destroy
27
24
 
28
- # @return [Array<Mihari::Tag>] Tags
29
- attr_accessor :tags
25
+ include ActiveModel::Validations
30
26
 
31
- # @return [String, nil] Rule ID
32
- attr_accessor :rule_id
27
+ validates_with ArtifactValidator
33
28
 
34
- def initialize(*args, **kwargs)
35
- attrs = args.first || kwargs
36
- data_ = attrs[:data]
29
+ # @return [Array<Mihari::Tag>] Tags
30
+ attr_accessor :tags
37
31
 
38
- raise TypeError if data_.is_a?(Array) || data_.is_a?(Hash)
32
+ # @return [String, nil] Rule ID
33
+ attr_accessor :rule_id
39
34
 
40
- super(*args, **kwargs)
35
+ def initialize(*args, **kwargs)
36
+ attrs = args.first || kwargs
37
+ data_ = attrs[:data]
41
38
 
42
- self.data_type = TypeChecker.type(data)
39
+ raise TypeError if data_.is_a?(Array) || data_.is_a?(Hash)
43
40
 
44
- @tags = []
45
- @rule_id = ""
46
- end
41
+ super(*args, **kwargs)
47
42
 
48
- #
49
- # Check uniqueness of artifact
50
- #
51
- # @param [Time, nil] base_time Base time to check decaying
52
- # @param [Integer, nil] artifact_lifetime Artifact lifetime (TTL) in seconds
53
- #
54
- # @return [Boolean] true if it is unique. Otherwise false.
55
- #
56
- def unique?(base_time: nil, artifact_lifetime: nil)
57
- artifact = self.class.joins(:alert).where(
58
- data: data,
59
- alert: { rule_id: rule_id }
60
- ).order(created_at: :desc).first
61
- return true if artifact.nil?
62
-
63
- # check whether the artifact is decayed or not
64
- return false if artifact_lifetime.nil?
65
-
66
- # use the current UTC time if base_time is not given (for testing)
67
- base_time ||= Time.now.utc
68
-
69
- decayed_at = base_time - (artifact_lifetime || -1).seconds
70
- artifact.created_at < decayed_at
71
- end
43
+ self.data_type = TypeChecker.type(data)
72
44
 
73
- #
74
- # Enrich(add) whois record
75
- #
76
- # @param [Mihari::Enrichers::Whois] enricher
77
- #
78
- def enrich_whois(enricher = Enrichers::Whois.new)
79
- return unless can_enrich_whois?
45
+ @tags = []
46
+ @rule_id = ""
47
+ end
80
48
 
81
- self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
82
- end
49
+ #
50
+ # Check uniqueness of artifact
51
+ #
52
+ # @param [Time, nil] base_time Base time to check decaying
53
+ # @param [Integer, nil] artifact_lifetime Artifact lifetime (TTL) in seconds
54
+ #
55
+ # @return [Boolean] true if it is unique. Otherwise false.
56
+ #
57
+ def unique?(base_time: nil, artifact_lifetime: nil)
58
+ artifact = self.class.joins(:alert).where(
59
+ data: data,
60
+ alert: { rule_id: rule_id }
61
+ ).order(created_at: :desc).first
62
+ return true if artifact.nil?
63
+
64
+ # check whether the artifact is decayed or not
65
+ return false if artifact_lifetime.nil?
66
+
67
+ # use the current UTC time if base_time is not given (for testing)
68
+ base_time ||= Time.now.utc
69
+
70
+ decayed_at = base_time - (artifact_lifetime || -1).seconds
71
+ artifact.created_at < decayed_at
72
+ end
83
73
 
84
- #
85
- # Enrich(add) DNS records
86
- #
87
- # @param [Mihari::Enrichers::GooglePublicDNS] enricher
88
- #
89
- def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
90
- return unless can_enrich_dns?
74
+ #
75
+ # Enrich(add) whois record
76
+ #
77
+ # @param [Mihari::Enrichers::Whois] enricher
78
+ #
79
+ def enrich_whois(enricher = Enrichers::Whois.new)
80
+ return unless can_enrich_whois?
91
81
 
92
- self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
93
- end
82
+ self.whois_record = WhoisRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
83
+ end
94
84
 
95
- #
96
- # Enrich(add) reverse DNS names
97
- #
98
- # @param [Mihari::Enrichers::Shodan] enricher
99
- #
100
- def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
101
- return unless can_enrich_revese_dns?
85
+ #
86
+ # Enrich(add) DNS records
87
+ #
88
+ # @param [Mihari::Enrichers::GooglePublicDNS] enricher
89
+ #
90
+ def enrich_dns(enricher = Enrichers::GooglePublicDNS.new)
91
+ return unless can_enrich_dns?
102
92
 
103
- self.reverse_dns_names = ReverseDnsName.build_by_ip(data, enricher: enricher)
104
- end
93
+ self.dns_records = DnsRecord.build_by_domain(normalize_as_domain(data), enricher: enricher)
94
+ end
105
95
 
106
- #
107
- # Enrich(add) geolocation
108
- #
109
- # @param [Mihari::Enrichers::IPInfo] enricher
110
- #
111
- def enrich_geolocation(enricher = Enrichers::IPInfo.new)
112
- return unless can_enrich_geolocation?
96
+ #
97
+ # Enrich(add) reverse DNS names
98
+ #
99
+ # @param [Mihari::Enrichers::Shodan] enricher
100
+ #
101
+ def enrich_reverse_dns(enricher = Enrichers::Shodan.new)
102
+ return unless can_enrich_revese_dns?
113
103
 
114
- self.geolocation = Geolocation.build_by_ip(data, enricher: enricher)
115
- end
104
+ self.reverse_dns_names = ReverseDnsName.build_by_ip(data, enricher: enricher)
105
+ end
116
106
 
117
- #
118
- # Enrich AS
119
- #
120
- # @param [Mihari::Enrichers::IPInfo] enricher
121
- #
122
- def enrich_autonomous_system(enricher = Enrichers::IPInfo.new)
123
- return unless can_enrich_autonomous_system?
107
+ #
108
+ # Enrich(add) geolocation
109
+ #
110
+ # @param [Mihari::Enrichers::IPInfo] enricher
111
+ #
112
+ def enrich_geolocation(enricher = Enrichers::IPInfo.new)
113
+ return unless can_enrich_geolocation?
124
114
 
125
- self.autonomous_system = AutonomousSystem.build_by_ip(data, enricher: enricher)
126
- end
115
+ self.geolocation = Geolocation.build_by_ip(data, enricher: enricher)
116
+ end
127
117
 
128
- #
129
- # Enrich ports
130
- #
131
- # @param [Mihari::Enrichers::Shodan] enricher
132
- #
133
- def enrich_ports(enricher = Enrichers::Shodan.new)
134
- return unless can_enrich_ports?
118
+ #
119
+ # Enrich AS
120
+ #
121
+ # @param [Mihari::Enrichers::IPInfo] enricher
122
+ #
123
+ def enrich_autonomous_system(enricher = Enrichers::IPInfo.new)
124
+ return unless can_enrich_autonomous_system?
135
125
 
136
- self.ports = Port.build_by_ip(data, enricher: enricher)
137
- end
126
+ self.autonomous_system = AutonomousSystem.build_by_ip(data, enricher: enricher)
127
+ end
138
128
 
139
- #
140
- # Enrich CPEs
141
- #
142
- # @param [Mihari::Enrichers::Shodan] enricher
143
- #
144
- def enrich_cpes(enricher = Enrichers::Shodan.new)
145
- return unless can_enrich_cpes?
129
+ #
130
+ # Enrich ports
131
+ #
132
+ # @param [Mihari::Enrichers::Shodan] enricher
133
+ #
134
+ def enrich_ports(enricher = Enrichers::Shodan.new)
135
+ return unless can_enrich_ports?
146
136
 
147
- self.cpes = CPE.build_by_ip(data, enricher: enricher)
148
- end
137
+ self.ports = Port.build_by_ip(data, enricher: enricher)
138
+ end
149
139
 
150
- #
151
- # Enrich all the enrichable relationships of the artifact
152
- #
153
- def enrich_all
154
- enrich_autonomous_system
155
- enrich_dns
156
- enrich_geolocation
157
- enrich_reverse_dns
158
- enrich_whois
159
- enrich_ports
160
- enrich_cpes
161
- end
140
+ #
141
+ # Enrich CPEs
142
+ #
143
+ # @param [Mihari::Enrichers::Shodan] enricher
144
+ #
145
+ def enrich_cpes(enricher = Enrichers::Shodan.new)
146
+ return unless can_enrich_cpes?
162
147
 
163
- ENRICH_METHODS_BY_ENRICHER = {
164
- Enrichers::Whois => %i[
165
- enrich_whois
166
- ],
167
- Enrichers::IPInfo => %i[
148
+ self.cpes = CPE.build_by_ip(data, enricher: enricher)
149
+ end
150
+
151
+ #
152
+ # Enrich all the enrichable relationships of the artifact
153
+ #
154
+ def enrich_all
168
155
  enrich_autonomous_system
156
+ enrich_dns
169
157
  enrich_geolocation
170
- ],
171
- Enrichers::Shodan => %i[
158
+ enrich_reverse_dns
159
+ enrich_whois
172
160
  enrich_ports
173
161
  enrich_cpes
174
- enrich_reverse_dns
175
- ],
176
- Enrichers::GooglePublicDNS => %i[
177
- enrich_dns
178
- ]
179
- }.freeze
180
-
181
- #
182
- # Enrich by name of enricher
183
- #
184
- # @param [Mihari::Enrichers::Base] enricher
185
- #
186
- def enrich_by_enricher(enricher)
187
- methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
188
- methods.each do |method|
189
- send(method, enricher) if respond_to?(method)
190
162
  end
191
- end
192
163
 
193
- private
164
+ ENRICH_METHODS_BY_ENRICHER = {
165
+ Enrichers::Whois => %i[
166
+ enrich_whois
167
+ ],
168
+ Enrichers::IPInfo => %i[
169
+ enrich_autonomous_system
170
+ enrich_geolocation
171
+ ],
172
+ Enrichers::Shodan => %i[
173
+ enrich_ports
174
+ enrich_cpes
175
+ enrich_reverse_dns
176
+ ],
177
+ Enrichers::GooglePublicDNS => %i[
178
+ enrich_dns
179
+ ]
180
+ }.freeze
181
+
182
+ #
183
+ # Enrich by name of enricher
184
+ #
185
+ # @param [Mihari::Enrichers::Base] enricher
186
+ #
187
+ def enrich_by_enricher(enricher)
188
+ methods = ENRICH_METHODS_BY_ENRICHER[enricher.class] || []
189
+ methods.each do |method|
190
+ send(method, enricher) if respond_to?(method)
191
+ end
192
+ end
194
193
 
195
- def normalize_as_domain(url_or_domain)
196
- return url_or_domain if data_type == "domain"
194
+ private
197
195
 
198
- Addressable::URI.parse(url_or_domain).host
199
- end
196
+ def normalize_as_domain(url_or_domain)
197
+ return url_or_domain if data_type == "domain"
200
198
 
201
- def can_enrich_whois?
202
- %w[domain url].include?(data_type) && whois_record.nil?
203
- end
199
+ Addressable::URI.parse(url_or_domain).host
200
+ end
204
201
 
205
- def can_enrich_dns?
206
- %w[domain url].include?(data_type) && dns_records.empty?
207
- end
202
+ def can_enrich_whois?
203
+ %w[domain url].include?(data_type) && whois_record.nil?
204
+ end
208
205
 
209
- def can_enrich_revese_dns?
210
- data_type == "ip" && reverse_dns_names.empty?
211
- end
206
+ def can_enrich_dns?
207
+ %w[domain url].include?(data_type) && dns_records.empty?
208
+ end
212
209
 
213
- def can_enrich_geolocation?
214
- data_type == "ip" && geolocation.nil?
215
- end
210
+ def can_enrich_revese_dns?
211
+ data_type == "ip" && reverse_dns_names.empty?
212
+ end
216
213
 
217
- def can_enrich_autonomous_system?
218
- data_type == "ip" && autonomous_system.nil?
219
- end
214
+ def can_enrich_geolocation?
215
+ data_type == "ip" && geolocation.nil?
216
+ end
220
217
 
221
- def can_enrich_ports?
222
- data_type == "ip" && ports.empty?
223
- end
218
+ def can_enrich_autonomous_system?
219
+ data_type == "ip" && autonomous_system.nil?
220
+ end
224
221
 
225
- def can_enrich_cpes?
226
- data_type == "ip" && cpes.empty?
222
+ def can_enrich_ports?
223
+ data_type == "ip" && ports.empty?
224
+ end
225
+
226
+ def can_enrich_cpes?
227
+ data_type == "ip" && cpes.empty?
228
+ end
227
229
  end
228
230
  end
229
231
  end
@@ -1,30 +1,32 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- class AutonomousSystem < ActiveRecord::Base
5
- belongs_to :artifact
4
+ module Models
5
+ class AutonomousSystem < ActiveRecord::Base
6
+ belongs_to :artifact
6
7
 
7
- class << self
8
- include Dry::Monads[:result]
8
+ class << self
9
+ include Dry::Monads[:result]
9
10
 
10
- #
11
- # Build AS
12
- #
13
- # @param [String] ip
14
- # @param [Mihari::Enrichers::IPInfo] enricher
15
- #
16
- # @return [Mihari::AutonomousSystem, nil]
17
- #
18
- def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
19
- result = enricher.query_result(ip).bind do |res|
20
- value = res&.asn
21
- if value.nil?
22
- Success nil
23
- else
24
- Success new(asn: value)
11
+ #
12
+ # Build AS
13
+ #
14
+ # @param [String] ip
15
+ # @param [Mihari::Enrichers::IPInfo] enricher
16
+ #
17
+ # @return [Mihari::AutonomousSystem, nil]
18
+ #
19
+ def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
20
+ result = enricher.query_result(ip).bind do |res|
21
+ value = res&.asn
22
+ if value.nil?
23
+ Success nil
24
+ else
25
+ Success new(asn: value)
26
+ end
25
27
  end
28
+ result.value_or nil
26
29
  end
27
- result.value_or nil
28
30
  end
29
31
  end
30
32
  end
@@ -1,29 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- class CPE < ActiveRecord::Base
5
- belongs_to :artifact
4
+ module Models
5
+ class CPE < ActiveRecord::Base
6
+ belongs_to :artifact
6
7
 
7
- class << self
8
- include Dry::Monads[:result]
8
+ class << self
9
+ include Dry::Monads[:result]
9
10
 
10
- #
11
- # Build CPEs
12
- #
13
- # @param [String] ip
14
- # @param [Mihari::Enrichers::Shodan] enricher
15
- #
16
- # @return [Array<Mihari::CPE>]
17
- #
18
- def build_by_ip(ip, enricher: Enrichers::Shodan.new)
19
- result = enricher.query_result(ip).bind do |res|
20
- if res.nil?
21
- Success []
22
- else
23
- Success(res.cpes.map { |cpe| new(cpe: cpe) })
11
+ #
12
+ # Build CPEs
13
+ #
14
+ # @param [String] ip
15
+ # @param [Mihari::Enrichers::Shodan] enricher
16
+ #
17
+ # @return [Array<Mihari::CPE>]
18
+ #
19
+ def build_by_ip(ip, enricher: Enrichers::Shodan.new)
20
+ result = enricher.query_result(ip).bind do |res|
21
+ if res.nil?
22
+ Success []
23
+ else
24
+ Success(res.cpes.map { |cpe| new(cpe: cpe) })
25
+ end
24
26
  end
27
+ result.value_or []
25
28
  end
26
- result.value_or []
27
29
  end
28
30
  end
29
31
  end
@@ -1,31 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- class DnsRecord < ActiveRecord::Base
5
- belongs_to :artifact
4
+ module Models
5
+ class DnsRecord < ActiveRecord::Base
6
+ belongs_to :artifact
6
7
 
7
- class << self
8
- include Dry::Monads[:result]
8
+ class << self
9
+ include Dry::Monads[:result]
9
10
 
10
- #
11
- # Build DNS records
12
- #
13
- # @param [String] domain
14
- # @param [Mihari::Enrichers::Shodan] enricher
15
- #
16
- # @return [Array<Mihari::DnsRecord>]
17
- #
18
- def build_by_domain(domain, enricher: Enrichers::GooglePublicDNS.new)
19
- result = enricher.query_result(domain).bind do |responses|
20
- Success(
21
- responses.map do |res|
22
- res.answers.map do |answer|
23
- new(resource: answer.resource_type, value: answer.data)
24
- end
25
- end.flatten
26
- )
11
+ #
12
+ # Build DNS records
13
+ #
14
+ # @param [String] domain
15
+ # @param [Mihari::Enrichers::Shodan] enricher
16
+ #
17
+ # @return [Array<Mihari::Models::DnsRecord>]
18
+ #
19
+ def build_by_domain(domain, enricher: Enrichers::GooglePublicDNS.new)
20
+ result = enricher.query_result(domain).bind do |responses|
21
+ Success(
22
+ responses.map do |res|
23
+ res.answers.map do |answer|
24
+ new(resource: answer.resource_type, value: answer.data)
25
+ end
26
+ end.flatten
27
+ )
28
+ end
29
+ result.value_or []
27
30
  end
28
- result.value_or []
29
31
  end
30
32
  end
31
33
  end
@@ -3,30 +3,32 @@
3
3
  require "normalize_country"
4
4
 
5
5
  module Mihari
6
- class Geolocation < ActiveRecord::Base
7
- belongs_to :artifact
6
+ module Models
7
+ class Geolocation < ActiveRecord::Base
8
+ belongs_to :artifact
8
9
 
9
- class << self
10
- include Dry::Monads[:result]
10
+ class << self
11
+ include Dry::Monads[:result]
11
12
 
12
- #
13
- # Build Geolocation
14
- #
15
- # @param [String] ip
16
- # @param [Mihari::Enrichers::IPinfo] enricher
17
- #
18
- # @return [Mihari::Geolocation, nil]
19
- #
20
- def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
21
- result = enricher.query_result(ip).bind do |res|
22
- value = res&.country_code
23
- if value.nil?
24
- Success nil
25
- else
26
- Success new(country: NormalizeCountry(value, to: :short), country_code: value)
13
+ #
14
+ # Build Geolocation
15
+ #
16
+ # @param [String] ip
17
+ # @param [Mihari::Enrichers::IPinfo] enricher
18
+ #
19
+ # @return [Mihari::Geolocation, nil]
20
+ #
21
+ def build_by_ip(ip, enricher: Enrichers::IPInfo.new)
22
+ result = enricher.query_result(ip).bind do |res|
23
+ value = res&.country_code
24
+ if value.nil?
25
+ Success nil
26
+ else
27
+ Success new(country: NormalizeCountry(value, to: :short), country_code: value)
28
+ end
27
29
  end
30
+ result.value_or nil
28
31
  end
29
- result.value_or nil
30
32
  end
31
33
  end
32
34
  end
@@ -1,29 +1,31 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- class Port < ActiveRecord::Base
5
- belongs_to :artifact
4
+ module Models
5
+ class Port < ActiveRecord::Base
6
+ belongs_to :artifact
6
7
 
7
- class << self
8
- include Dry::Monads[:result]
8
+ class << self
9
+ include Dry::Monads[:result]
9
10
 
10
- #
11
- # Build ports
12
- #
13
- # @param [String] ip
14
- # @param [Mihari::Enrichers::Shodan] enricher
15
- #
16
- # @return [Array<Mihari::Port>]
17
- #
18
- def build_by_ip(ip, enricher: Enrichers::Shodan.new)
19
- result = enricher.query_result(ip).bind do |res|
20
- if res.nil?
21
- Success []
22
- else
23
- Success(res.ports.map { |port| new(port: port) })
11
+ #
12
+ # Build ports
13
+ #
14
+ # @param [String] ip
15
+ # @param [Mihari::Enrichers::Shodan] enricher
16
+ #
17
+ # @return [Array<Mihari::Port>]
18
+ #
19
+ def build_by_ip(ip, enricher: Enrichers::Shodan.new)
20
+ result = enricher.query_result(ip).bind do |res|
21
+ if res.nil?
22
+ Success []
23
+ else
24
+ Success(res.ports.map { |port| new(port: port) })
25
+ end
24
26
  end
27
+ result.value_or []
25
28
  end
26
- result.value_or []
27
29
  end
28
30
  end
29
31
  end