mihari 5.4.2 → 5.4.3

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 (44) hide show
  1. checksums.yaml +4 -4
  2. data/lib/mihari/analyzers/base.rb +0 -4
  3. data/lib/mihari/analyzers/binaryedge.rb +4 -44
  4. data/lib/mihari/analyzers/censys.rb +4 -20
  5. data/lib/mihari/analyzers/circl.rb +2 -26
  6. data/lib/mihari/analyzers/crtsh.rb +2 -17
  7. data/lib/mihari/analyzers/dnstwister.rb +1 -3
  8. data/lib/mihari/analyzers/greynoise.rb +5 -4
  9. data/lib/mihari/analyzers/hunterhow.rb +8 -23
  10. data/lib/mihari/analyzers/onyphe.rb +5 -39
  11. data/lib/mihari/analyzers/otx.rb +2 -38
  12. data/lib/mihari/analyzers/passivetotal.rb +3 -41
  13. data/lib/mihari/analyzers/securitytrails.rb +3 -41
  14. data/lib/mihari/analyzers/shodan.rb +7 -39
  15. data/lib/mihari/analyzers/urlscan.rb +2 -38
  16. data/lib/mihari/analyzers/virustotal_intelligence.rb +2 -25
  17. data/lib/mihari/analyzers/zoomeye.rb +17 -83
  18. data/lib/mihari/clients/base.rb +9 -1
  19. data/lib/mihari/clients/binaryedge.rb +27 -2
  20. data/lib/mihari/clients/censys.rb +32 -2
  21. data/lib/mihari/clients/circl.rb +28 -1
  22. data/lib/mihari/clients/crtsh.rb +9 -2
  23. data/lib/mihari/clients/dnstwister.rb +4 -2
  24. data/lib/mihari/clients/greynoise.rb +31 -4
  25. data/lib/mihari/clients/hunterhow.rb +41 -3
  26. data/lib/mihari/clients/onyphe.rb +25 -3
  27. data/lib/mihari/clients/otx.rb +40 -0
  28. data/lib/mihari/clients/passivetotal.rb +33 -15
  29. data/lib/mihari/clients/securitytrails.rb +44 -0
  30. data/lib/mihari/clients/shodan.rb +30 -2
  31. data/lib/mihari/clients/urlscan.rb +32 -6
  32. data/lib/mihari/clients/virustotal.rb +29 -4
  33. data/lib/mihari/clients/zoomeye.rb +53 -2
  34. data/lib/mihari/commands/web.rb +1 -1
  35. data/lib/mihari/config.rb +1 -1
  36. data/lib/mihari/structs/censys.rb +11 -11
  37. data/lib/mihari/structs/greynoise.rb +17 -8
  38. data/lib/mihari/structs/onyphe.rb +7 -7
  39. data/lib/mihari/structs/shodan.rb +5 -5
  40. data/lib/mihari/structs/urlscan.rb +3 -3
  41. data/lib/mihari/structs/virustotal_intelligence.rb +3 -3
  42. data/lib/mihari/version.rb +1 -1
  43. data/mihari.gemspec +7 -7
  44. metadata +16 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 720f1926ff4ec5f63436731bb639dd6de8d3ff7e3071d9c1b70602425829d711
4
- data.tar.gz: 3fef4921ee2f23513d8b110289f64ae9f500344a99cd0d1149df259929109e73
3
+ metadata.gz: 53a27dd7a778ef0678eddbf4f48f2ba19c476873a46a2337432d55b178321c70
4
+ data.tar.gz: 2518b10896081dcdb329f0f3caec21093d6dd980efcec545ed5f56a1bc569e49
5
5
  SHA512:
