mihari 6.0.0 → 6.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2846f5154fcdde4cda4f0237c79e047fc498b96b5c21a6152287ac9ab11faac9
4
- data.tar.gz: f43b4e20a59b1274b62c5e9768f153429540067882508b34f0c36932cc9cb5ef
3
+ metadata.gz: dc2d39ad14f53cf88ed2c68bb2e2668e9a43f36444099401ef9fbe1347948644
4
+ data.tar.gz: 2d08fed6ec6f82da36f72a2fb05ae1ede82ba65d6bc9bcdb7c60b8f7e244c71a
5
5
  SHA512:
6
- metadata.gz: b54da0da25e57531c1efef94bdc42df715569b9e88842ca330d1d0893f4c20990bb2ded22a001f31816cbd72f00f43473f0254f222a9849308be746576128e3c
7
- data.tar.gz: 7167afd356c4f945e66631bb3c6cefc06678961b480511d85939e6ede9eccec9a5f83a948a169be9ee7ba5cc79af918a447b8f01e5280faff3138071e7808beb
6
+ metadata.gz: 684c4106554f9c11bc7ff7f8633b32c5fa24b4127001415e6d14bd4de73e51a04084eb802a29cac109d8b56c71bc7068c8657f4d6ec7cd53e0519ef353aa859f
7
+ data.tar.gz: 4a4c3183ca85d47b54f7a98837059a9fae585c2d079fe005336520c62290bc317aa61880695f923a2ad0ad7ba5cf18e3e888990a9394d82b4ac41939f34b3403
data/.rubocop.yml CHANGED
@@ -13,6 +13,10 @@ Metrics/MethodLength:
13
13
  Max: 50
14
14
  Metrics/AbcSize:
15
15
  Max: 50
16
+ RSpec/MultipleMemoizedHelpers:
17
+ Max: 10
18
+ RSpec/ExampleLength:
19
+ Max: 20
16
20
  require:
17
21
  - rubocop-rspec
18
22
  - rubocop-yard
data/lib/mihari/actor.rb CHANGED
@@ -78,7 +78,7 @@ module Mihari
78
78
  # @return [String]
79
79
  #
80
80
  def class_key
81
- to_s.split("::").last
81
+ to_s.split("::").last.downcase
82
82
  end
83
83
 
84
84
  #
@@ -60,7 +60,10 @@ module Mihari
60
60
  # No need to set data_type manually
61
61
  # It is set automatically in #initialize
62
62
  artifact = artifact.is_a?(Models::Artifact) ? artifact : Models::Artifact.new(data: artifact)
63
+
63
64
  artifact.source = self.class.class_key
65
+ artifact.query = query
66
+
64
67
  artifact
65
68
  end.select(&:valid?).uniq(&:data)
66
69
  end
@@ -22,7 +22,7 @@ module Mihari
22
22
  # @param [Hash, nil] options
23
23
  # @param [String, nil] api_key
24
24
  #
25
- def initialize(query, start_time:, end_time:, options: nil, api_key: nil)
25
+ def initialize(query, start_time: nil, end_time: nil, options: nil, api_key: nil)
26
26
  super(query, options: options)
27
27
 
28
28
  @api_key = api_key || Mihari.config.hunterhow_api_key
data/lib/mihari/config.rb CHANGED
@@ -45,7 +45,8 @@ module Mihari
45
45
  retry_exponential_backoff: true,
46
46
  retry_interval: 5,
47
47
  retry_times: 3,
48
- sentry_dsn: nil
48
+ sentry_dsn: nil,
49
+ sentry_trace_sample_rate: 0.25
49
50
  )
50
51
 
51
52
  # @!attribute [r] binaryedge_api_key
@@ -132,6 +133,9 @@ module Mihari
132
133
  # @!attribute [r] sentry_dsn
133
134
  # @return [String, nil]
134
135
 
136
+ # @!attribute [r] sentry_trace_sample_rate
137
+ # @return [Float]
138
+
135
139
  # @!attribute [r] retry_interval
136
140
  # @return [Integer]
137
141
 
@@ -111,6 +111,12 @@ class V5Schema < ActiveRecord::Migration[7.1]
111
111
  end
112
112
  end
113
113
 
114
+ class V61Schema < ActiveRecord::Migration[7.1]
115
+ def change
116
+ add_column :artifacts, :query, :string
117
+ end
118
+ end
119
+
114
120
  def adapter
