mihari 6.0.0 → 6.1.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.
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