6
- metadata.gz: a1c20f24dcc870dfbcd924a2c8f24e995795133fe75cde624391fdc958745ffb165bae0831bf40890d0ca9d850907b528ecad0ee9d664e48e6b3617d8e744b44
7
- data.tar.gz: d3322c315fca18d7c6da05c38acabaca60c39dce2c6f3d666740228c7208ce72bbebc455f9fec8de738959ba0023335d084d0cf2996f306da062589281a755a0
6
+ metadata.gz: '085565b584d7e0c888fca6d4ba9ddb1c2f462201243df060e157ab1f5ec70c12261475af8c9304ffe21ead8cc39398dbb37e7e438ab3bad9ab28bb99aa4d760b'
7
+ data.tar.gz: e4964d0298b5dc0c49402cd0b04762b3c17e4b34d028ead1c3076b7ed7adfc7b4c9c40591559e1b2822f3c69e7e8e9e8d35b861ddfd670cf9bb071c103b607a1
@@ -82,10 +82,6 @@ module Mihari
82
82
 
83
83
  private
84
84
 
85
- def sleep_interval
86
- sleep(interval) if interval
87
- end
88
-
89
85
  class << self
90
86
  #
91
87
  # Initialize an analyzer by query params
@@ -18,16 +18,13 @@ module Mihari
18
18
  end
19
19
 
20
20
  def artifacts
21
- results = search
22
- return [] unless results || results.empty?
23
-
24
- results.map do |result|
25
- events = result["events"] || []
21
+ client.search_with_pagination(query, pagination_limit: pagination_limit).map do |res|
22
+ events = res["events"] || []
26
23
  events.filter_map do |event|
27
24
  data = event.dig("target", "ip")
28
25
  data.nil? ? nil : Artifact.new(data: data, source: source, metadata: event)
29
26
  end
30
- end.flatten
27
+ end
31
28
  end
32
29
 
33
30
  def configuration_keys
@@ -36,49 +33,12 @@ module Mihari
36
33
 
37
34
  private
38
35
 
39
- PAGE_SIZE = 20
40
-
41
- #
42
- # Search with pagination
43
- #
44
- # @param [Integer] page
45
- #
46
- # @return [Hash]
47
- #
48
- def search_with_page(page: 1)
49
- client.search(query, page: page)
50
- rescue StatusCodeError => e
51
- raise RetryableError, e if e.message.include?("Request time limit exceeded")
52
-
53
- raise e
54
- end
55
-
56
- #
57
- # Search
58
- #
59
- # @return [Array<Hash>]
60
- #
61
- def search
62
- responses = []
63
- (1..pagination_limit).each do |page|
64
- res = search_with_page(page: page)
65
- total = res["total"].to_i
66
-
67
- responses << res
68
- break if total <= page * PAGE_SIZE
69
-
70
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
71
- sleep_interval
72
- end
73
- responses
74
- end
75
-
76
36
  #
77
37
  #
78
38
  # @return [Mihari::Clients::BinaryEdge]
79
39
  #
80
40
  def client
81
- @client ||= Clients::BinaryEdge.new(api_key: api_key)
41
+ @client ||= Clients::BinaryEdge.new(api_key: api_key, interval: interval)
82
42
  end
83
43
  end
84
44
  end
@@ -27,25 +27,9 @@ module Mihari
27
27
  # @return [Array<Mihari::Artifact>]
28
28
  #
29
29
  def artifacts
30
- artifacts = []
31
-
32
- cursor = nil
33
- pagination_limit.times do
34
- response = client.search(query, cursor: cursor)
35
- artifacts << response.result.to_artifacts
36
- cursor = response.result.links.next
37
- # NOTE: Censys's search API is unstable recently
38
- # it may returns empty links or empty string cursors
39
- # - Empty links: "links": {}
40
- # - Empty cursors: "links": { "next": "", "prev": "" }
41
- # So it needs to check both cases
42
- break if cursor.nil? || cursor.empty?
43
-
44
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
45
- sleep_interval
46
- end
47
-
48
- artifacts.flatten.uniq(&:data)
30
+ client.search_with_pagination(query, pagination_limit: pagination_limit).map do |res|
31
+ res.result.artifacts
32
+ end.flatten.uniq(&:data)
49
33
  end
50
34
 
51
35
  #
@@ -68,7 +52,7 @@ module Mihari
68
52
  # @return [Mihari::Clients::Censys]
69
53
  #
70
54
  def client
71
- @client ||= Clients::Censys.new(id: id, secret: secret)
55
+ @client ||= Clients::Censys.new(id: id, secret: secret, interval: interval)
72
56
  end