115
121
  return "postgresql" if %w[postgresql postgres].include?(Mihari.config.database_url.scheme)
116
122
  return "mysql2" if Mihari.config.database_url.scheme == "mysql2"
@@ -122,7 +128,7 @@ end
122
128
  # @return [Array<ActiveRecord::Migration>] schemas
123
129
  #
124
130
  def schemas
125
- [V5Schema]
131
+ [V5Schema, V61Schema]
126
132
  end
127
133
 
128
134
  module Mihari
@@ -56,12 +56,12 @@ module Mihari
56
56
  })
57
57
  end
58
58
 
59
- private
60
-
61
59
  def configuration_keys
62
60
  %w[misp_url misp_api_key]
63
61
  end
64
62
 
63
+ private
64
+
65
65
  def client
66
66
  @client ||= Clients::MISP.new(url, api_key: api_key, timeout: timeout)
67
67
  end
@@ -6,7 +6,7 @@ require "slack-notifier"
6
6
  module Mihari
7
7
  module Emitters
8
8
  class Attachment
9
- include Memist::Memoizable
9
+ prepend MemoWise
10
10
 
11
11
  # @return [String]
12
12
  attr_reader :data
@@ -76,7 +76,7 @@ module Mihari
76
76
  "https://urlscan.io/domain/#{uri.hostname}"
77
77
  end
78
78
  end
79
- memoize :_urlscan_link
79
+ memo_wise :_urlscan_link
80
80
 
81
81
  # @return [String, nil]
82
82
  def _vt_link
@@ -93,19 +93,19 @@ module Mihari
93
93
  "https://www.virustotal.com/#/search/#{data}"
94
94
  end
95
95
  end
96
- memoize :_vt_link
96
+ memo_wise :_vt_link
97
97
 
98
98
  # @return [String, nil]
99
99
  def _censys_link
100
100
  (data_type == "ip") ? "https://search.censys.io/hosts/#{data}" : nil
101
101
  end
102
- memoize :_censys_link
102
+ memo_wise :_censys_link
103
103
 
104
104
  # @return [String, nil]
105
105
  def _shodan_link
106
106
  (data_type == "ip") ? "https://www.shodan.io/host/#{data}" : nil
107
107
  end
108
- memoize :_shodan_link
108
+ memo_wise :_shodan_link
109
109
 
110
110
  # @return [String]
111
111
  def sha256
@@ -66,12 +66,12 @@ module Mihari
66
66
  end.first
67
67
  end
68
68
 
69
- private
70
-
71
69
  def configuration_keys
72
70
  %w[thehive_url thehive_api_key]
73
71
  end
74
72
 
73
+ private
74
+
75
75
  def client
76
76
  @client ||= Clients::TheHive.new(url, api_key: api_key, api_version: normalized_api_version, timeout: timeout)
77
77
  end
@@ -6,6 +6,8 @@ module Mihari
6
6
  # Base class for enrichers
7
7
  #
8
8
  class Base < Actor
9
+ prepend MemoWise
10
+
9
11
  def initialize(options: nil)
10
12
  super(options: options)
11
13
  end
@@ -35,6 +35,7 @@ module Mihari
35
35
  res = http.get(url)
36
36
  Structs::IPInfo::Response.from_dynamic! JSON.parse(res.body.to_s)
37
37
  end
38
+ memo_wise :call
38
39
 
39
40
  private
40
41
 
@@ -18,6 +18,7 @@ module Mihari
18
18
  res = http.get(url)
19
19
  Structs::Shodan::InternetDBResponse.from_dynamic! JSON.parse(res.body.to_s)
20
20
  end
21
+ memo_wise :call
21
22
 
22
23
  private
23
24
 
@@ -8,16 +8,11 @@ module Mihari
8
8
  # Whois enricher
9
9
  #
10
10
  class Whois < Base
11
- # @return [Hash]
12
- attr_accessor :memo
13
-
14
11
  #
15
12
  # @param [Hash, nil] options
16
13
  #
17
14
  def initialize(options: nil)
18
15
  super(options: options)
19
-
20
- @memo = {}
21
16
  end
22
17
 
23
18
  #
@@ -28,16 +23,22 @@ module Mihari
28
23
  # @return [Mihari::Models::WhoisRecord, nil]
29
24
  #
