mihari 8.2.0 → 8.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f8838a34fe88cc9298632b713c7fea892bcb007b19590dda803c7194f75d593d
4
- data.tar.gz: 3b4de2b033ef657f99ae6e78018a912f2b19bf3098fee2e417ec7b295f40e215
3
+ metadata.gz: b337f264e337771e4d543b77153a57cdd13d5ce8960f75f70fc6fd7c70215903
4
+ data.tar.gz: 5013b97ab578766604d0ce2f1329b2209e1f234d5d018e9b642eda053b8ce4d7
5
5
  SHA512:
6
- metadata.gz: 5b7a97f55459f2e123746af8964a305747122c350c75600a5da00c8b73f222d554dc817d5906df6841bb3a41fa2522988d28678e0ebec29d9451303e32888e7b
7
- data.tar.gz: 22eb5f3f4ab974baadcb6f9e16c136ae18ce776ed7c7841f4e55d1cee85d1431897e3c3d00e0e44adc24daac207c7a7782007c922b6a41eefd56712c7d5e61af
6
+ metadata.gz: 942a3f9dab169e653d6c4a75a32e6bda6f54f35207c356c69d2c7b2412031ff7f2ca5f10c92dc8713cc6d567731a8ea420ad2d21f02ecfd1fc1a853996e881b2
7
+ data.tar.gz: 01e710c03b08ec63f3365a370148e3b1861ea3a961a4a9b53cf5d4eef92b65c7a7afebb623c4f9fb0524c0076b4c0e8c600312fb937b6d2fe30be0c01152418d
@@ -12,42 +12,69 @@ module Mihari
12
12
  # @return [String, nil]
13
13
  attr_reader :secret
14
14
 
15
- #
16
- # @param [String] query
17
- # @param [hash, nil] options
18
- # @param [String, nil] id
19
- # @param [String, nil] secret
20
- #
21
- def initialize(query, options: nil, id: nil, secret: nil)
15
+ # @return [String, nil]
16
+ attr_reader :pat
17
+
18
+ # @return [String, nil]
19
+ attr_reader :organization_id
20
+
21
+ # @return [Integer, nil]
22
+ attr_reader :version
23
+
24
+ def initialize(query, version: nil, options: nil, id: nil, secret: nil, pat: nil, organization_id: nil)
22
25
  super(query, options:)
23
26
 
27
+ @version = version || Mihari.config.censys_version
28
+
29
+ # v2
24
30
  @id = id || Mihari.config.censys_id
25
31
  @secret = secret || Mihari.config.censys_secret
32
+ # v3
33
+ @pat = pat || Mihari.config.censys_pat
34
+ @organization_id = organization_id || Mihari.config.censys_organization_id
26
35
  end
27
36
 
28
- #
29
- # @return [Array<Mihari::Models::Artifact>]
30
- #
31
37
  def artifacts
32
- client.search_with_pagination(query, pagination_limit:).map do |res|
33
- res.result.artifacts
34
- end.flatten.uniq(&:data)
38
+ client.search_with_pagination(query, pagination_limit:).flat_map do |res|
39
+ res.artifacts
40
+ end.uniq(&:data)
35
41
  end
36
42
 
37
- #
38
- # @return [Boolean]
39
- #
40
43
  def configured?
41
- configuration_keys? || (id? && secret?)
44
+ case version
45
+ when 2
46
+ v2_configured?
47
+ when 3
48
+ v3_configured?
49
+ else
50
+ false
51
+ end
42
52
  end
43
53
 
44
54
  private
45
55
 
46
- #
47
- # @return [Mihari::Clients::Censys]
48
- #
49
56
  def client