73
57
 
74
58
  #
@@ -32,9 +32,9 @@ module Mihari
32
32
  def artifacts
33
33
  case type
34
34
  when "domain"
35
- passive_dns_search
35
+ client.passive_dns_search query
36
36
  when "hash"
37
- passive_ssl_search
37
+ client.passive_ssl_search query
38
38
  else
39
39
  raise InvalidInputError, "#{@query}(type: #{@type || "unknown"}) is not supported."
40
40
  end
@@ -54,30 +54,6 @@ module Mihari
54
54
  @client ||= Clients::CIRCL.new(username: username, password: password)
55
55
  end
56
56
 
57
- #
58
- # Passive DNS search
59
- #
60
- # @return [Array<String>]
61
- #
62
- def passive_dns_search
63
- results = client.dns_query(query)
64
- results.filter_map do |result|
65
- type = result["rrtype"]
66
- (type == "A") ? result["rdata"] : nil
67
- end.uniq
68
- end
69
-
70
- #
71
- # Passive SSL search
72
- #
73
- # @return [Array<String>]
74
- #
75
- def passive_ssl_search
76
- result = client.ssl_cquery(query)
77
- seen = result["seen"] || []
78
- seen.uniq
79
- end
80
-
81
57
  def username?
82
58
  !username.nil?
83
59
  end
@@ -18,13 +18,8 @@ module Mihari
18
18
  end
19
19
 
20
20
  def artifacts
21
- results = search
22
- results.map do |result|
23
- values = result["name_value"].to_s.lines.map(&:chomp)
24
- values.map do |value|
25
- Artifact.new(data: value, source: source, metadata: result)
26
- end
27
- end.flatten
21
+ exclude = exclude_expired ? "expired" : nil
22
+ client.search(query, exclude: exclude)
28
23
  end
29
24
 
30
25
  private
@@ -35,16 +30,6 @@ module Mihari
35
30
  def client
36
31
  @client ||= Mihari::Clients::Crtsh.new
37
32
  end
38
-
39
- #
40
- # Search
41
- #
42
- # @return [Array<Hash>]
43
- #
44
- def search
45
- exclude = exclude_expired ? "expired" : nil
46
- client.search(query, exclude: exclude)
47
- end
48
33
  end
49
34
  end
50
35
  end
@@ -21,9 +21,7 @@ module Mihari
21
21
  def artifacts
22
22
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
23
23
 
24
- res = client.fuzz(query)
25
- fuzzy_domains = res["fuzzy_domains"] || []
26
- domains = fuzzy_domains.map { |domain| domain["domain"] }
24
+ domains = client.fuzz(query)
27
25
  Parallel.map(domains) do |domain|
28
26
  resolvable?(domain) ? domain : nil
29
27
  end.compact
@@ -3,8 +3,6 @@
3
3
  module Mihari
4
4
  module Analyzers
5
5
  class GreyNoise < Base
6
- PAGE_SIZE = 10_000
7
-
8
6
  # @return [String, nil]
9
7
  attr_reader :api_key
10
8
 
@@ -20,7 +18,10 @@ module Mihari
20
18
  end
21
19
 
22
20
  def artifacts
23
- client.gnql_search(query, size: PAGE_SIZE).to_artifacts
21
+ client.gnql_search_with_pagination(
22
+ query,
23
+ pagination_limit: pagination_limit
24
+ ).map(&:artifacts).flatten
24
25
  end
25
26
 
26
27
  def configuration_keys
@@ -30,7 +31,7 @@ module Mihari
30
31
  private
31
32
 
32
33
  def client
33
- @client ||= Clients::GreyNoise.new(api_key: api_key)
34
+ @client ||= Clients::GreyNoise.new(api_key: api_key, interval: interval)
34
35
  end
35
36
  end
36
37
  end
@@ -30,25 +30,13 @@ module Mihari
30
30
  # @return [Array<Mihari::Artifact>]
31
31
  #
32
32
  def artifacts