30
25
  def call(domain)
31
- domain = PublicSuffix.domain(domain)
26
+ _call PublicSuffix.domain(domain)
27
+ end
32
28
 
33
- # check memo
34
- return memo[domain].dup if memo.key?(domain)
29
+ private
35
30
 
31
+ #
32
+ # @param [String] domain
33
+ #
34
+ # @return [Mihari::Models::WhoisRecord, nil]
35
+ #
36
+ def _call(domain)
36
37
  record = whois.lookup(domain)
37
38
  parser = record.parser
38
39
  return nil if parser.available?
39
40
 
40
- whois_record = Models::WhoisRecord.new(
41
+ Models::WhoisRecord.new(
41
42
  domain: domain,
42
43
  created_on: get_created_on(parser),
43
44
  updated_on: get_updated_on(parser),
@@ -45,14 +46,8 @@ module Mihari
45
46
  registrar: get_registrar(parser),
46
47
  contacts: get_contacts(parser)
47
48
  )
48
-
49
- # set memo
50
- memo[domain] = whois_record
51
-
52
- whois_record
53
49
  end
54
-
55
- private
50
+ memo_wise :_call
56
51
 
57
52
  #
58
53
  # @return [::Whois::Client]
@@ -11,6 +11,7 @@ module Mihari
11
11
  expose :data, documentation: { type: String, required: true }
12
12
  expose :data_type, documentation: { type: String, required: true }, as: :dataType
13
13
  expose :source, documentation: { type: String, required: true }
14
+ expose :query, documentation: { type: String, required: false }
14
15
  expose :tags, documentation: { type: String, is_array: true }
15
16
  end
16
17
 
@@ -6,7 +6,7 @@ module Mihari
6
6
  # False positive mixins
7
7
  #
8
8
  module FalsePositive
9
- include Memist::Memoizable
9
+ prepend MemoWise
10
10
 
11
11
  #
12
12
  # Normalize a falsepositive value
@@ -22,7 +22,7 @@ module Mihari
22
22
  value_without_slashes = value[1..-2]
23
23
  Regexp.compile value_without_slashes.to_s
24
24
  end
25
- memoize :normalize_falsepositive
25
+ memo_wise :normalize_falsepositive
26
26
 
27
27
  #
28
28
  # Check whether a value is valid format as a disallowed data value
@@ -158,13 +158,13 @@ module Mihari
158
158
  # Enrich all the enrichable relationships of the artifact
159
159
  #
160
160
  def enrich_all
161
- enrich_autonomous_system
161
+ enrich_autonomous_system ipinfo
162
162
  enrich_dns
163
- enrich_geolocation
164
- enrich_reverse_dns
163
+ enrich_geolocation ipinfo
164
+ enrich_reverse_dns shodan
165
165
  enrich_whois
166
- enrich_ports
167
- enrich_cpes
166
+ enrich_ports shodan
167
+ enrich_cpes shodan
168
168
  end
169
169
 
170
170
  ENRICH_METHODS_BY_ENRICHER = {
@@ -197,6 +197,14 @@ module Mihari
197
197
 
198
198
  private
199
199
 
200
+ def ipinfo
201
+ @ipinfo ||= Enrichers::IPInfo.new
202
+ end
203
+
204
+ def shodan
205
+ @shodan ||= Enrichers::Shodan.new
206
+ end
207
+
200
208
  def normalize_as_domain(url_or_domain)
201
209
  return url_or_domain if data_type == "domain"
202
210
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- VERSION = "6.0.0"
4
+ VERSION = "6.1.0"
5
5
  end
@@ -53,17 +53,17 @@ module Mihari
53
53
 
54
54
  class << self
55
55
  def instance
56
- @instance ||= Rack::Builder.new do
56
+ Rack::Builder.new do
57
57
  use Rack::Cors do
58
58
  allow do
59
59
  origins "*"
60
60
  resource "*", headers: :any, methods: %i[get post put delete options]
61
61
  end
62
62
  end
63
-
64
63
  use Middleware::ConnectionAdapter
65
64
  use Middleware::ErrorNotificationAdapter
66
65
 
66
+ use Sentry::Rack::CaptureExceptions if Sentry.initialized?
67
67
  use BetterErrors::Middleware if ENV["RACK_ENV"] == "development" && defined?(BetterErrors::Middleware)
68
68
 
69
69
  run App.new