50
- Clients::Censys.new(
57
+ case version
58
+ when 2
59
+ v2_client
60
+ when 3
61
+ v3_client
62
+ else
63
+ raise "Unsupported Censys version: #{version}"
64
+ end
65
+ end
66
+
67
+ def v3_client
68
+ Clients::Censys::V3.new(
69
+ pat:,
70
+ organization_id:,
71
+ pagination_interval:,
72
+ timeout:
73
+ )
74
+ end
75
+
76
+ def v2_client
77
+ Clients::Censys::V2.new(
51
78
  id:,
52
79
  secret:,
53
80
  pagination_interval:,
@@ -55,19 +82,29 @@ module Mihari
55
82
  )
56
83
  end
57
84
 
58
- #
59
- # @return [Boolean]
60
- #
85
+ def v2_configured?
86
+ id? && secret?
87
+ end
88
+
89
+ def v3_configured?
90
+ pat? && organization_id?
91
+ end
92
+
61
93
  def id?
62
94
  !id.nil?
63
95
  end
64
96
 
65
- #
66
- # @return [Boolean]
67
- #
68
97
  def secret?
69
98
  !secret.nil?
70
99
  end
100
+
101
+ def pat?
102
+ !pat.nil?
103
+ end
104
+
105
+ def organization_id?
106
+ !organization_id.nil?
107
+ end
71
108
  end
72
109
  end
73
110
  end
@@ -7,73 +7,106 @@ module Mihari
7
7
  #
8
8
  # Censys API client
9
9
  #
10
- class Censys < Base
11
- #
12
- # @param [String] base_url
13
- # @param [String, nil] id
14
- # @param [String, nil] secret
15
- # @param [Hash] headers
16
- # @param [Integer] pagination_interval
17
- # @param [Integer, nil] timeout
18
- #
19
- def initialize(
20
- base_url = "https://search.censys.io",
21
- id:,
22
- secret:,
23
- headers: {},
24
- pagination_interval: Mihari.config.pagination_interval,
25
- timeout: nil
26
- )
27
- raise(ArgumentError, "id is required") if id.nil?
28
- raise(ArgumentError, "secret is required") if secret.nil?
10
+ module Censys
11
+ class V2 < Base
12
+ #
13
+ # @param [String] base_url
14
+ # @param [String, nil] id
15
+ # @param [String, nil] secret
16
+ # @param [Hash] headers
17
+ # @param [Integer] pagination_interval
18
+ # @param [Integer, nil] timeout
19
+ #
20
+ def initialize(
21
+ base_url = "https://search.censys.io",
22
+ id:,
23
+ secret:,
24
+ headers: {},
25
+ pagination_interval: Mihari.config.pagination_interval,
26
+ timeout: nil
27
+ )
28
+ raise(ArgumentError, "id is required") if id.nil?
29
+ raise(ArgumentError, "secret is required") if secret.nil?
29
30
 
30
- headers["authorization"] = "Basic #{Base64.strict_encode64("#{id}:#{secret}")}"
31
+ headers["authorization"] = "Basic #{Base64.strict_encode64("#{id}:#{secret}")}"
31
32
 
32
- super(base_url, headers:, pagination_interval:, timeout:)
33
- end
33
+ super(base_url, headers:, pagination_interval:, timeout:)
34
+ end
35
+
36
+ #
37
+ # Search current index.
38
+ #
39
+ # Searches the given index for all records that match the given query.
40
+ # For more details, see our documentation: https://search.censys.io/api/v2/docs
41
+ #
42
+ # @param [String] query the query to be executed.
43
+ # @param [Integer, nil] per_page the number of results to be returned for each page.
44
+ # @param [Integer, nil] cursor the cursor of the desired result set.
45
+ #
46
+ # @return [Mihari::Structs::Censys::Response]
47
+ #
48
+ def search(query, per_page: nil, cursor: nil)
49
+ params = {q: query, per_page:, cursor:}.compact
50
+ Structs::Censys::V2::Response.from_dynamic! get_json("/api/v2/hosts/search", params:)
51
+ end
52
+
53
+ #
54
+ # @param [String] query
55
+ # @param [Integer, nil] per_page
56
+ # @param [Integer] pagination_limit
57
+ #
58
+ # @return [Enumerable<Mihari::Structs::Censys::Response>]
59
+ #
60
+ def search_with_pagination(query, per_page: nil, pagination_limit: Mihari.config.pagination_limit)
61
+ cursor = nil
62
+
63
+ Enumerator.new do |y|
64
+ pagination_limit.times do
65
+ res = search(query, per_page:, cursor:)
34
66
 
35
- #
36
- # Search current index.
37
- #
38
- # Searches the given index for all records that match the given query.
39
- # For more details, see our documentation: https://search.censys.io/api/v2/docs
40
- #
41
- # @param [String] query the query to be executed.
42
- # @param [Integer, nil] per_page the number of results to be returned for each page.
43
- # @param [Integer, nil] cursor the cursor of the desired result set.
44
- #
45
- # @return [Mihari::Structs::Censys::Response]
46
- #
47
- def search(query, per_page: nil, cursor: nil)
48
- params = {q: query, per_page:, cursor:}.compact
49
- Structs::Censys::Response.from_dynamic! get_json("/api/v2/hosts/search", params:)
67
+ y.yield res
68
+
69
+ cursor = res.result.links.next
70
+ # NOTE: Censys's search API is unstable recently
71
+ # it may returns empty links or empty string cursors
72
+ # - Empty links: "links": {}
73
+ # - Empty cursors: "links": { "next": "", "prev": "" }
74
+ # So it needs to check both cases
75
+ break if cursor.nil? || cursor.empty?
76
+
77
+ sleep_pagination_interval
78
+ end
79
+ end
80
+ end
50
81
  end
51
82
 
52
- #
53
- # @param [String] query
54
- # @param [Integer, nil] per_page
55
- # @param [Integer] pagination_limit
56
- #
57
- # @return [Enumerable<Mihari::Structs::Censys::Response>]
58
- #
59
- def search_with_pagination(query, per_page: nil, pagination_limit: Mihari.config.pagination_limit)
60
- cursor = nil
83
+ class V3 < Base
84
+ def initialize(base_url = "https://api.platform.censys.io", pat:, organization_id:, headers: {}, pagination_interval: Mihari.config.pagination_interval, timeout: nil)
85
+ raise(ArgumentError, "pat is required") if pat.nil?
86
+ raise(ArgumentError, "organization_id is required") if organization_id.nil?
61
87
 
62
- Enumerator.new do |y|
63
- pagination_limit.times do
64
- res = search(query, per_page:, cursor:)
88
+ headers["Authorization"] = "Bearer #{pat}"
89
+ headers["Accept"] = "application/vnd.censys.api.v3.host.v1+json"
90
+ headers["X-Organization-ID"] = organization_id
65
91
 
66
- y.yield res
92
+ super(base_url, headers: headers, pagination_interval: pagination_interval, timeout: timeout)
93
+ end
67
94
 
68
- cursor = res.result.links.next
69
- # NOTE: Censys's search API is unstable recently
70
- # it may returns empty links or empty string cursors
71
- # - Empty links: "links": {}
72
- # - Empty cursors: "links": { "next": "", "prev": "" }
73
- # So it needs to check both cases
74
- break if cursor.nil? || cursor.empty?
95
+ def search(query, page_size: nil, page_token: nil)
96
+ json = {query: query, page_size:, page_token:}.compact
97
+ Structs::Censys::V3::Response.from_dynamic! post_json("/v3/global/search/query", json:)
98
+ end
75
99
 
76
- sleep_pagination_interval
100
+ def search_with_pagination(query, page_size: nil, pagination_limit: Mihari.config.pagination_limit)
101
+ page_token = nil
102
+ Enumerator.new do |y|
103
+ pagination_limit.times do
104
+ res = search(query, page_size:, page_token:)
105
+ y.yield res
106
+ page_token = res.result&.next_page_token
107
+ break if page_token.nil? || page_token.empty?
108
+ sleep_pagination_interval
109
+ end
77
110
  end
78
111
  end
79
112
  end
data/lib/mihari/config.rb CHANGED
@@ -11,6 +11,9 @@ module Mihari
11
11
  # analyzers, emitters & enrichers
12
12
  censys_id: nil,
13
13
  censys_secret: nil,
14
+ censys_pat: nil,
15
+ censys_version: 2,
16
+ censys_organization_id: nil,
14
17
  circl_passive_password: nil,
15
18
  circl_passive_username: nil,
16
19
  database_url: URI("sqlite3:mihari.db"),
@@ -50,9 +50,14 @@ module Mihari
50
50
  Censys = Dry::Schema.Params do
51
51
  required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::Censys.keys))