33
- artifacts = []
34
-
35
- (1..pagination_limit).each do |page|
36
- res = client.search(
37
- query,
38
- page: page,
39
- page_size: PAGE_SIZE,
40
- start_time: start_time.strftime("%Y-%m-%d"),
41
- end_time: end_time.strftime("%Y-%m-%d")
42
- )
43
-
44
- artifacts << res.data.artifacts
45
-
46
- break if res.data.list.length < PAGE_SIZE
47
-
48
- sleep_interval
49
- end
50
-
51
- artifacts.flatten
33
+ client.search_with_pagination(
34
+ query,
35
+ start_time: start_time.strftime("%Y-%m-%d"),
36
+ end_time: end_time.strftime("%Y-%m-%d")
37
+ ).map do |res|
38
+ res.data.artifacts
39
+ end.flatten
52
40
  end
53
41
 
54
42
  def configuration_keys
@@ -57,11 +45,8 @@ module Mihari
57
45
 
58
46
  private
59
47
 
60
- # @return [Integer]
61
- PAGE_SIZE = 100
62
-
63
48
  def client
64
- @client ||= Clients::HunterHow.new(api_key: api_key)
49
+ @client ||= Clients::HunterHow.new(api_key: api_key, interval: interval)
65
50
  end
66
51
  end
67
52
  end
@@ -20,10 +20,10 @@ module Mihari
20
20
  end
21
21
 
22
22
  def artifacts
23
- responses = search
24
- return [] unless responses
25
-
26
- responses.map(&:to_artifacts).flatten
23
+ client.datascan_with_pagination(
24
+ query,
25
+ pagination_limit: pagination_limit
26
+ ).map(&:artifacts).flatten
27
27
  end
28
28
 
29
29
  def configuration_keys
@@ -32,42 +32,8 @@ module Mihari
32
32
 
33
33
  private
34
34
 
35
- PAGE_SIZE = 10
36
-
37
35
  def client
38
- @client ||= Clients::Onyphe.new(api_key: api_key)
39
- end
40
-
41
- #
42
- # Search with pagination
43
- #
44
- # @param [String] query
45
- # @param [Integer] page
46
- #
47
- # @return [Structs::Onyphe::Response]
48
- #
49
- def search_with_page(query, page: 1)
50
- client.datascan(query, page: page)
51
- end
52
-
53
- #
54
- # Search
55
- #
56
- # @return [Array<Structs::Onyphe::Response>]
57
- #
58
- def search
59
- responses = []
60
- (1..pagination_limit).each do |page|
61
- res = search_with_page(query, page: page)
62
- responses << res
63
-
64
- total = res.total
65
- break if total <= page * PAGE_SIZE
66
-
67
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
68
- sleep_interval
69
- end
70
- responses
36
+ @client ||= Clients::Onyphe.new(api_key: api_key, interval: interval)
71
37
  end
72
38
  end
73
39
  end
@@ -27,9 +27,9 @@ module Mihari
27
27
  def artifacts
28
28
  case type
29
29
  when "domain"
30
- domain_search
30
+ client.domain_search(query)
31
31
  when "ip"
32
- ip_search
32
+ client.ip_search(query)
33
33
  else
34
34
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
35
35
  end
@@ -53,42 +53,6 @@ module Mihari
53
53
  def valid_type?
54
54
  %w[ip domain].include? type
55
55
  end
56
-
57
- #
58
- # Domain search
59
- #
60
- # @return [Array<String>]
61
- #
62
- def domain_search
63
- res = client.query_by_domain(query)
64
- return [] if res.nil?
65
-
66
- records = res["passive_dns"] || []
67
- records.filter_map do |record|
68
- record_type = record["record_type"]
69
- address = record["address"]
70
-
71
- address if record_type == "A"
72
- end.uniq
73
- end
74
-
75
- #
76
- # IP search
77
- #
78
- # @return [Array<String>]
79
- #
80
- def ip_search
81
- res = client.query_by_ip(query)
82
- return [] if res.nil?
83
-
84
- records = res["passive_dns"] || []
85
- records.filter_map do |record|
86
- record_type = record["record_type"]
87
- hostname = record["hostname"]
88
-
89
- hostname if record_type == "A"
90
- end.uniq
91
- end
92
56
  end
93
57
  end
94
58
  end
@@ -32,11 +32,11 @@ module Mihari
32
32
  def artifacts
33
33
  case type
34
34
  when "domain", "ip"
35
- passive_dns_search
35
+ client.passive_dns_search query
36
36
  when "mail"
37
- reverse_whois_search
37
+ client.reverse_whois_search query
38
38
  when "hash"
39
- ssl_search
39
+ client.ssl_search query
40
40
  else
41
41
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
42
42
  end
@@ -65,44 +65,6 @@ module Mihari
65
65
  %w[ip domain mail hash].include? type
66
66
  end
67
67
 
68
- #
69
- # Passive DNS search
70
- #
71
- # @return [Array<String>]
72
- #
73
- def passive_dns_search
74
- res = client.passive_dns_search(query)
75
- res["results"] || []
76
- end
77
-
78
- #
79
- # Reverse whois search
80
- #
81
- # @return [Array<Mihari::Artifact>]
82
- #
83
- def reverse_whois_search
84
- res = client.reverse_whois_search(query: query, field: "email")
85
- results = res["results"] || []
86
- results.map do |result|
87
- data = result["domain"]
88
- Artifact.new(data: data, source: source, metadata: result)
89
- end.flatten
90
- end
91
-
92
- #
93
- # Passive SSL search
94
- #
95
- # @return [Array<Mihari::Artifact>]
96
- #
97
- def ssl_search
98
- res = client.ssl_search(query)
99
- results = res["results"] || []
100
- results.map do |result|
101
- data = result["ipAddresses"]
102
- data.map { |d| Artifact.new(data: d, source: source, metadata: result) }
103
- end.flatten
104
- end
105
-
106
68
  def username?
107
69
  !username.nil?
108
70
  end
@@ -30,11 +30,11 @@ module Mihari
30
30
  def artifacts
31
31
  case type
32
32
  when "domain"
33
- domain_search
33
+ client.domain_search query
34
34
  when "ip"
35
- ip_search
35
+ client.ip_search query
36
36
  when "mail"
37
- mail_search
37
+ client.mail_search query
38
38
  else
39
39
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
40
40
  end
@@ -58,44 +58,6 @@ module Mihari
58
58
  def valid_type?
59
59
  %w[ip domain mail].include? type
60
60
  end
61
-
62
- #
63
- # Domain search
64
- #
65
- # @return [Array<String>]
66
- #
67
- def domain_search
68
- records = client.get_all_dns_history(query, type: "a")
69
- records.map do |record|
70
- (record["values"] || []).map { |value| value["ip"] }
71
- end.flatten.compact.uniq
72
- end
73
-
74
- #
75
- # IP search
76
- #
77
- # @return [Array<Mihari::Artifact>]
78
- #
79
- def ip_search
80
- records = client.search_by_ip(query)
81
- records.filter_map do |record|
82
- data = record["hostname"]
83
- Artifact.new(data: data, source: source, metadata: record)
84
- end
85
- end
86
-
87
- #
88
- # Mail search
89
- #
90
- # @return [Array<String>]
91
- #
92
- def mail_search
93
- records = client.search_by_mail(query)
94
- records.filter_map do |record|
95
- data = record["hostname"]
96
- Artifact.new(data: data, source: source, metadata: record)
97
- end
98
- end
99
61
  end
100
62
  end
101
63
  end
@@ -18,10 +18,10 @@ module Mihari
18
18
  end
19
19
 
20
20
  def artifacts
21
- results = search
22
- return [] if results.empty?
23
-
24
- results.map(&:to_artifacts).flatten.uniq(&:data)
21
+ client.search_with_pagination(
22
+ query,
23
+ pagination_limit: pagination_limit
24
+ ).map(&:artifacts).flatten.uniq(&:data)
25
25
  end
26
26
 
27
27
  def configuration_keys
@@ -30,43 +30,11 @@ module Mihari
30
30
 
31
31
  private
32
32
 
33
- PAGE_SIZE = 100
34
-
35
- def client
36
- @client ||= Clients::Shodan.new(api_key: api_key)
37
- end
38
-
39
- #
40
- # Search with pagination
41
- #
42
- # @param [Integer] page
43
- #
44
- # @return [Structs::Shodan::Result]
45
- #
46
- def search_with_page(page: 1)
47
- client.search(query, page: page)
48
- end
49
-
50
33
  #