52
52
  required(:query).filled(:string)
53
+ optional(:version).value(Types::Coercible::Integer.enum(2, 3)).default(2)
54
+ optional(:options).hash(AnalyzerPaginationOptions)
55
+ # v2
53
56
  optional(:id).filled(:string)
54
57
  optional(:secret).filled(:string)
55
- optional(:options).hash(AnalyzerPaginationOptions)
58
+ # v3
59
+ optional(:pat).filled(:string)
60
+ optional(:organization_id).filled(:string)
56
61
  end
57
62
 
58
63
  CIRCL = Dry::Schema.Params do
@@ -82,6 +87,7 @@ module Mihari
82
87
  Urlscan = Dry::Schema.Params do
83
88
  required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::Urlscan.keys))
84
89
  required(:query).filled(:string)
90
+ optional(:api_key).filled(:string)
85
91
  optional(:data_types).filled(array[Types::NetworkDataTypes]).default(Types::NetworkDataTypes.values)
86
92
  optional(:options).hash(AnalyzerPaginationOptions)
87
93
  end
@@ -89,6 +95,7 @@ module Mihari
89
95
  ZoomEye = Dry::Schema.Params do
90
96
  required(:analyzer).value(Types::String.enum(*Mihari::Analyzers::ZoomEye.keys))
91
97
  required(:query).filled(:string)
98
+ optional(:api_key).filled(:string)
92
99
  optional(:data_types).filled(array[Types::NetworkDataTypes]).default(Types::NetworkDataTypes.values)
93
100
  optional(:options).hash(AnalyzerPaginationOptions)
94
101
  end
@@ -6,9 +6,10 @@ require "mihari/sidekiq/jobs"
6
6
 
7
7
  Sidekiq.configure_server do |config|
8
8
  config.redis = {url: Mihari.config.sidekiq_redis_url.to_s}
9
- config.default_job_options = {retry: Mihari.config.sidekiq_retry}
10
9
  end
11
10
 
11
+ Sidekiq.default_job_options = {retry: Mihari.config.sidekiq_retry}
12
+
12
13
  Sidekiq.configure_client do |config|
13
14
  config.redis = {url: Mihari.config.sidekiq_redis_url.to_s}
14
15
  end