51
- # Search
34
+ # @return [Clients::Shodan]
52
35
  #
53
- # @return [Array<Structs::Shodan::Result>]
54
- #
55
- def search
56
- responses = []
57
- (1..pagination_limit).each do |page|
58
- res = search_with_page(page: page)
59
- responses << res
60
- break if res.total <= page * PAGE_SIZE
61
-
62
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
63
- sleep_interval
64
- rescue JSON::ParserError
65
- # ignore JSON::ParserError
66
- # ref. https://github.com/ninoseki/mihari/issues/197
67
- next
68
- end
69
- responses
36
+ def client
37
+ @client ||= Clients::Shodan.new(api_key: api_key, interval: interval)
70
38
  end
71
39
  end
72
40
  end
@@ -4,7 +4,6 @@ module Mihari
4
4
  module Analyzers
5
5
  class Urlscan < Base
6
6
  SUPPORTED_DATA_TYPES = %w[url domain ip].freeze
7
- SIZE = 1000
8
7
 
9
8
  # @return [String, nil]
10
9
  attr_reader :api_key
@@ -30,9 +29,8 @@ module Mihari
30
29
  end
31
30
 
32
31
  def artifacts
33
- responses = search
34
32
  # @type [Array<Mihari::Artifact>]
35
- artifacts = responses.map { |res| res.to_artifacts }.flatten
33
+ artifacts = client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
36
34
 
37
35
  artifacts.select do |artifact|
38
36
  allowed_data_types.include? artifact.data_type
@@ -46,41 +44,7 @@ module Mihari
46
44
  private
47
45
 
48
46
  def client
49
- @client ||= Clients::UrlScan.new(api_key: api_key)
50
- end
51
-
52
- #
53
- # Search with search_after option
54
- #
55
- # @return [Structs::Urlscan::Response]
56
- #
57
- def search_with_search_after(search_after: nil)
58
- res = client.search(query, size: SIZE, search_after: search_after)
59
- Structs::Urlscan::Response.from_dynamic! res
60
- end
61
-
62
- #
63
- # Search
64
- #
65
- # @return [Array<Structs::Urlscan::Response>]
66
- #
67
- def search
68
- responses = []
69
-
70
- search_after = nil
71
- pagination_limit.times do
72
- res = search_with_search_after(search_after: search_after)
73
- responses << res
74
-
75
- break if res.results.length < SIZE
76
-
77
- search_after = res.results.last.sort.join(",")
78
-
79
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
80
- sleep_interval
81
- end
82
-
83
- responses
47
+ @client ||= Clients::UrlScan.new(api_key: api_key, interval: interval)
84
48
  end
85
49
 
86
50
  #
@@ -18,7 +18,7 @@ module Mihari
18
18
  end
19
19
 
20
20
  def artifacts
21
- search_with_cursor.map(&:to_artifacts).flatten
21
+ client.intel_search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
22
22
  end
23
23
 
24
24
  def configuration_keys
@@ -33,30 +33,7 @@ module Mihari
33
33
  # @return [::VirusTotal::API]
34
34
  #
35
35
  def client
36
- @client = Clients::VirusTotal.new(api_key: api_key)
37
- end
38
-
39
- #
40
- # Search with cursor
41
- #
42
- # @return [Array<Structs::VirusTotalIntelligence::Response>]
43
- #
44
- def search_with_cursor
45
- cursor = nil
46
- responses = []
47
-
48
- pagination_limit.times do
49
- response = Structs::VirusTotalIntelligence::Response.from_dynamic!(client.intel_search(query,
50
- cursor: cursor))
51
- responses << response
52
- break if response.meta.cursor.nil?
53
-
54
- cursor = response.meta.cursor
55
- # sleep #{interval} seconds to avoid the rate limitation (if it is set)
56
- sleep_interval
57
- end
58
-
59
- responses
36
+ @client = Clients::VirusTotal.new(api_key: api_key, interval: interval)
60
37
  end
61
38
  end
62
39
  end