mihari 5.0.1 → 5.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +1 -1
  3. data/docker/Dockerfile +1 -1
  4. data/lib/mihari/analyzers/binaryedge.rb +9 -7
  5. data/lib/mihari/analyzers/censys.rb +3 -5
  6. data/lib/mihari/analyzers/circl.rb +4 -6
  7. data/lib/mihari/analyzers/crtsh.rb +6 -7
  8. data/lib/mihari/analyzers/dnpedia.rb +3 -7
  9. data/lib/mihari/analyzers/dnstwister.rb +3 -5
  10. data/lib/mihari/analyzers/feed.rb +12 -10
  11. data/lib/mihari/analyzers/greynoise.rb +3 -5
  12. data/lib/mihari/analyzers/onyphe.rb +3 -4
  13. data/lib/mihari/analyzers/otx.rb +1 -3
  14. data/lib/mihari/analyzers/passivetotal.rb +5 -7
  15. data/lib/mihari/analyzers/pulsedive.rb +5 -7
  16. data/lib/mihari/analyzers/shodan.rb +3 -9
  17. data/lib/mihari/analyzers/urlscan.rb +7 -6
  18. data/lib/mihari/analyzers/virustotal.rb +4 -6
  19. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -5
  20. data/lib/mihari/analyzers/zoomeye.rb +4 -10
  21. data/lib/mihari/cli/database.rb +11 -0
  22. data/lib/mihari/cli/main.rb +10 -4
  23. data/lib/mihari/cli/rule.rb +11 -0
  24. data/lib/mihari/clients/base.rb +53 -0
  25. data/lib/mihari/clients/binaryedge.rb +33 -0
  26. data/lib/mihari/clients/censys.rb +42 -0
  27. data/lib/mihari/clients/circl.rb +59 -0
  28. data/lib/mihari/clients/crtsh.rb +31 -0
  29. data/lib/mihari/clients/dnpedia.rb +64 -0
  30. data/lib/mihari/clients/dnstwister.rb +40 -0
  31. data/lib/mihari/clients/greynoise.rb +29 -0
  32. data/lib/mihari/clients/misp.rb +24 -0
  33. data/lib/mihari/clients/onyphe.rb +23 -0
  34. data/lib/mihari/clients/otx.rb +29 -0
  35. data/lib/mihari/clients/passivetotal.rb +65 -0
  36. data/lib/mihari/clients/publsedive.rb +39 -0
  37. data/lib/mihari/clients/shodan.rb +30 -0
  38. data/lib/mihari/clients/the_hive.rb +28 -0
  39. data/lib/mihari/clients/urlscan.rb +31 -0
  40. data/lib/mihari/clients/virustotal.rb +56 -0
  41. data/lib/mihari/clients/zoomeye.rb +68 -0
  42. data/lib/mihari/commands/database.rb +28 -0
  43. data/lib/mihari/commands/{initializer.rb → rule.rb} +27 -6
  44. data/lib/mihari/commands/searcher.rb +5 -0
  45. data/lib/mihari/database.rb +8 -22
  46. data/lib/mihari/emitters/misp.rb +13 -20
  47. data/lib/mihari/emitters/the_hive.rb +3 -5
  48. data/lib/mihari/emitters/webhook.rb +2 -2
  49. data/lib/mihari/feed/reader.rb +14 -11
  50. data/lib/mihari/http.rb +29 -21
  51. data/lib/mihari/mixins/database.rb +2 -0
  52. data/lib/mihari/mixins/retriable.rb +3 -1
  53. data/lib/mihari/schemas/analyzer.rb +5 -4
  54. data/lib/mihari/version.rb +1 -1
  55. data/lib/mihari.rb +21 -0
  56. data/mihari.gemspec +14 -20
  57. metadata +61 -238
  58. data/lib/mihari/analyzers/clients/otx.rb +0 -36
  59. data/lib/mihari/commands/validator.rb +0 -31
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b7944fcbb2ef6b1ff7fccbe5c8158bd21a186b05e8fae70a6700256dce10adbb
4
- data.tar.gz: 36605153506952b323be6e3a7646fd4446f280943fc6c587d7885e8eec413c33
3
+ metadata.gz: e19317302956178dc4302543d81a0920018aa384595f91c69dd70110086d575a
4
+ data.tar.gz: 80d6314c2df13a4a28ec71a0d4b358e74ab0ee9778d818658a997c1fd821f062
5
5
  SHA512:
6
- metadata.gz: ba53c1fb987ffd933017ccc64a3a72adc032de81a377e34684c4927304d295d85531ad11e796abd3c17489411fcf15eedd494d7ff7a8b7d0c53fdeb511eb5a8d
7
- data.tar.gz: 6dff687f32dfef7f0cc19b76cba77a6233ebbefa9b90f522f37092468370eb5abb0e7f185d86f74077944cb0c76609b01390e7878ca494a82419ac44e59d93e5
6
+ metadata.gz: b54bffc456bc114a2a8b52e5acbcc3f30d7571124fc9431fbda209bb57910eabe7950d86c50ef750c41d5df604a5aa08c9affb25d434db8a4f53d85ba8ae4921
7
+ data.tar.gz: 4bce535d8d6d2573102b0197984854b84628a08ab37855c2a7f7fb1574b701e6b4ca816d3b23b3719d7cde0b7de89753af3b386d43af39e422c7c06b1d65448c
data/.rspec CHANGED
@@ -1,3 +1,3 @@
1
- --format documentation
1
+ --format Fuubar
2
2
  --color
3
3
  --require spec_helper
data/docker/Dockerfile CHANGED
@@ -3,7 +3,7 @@ FROM ruby:3.1.3-alpine3.17
3
3
  RUN apk --no-cache add git build-base ruby-dev sqlite-dev postgresql-dev mysql-client mysql-dev && \
4
4
  gem install pg mysql2
5
5
 
6
- ARG MIHARI_VERSION=4.11.0
6
+ ARG MIHARI_VERSION=5.1.0
7
7
 
8
8
  RUN gem install mihari -v ${MIHARI_VERSION}
9
9
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "binaryedge"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class BinaryEdge < Base
@@ -44,8 +42,8 @@ module Mihari
44
42
  # @return [Hash]
45
43
  #
46
44
  def search_with_page(query, page: 1)
47
- api.host.search(query, page: page)
48
- rescue ::BinaryEdge::Error => e
45
+ client.search(query, page: page)
46
+ rescue UnsuccessfulStatusCodeError => e
49
47
  raise RetryableError, e if e.message.include?("Request time limit exceeded")
50
48
 
51
49
  raise e
@@ -58,7 +56,7 @@ module Mihari
58
56
  #
59
57
  def search
60
58
  responses = []
61
- (1..Float::INFINITY).each do |page|
59
+ (1..500).each do |page|
62
60
  res = search_with_page(query, page: page)
63
61
  total = res["total"].to_i
64
62
 
@@ -75,8 +73,12 @@ module Mihari
75
73
  %w[binaryedge_api_key]
76
74
  end
77
75
 
78
- def api
79
- @api ||= ::BinaryEdge::API.new(api_key)
76
+ #
77
+ #
78
+ # @return [Mihari::Clients::BinaryEdge]
79
+ #
80
+ def client
81
+ @client ||= Clients::BinaryEdge.new(api_key: api_key)
80
82
  end
81
83
  end
82
84
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "censysx"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class Censys < Base
@@ -42,7 +40,7 @@ module Mihari
42
40
 
43
41
  cursor = nil
44
42
  loop do
45
- response = api.search(query, cursor: cursor)
43
+ response = client.search(query, cursor: cursor)
46
44
  response = Structs::Censys::Response.from_dynamic!(response)
47
45
 
48
46
  artifacts << response_to_artifacts(response)
@@ -106,8 +104,8 @@ module Mihari
106
104
  %w[censys_id censys_secret]
107
105
  end
108
106
 
109
- def api
110
- @api ||= ::Censys::API.new(id, secret)
107
+ def client
108
+ @client ||= Clients::Censys.new(id: id, secret: secret)
111
109
  end
112
110
 
113
111
  def id?
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "passive_circl"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class CIRCL < Base
@@ -42,8 +40,8 @@ module Mihari
42
40
  %w[circl_passive_password circl_passive_username]
43
41
  end
44
42
 
45
- def api
46
- @api ||= ::PassiveCIRCL::API.new(username: username, password: password)
43
+ def client
44
+ @client ||= Clients::CIRCL.new(username: username, password: password)
47
45
  end
48
46
 
49
47
  #
@@ -68,7 +66,7 @@ module Mihari
68
66
  # @return [Array<String>]
69
67
  #
70
68
  def passive_dns_search
71
- results = api.dns.query(@query)
69
+ results = client.dns_query(@query)
72
70
  results.filter_map do |result|
73
71
  type = result["rrtype"]
74
72
  (type == "A") ? result["rdata"] : nil
@@ -81,7 +79,7 @@ module Mihari
81
79
  # @return [Array<String>]
82
80
  #
83
81
  def passive_ssl_search
84
- result = api.ssl.cquery(@query)
82
+ result = client.ssl_cquery(@query)
85
83
  seen = result["seen"] || []
86
84
  seen.uniq
87
85
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "crtsh"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class Crtsh < Base
@@ -21,8 +19,11 @@ module Mihari
21
19
 
22
20
  private
23
21
 
24
- def api
25
- @api ||= ::Crtsh::API.new
22
+ #
23
+ # @return [Mihari::Clients::Crtsh]
24
+ #
25
+ def client
26
+ @client ||= Mihari::Clients::Crtsh.new
26
27
  end
27
28
 
28
29
  #
@@ -32,9 +33,7 @@ module Mihari
32
33
  #
33
34
  def search
34
35
  exclude = exclude_expired ? "expired" : nil
35
- api.search(query, exclude: exclude)
36
- rescue ::Crtsh::Error => _e
37
- []
36
+ client.search(query, exclude: exclude)
38
37
  end
39
38
  end
40
39
  end
@@ -1,22 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dnpedia"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class DNPedia < Base
8
6
  param :query
9
7
 
10
- option :tags, default: proc { [] }
11
-
12
8
  def artifacts
13
9
  search || []
14
10
  end
15
11
 
16
12
  private
17
13
 
18
- def api
19
- @api ||= ::DNPedia::API.new
14
+ def client
15
+ @client ||= Clients::DNPedia.new
20
16
  end
21
17
 
22
18
  #
@@ -25,7 +21,7 @@ module Mihari
25
21
  # @return [Array<Mihari::Artifact>]
26
22
  #
27
23
  def search
28
- res = api.search(query)
24
+ res = client.search(query)
29
25
  rows = res["rows"] || []
30
26
  rows.map do |row|
31
27
  data = [row["name"], row["zoneid"]].join(".")
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "dnstwister"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class DNSTwister < Base
@@ -35,8 +33,8 @@ module Mihari
35
33
  type == "domain"
36
34
  end
37
35
 
38
- def api
39
- @api ||= ::DNSTwister::API.new
36
+ def client
37
+ @client ||= Clients::DNSTwister.new
40
38
  end
41
39
 
42
40
  #
@@ -61,7 +59,7 @@ module Mihari
61
59
  def search
62
60
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
63
61
 
64
- res = api.fuzz(query)
62
+ res = client.fuzz(query)
65
63
  fuzzy_domains = res["fuzzy_domains"] || []
66
64
  domains = fuzzy_domains.map { |domain| domain["domain"] }
67
65
  Parallel.map(domains) do |domain|
@@ -8,26 +8,28 @@ module Mihari
8
8
  class Feed < Base
9
9
  param :query
10
10
 
11
- option :http_request_method, default: proc { "GET" }
12
- option :http_request_headers, default: proc { {} }
13
- option :http_request_payload, default: proc { {} }
14
- option :http_request_payload_type, default: proc {}
11
+ option :method, default: proc { "GET" }
12
+ option :headers, default: proc { {} }
13
+ option :params, default: proc {}
14
+ option :json, default: proc {}
15
+ option :data, default: proc {}
15
16
 
16
17
  option :selector, default: proc { "" }
17
18
 
18
19
  def artifacts
19
- Mihari::Feed::Parser.new(data).parse selector
20
+ Mihari::Feed::Parser.new(results).parse selector
20
21
  end
21
22
 
22
23
  private
23
24
 
24
- def data
25
+ def results
25
26
  reader = Mihari::Feed::Reader.new(
26
27
  query,
27
- http_request_method: http_request_method,
28
- http_request_headers: http_request_headers,
29
- http_request_payload: http_request_payload,
30
- http_request_payload_type: http_request_payload_type
28
+ method: method,
29
+ headers: headers,
30
+ params: params,
31
+ json: json,
32
+ data: data
31
33
  )
32
34
  reader.read
33
35
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "greynoise"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class GreyNoise < Base
@@ -31,8 +29,8 @@ module Mihari
31
29
  %w[greynoise_api_key]
32
30
  end
33
31
 
34
- def api
35
- @api ||= ::GreyNoise::API.new(key: api_key)
32
+ def client
33
+ @client ||= Clients::GreyNoise.new(api_key: api_key)
36
34
  end
37
35
 
38
36
  #
@@ -41,7 +39,7 @@ module Mihari
41
39
  # @return [Hash]
42
40
  #
43
41
  def search
44
- api.experimental.gnql(query, size: PAGE_SIZE)
42
+ client.gnql_search(query, size: PAGE_SIZE)
45
43
  end
46
44
 
47
45
  #
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "onyphe"
4
3
  require "normalize_country"
5
4
 
6
5
  module Mihari
@@ -37,8 +36,8 @@ module Mihari
37
36
  %w[onyphe_api_key]
38
37
  end
39
38
 
40
- def api
41
- @api ||= ::Onyphe::API.new(api_key)
39
+ def client
40
+ @client ||= Clients::Onyphe.new(api_key: api_key)
42
41
  end
43
42
 
44
43
  #
@@ -50,7 +49,7 @@ module Mihari
50
49
  # @return [Structs::Onyphe::Response]
51
50
  #
52
51
  def search_with_page(query, page: 1)
53
- res = api.simple.datascan(query, page: page)
52
+ res = client.datascan(query, page: page)
54
53
  Structs::Onyphe::Response.from_dynamic!(res)
55
54
  end
56
55
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mihari/analyzers/clients/otx"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class OTX < Base
@@ -35,7 +33,7 @@ module Mihari
35
33
  end
36
34
 
37
35
  def client
38
- @client ||= Mihari::Analyzers::Clients::OTX.new(api_key)
36
+ @client ||= Mihari::Clients::OTX.new(api_key: api_key)
39
37
  end
40
38
 
41
39
  #
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "passivetotal"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class PassiveTotal < Base
@@ -42,8 +40,8 @@ module Mihari
42
40
  %w[passivetotal_username passivetotal_api_key]
43
41
  end
44
42
 
45
- def api
46
- @api ||= ::PassiveTotal::API.new(username: username, api_key: api_key)
43
+ def client
44
+ @client ||= Clients::PassiveTotal.new(username: username, api_key: api_key)
47
45
  end
48
46
 
49
47
  #
@@ -79,7 +77,7 @@ module Mihari
79
77
  # @return [Array<String>]
80
78
  #
81
79
  def passive_dns_search
82
- res = api.dns.passive_unique(query)
80
+ res = client.passive_dns_search(query)
83
81
  res["results"] || []
84
82
  end
85
83
 
@@ -89,7 +87,7 @@ module Mihari
89
87
  # @return [Array<Mihari::Artifact>]
90
88
  #
91
89
  def reverse_whois_search
92
- res = api.whois.search(query: query, field: "email")
90
+ res = client.reverse_whois_search(query: query, field: "email")
93
91
  results = res["results"] || []
94
92
  results.map do |result|
95
93
  data = result["domain"]
@@ -103,7 +101,7 @@ module Mihari
103
101
  # @return [Array<Mihari::Artifact>]
104
102
  #
105
103
  def ssl_search
106
- res = api.ssl.history(query)
104
+ res = client.ssl_search(query)
107
105
  results = res["results"] || []
108
106
  results.map do |result|
109
107
  data = result["ipAddresses"]
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pulsedive"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class Pulsedive < Base
@@ -34,8 +32,8 @@ module Mihari
34
32
  %w[pulsedive_api_key]
35
33
  end
36
34
 
37
- def api
38
- @api ||= ::Pulsedive::API.new(api_key)
35
+ def client
36
+ @client ||= Clients::PulseDive.new(api_key: api_key)
39
37
  end
40
38
 
41
39
  #
@@ -55,12 +53,12 @@ module Mihari
55
53
  def search
56
54
  raise InvalidInputError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
57
55
 
58
- indicator = api.indicator.get_by_value(query)
56
+ indicator = client.get_indicator(query)
59
57
  iid = indicator["iid"]
60
58
 
61
- properties = api.indicator.get_properties_by_id(iid)
59
+ properties = client.get_properties(iid)
62
60
  (properties["dns"] || []).filter_map do |property|
63
- if ["A", "PTR"].include?(property["name"])
61
+ if %w[A PTR].include?(property["name"])
64
62
  nil
65
63
  else
66
64
  data = property["value"]
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "shodan"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class Shodan < Base
@@ -37,8 +35,8 @@ module Mihari
37
35
  %w[shodan_api_key]
38
36
  end
39
37
 
40
- def api
41
- @api ||= ::Shodan::API.new(key: api_key)
38
+ def client
39
+ @client ||= Clients::Shodan.new(api_key: api_key)
42
40
  end
43
41
 
44
42
  #
@@ -50,11 +48,7 @@ module Mihari
50
48
  # @return [Hash]
51
49
  #
52
50
  def search_with_page(query, page: 1)
53
- api.host.search(query, page: page)
54
- rescue ::Shodan::Error => e
55
- raise RetryableError, e if e.message.include?("request timed out")
56
-
57
- raise e
51
+ client.search(query, page: page)
58
52
  end
59
53
 
60
54
  #
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "urlscan"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class Urlscan < Base
@@ -20,7 +18,10 @@ module Mihari
20
18
  def initialize(*args, **kwargs)
21
19
  super
22
20
 
23
- raise InvalidInputError, "allowed_data_types should be any of url, domain and ip." unless valid_alllowed_data_types?
21
+ unless valid_alllowed_data_types?
22
+ raise InvalidInputError,
23
+ "allowed_data_types should be any of url, domain and ip."
24
+ end
24
25
 
25
26
  @api_key = kwargs[:api_key] || Mihari.config.urlscan_api_key
26
27
  end
@@ -44,8 +45,8 @@ module Mihari
44
45
  %w[urlscan_api_key]
45
46
  end
46
47
 
47
- def api
48
- @api ||= ::UrlScan::API.new(api_key)
48
+ def client
49
+ @client ||= Clients::UrlScan.new(api_key: api_key)
49
50
  end
50
51
 
51
52
  #
@@ -54,7 +55,7 @@ module Mihari
54
55
  # @return [Structs::Urlscan::Response]
55
56
  #
56
57
  def search_with_search_after(search_after: nil)
57
- res = api.search(query, size: SIZE, search_after: search_after)
58
+ res = client.search(query, size: SIZE, search_after: search_after)
58
59
  Structs::Urlscan::Response.from_dynamic! res
59
60
  end
60
61
 
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "virustotal"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class VirusTotal < Base
@@ -33,8 +31,8 @@ module Mihari
33
31
  %w[virustotal_api_key]
34
32
  end
35
33
 
36
- def api
37
- @api = ::VirusTotal::API.new(key: api_key)
34
+ def client
35
+ @client = Clients::VirusTotal.new(api_key: api_key)
38
36
  end
39
37
 
40
38
  #
@@ -68,7 +66,7 @@ module Mihari
68
66
  # @return [Array<Mihari::Artifact>]
69
67
  #
70
68
  def domain_search
71
- res = api.domain.resolutions(query)
69
+ res = client.domain_search(query)
72
70
 
73
71
  data = res["data"] || []
74
72
  data.filter_map do |item|
@@ -83,7 +81,7 @@ module Mihari
83
81
  # @return [Array<Mihari::Artifact>]
84
82
  #
85
83
  def ip_search
86
- res = api.ip_address.resolutions(query)
84
+ res = client.ip_search(query)
87
85
 
88
86
  data = res["data"] || []
89
87
  data.filter_map do |item|
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "virustotal"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class VirusTotalIntelligence < Base
@@ -40,8 +38,8 @@ module Mihari
40
38
  #
41
39
  # @return [::VirusTotal::API]
42
40
  #
43
- def api
44
- @api = ::VirusTotal::API.new(key: api_key)
41
+ def client
42
+ @client = Clients::VirusTotal.new(api_key: api_key)
45
43
  end
46
44
 
47
45
  #
@@ -54,7 +52,8 @@ module Mihari
54
52
  responses = []
55
53
 
56
54
  loop do
57
- response = Structs::VirusTotalIntelligence::Response.from_dynamic!(api.intelligence.search(query, cursor: cursor))
55
+ response = Structs::VirusTotalIntelligence::Response.from_dynamic!(client.intel_search(query,
56
+ cursor: cursor))
58
57
  responses << response
59
58
 
60
59
  break if response.meta.cursor.nil?
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "zoomeye"
4
-
5
3
  module Mihari
6
4
  module Analyzers
7
5
  class ZoomEye < Base
@@ -48,8 +46,8 @@ module Mihari
48
46
  %w[zoomeye_api_key]
49
47
  end
50
48
 
51
- def api
52
- @api ||= ::ZoomEye::API.new(api_key: api_key)
49
+ def client
50
+ @client ||= Clients::ZoomEye.new(api_key: api_key)
53
51
  end
54
52
 
55
53
  #
@@ -83,9 +81,7 @@ module Mihari
83
81
  # @return [Hash, nil]
84
82
  #
85
83
  def _host_search(query, page: 1)
86
- api.host.search(query, page: page)
87
- rescue ::ZoomEye::Error => _e
88
- nil
84
+ client.host_search(query, page: page)
89
85
  end
90
86
 
91
87
  #
@@ -118,9 +114,7 @@ module Mihari
118
114
  # @return [Hash, nil]
119
115
  #
120
116
  def _web_search(query, page: 1)
121
- api.web.search(query, page: page)
122
- rescue ::ZoomEye::Error => _e
123
- nil
117
+ client.web_search(query, page: page)
124
118
  end
125
119
 
126
120
  #
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mihari/commands/database"
4
+
5
+ module Mihari
6
+ module CLI
7
+ class Database < Base
8
+ include Mihari::Commands::Database
9
+ end
10
+ end
11
+ end
@@ -3,23 +3,29 @@
3
3
  require "thor"
4
4
 
5
5
  # Commands
6
- require "mihari/commands/initializer"
7
6
  require "mihari/commands/searcher"
8
- require "mihari/commands/validator"
9
7
  require "mihari/commands/version"
10
8
  require "mihari/commands/web"
9
+ require "mihari/commands/database"
11
10
 
12
11
  # CLIs
13
12
  require "mihari/cli/base"
14
13
 
14
+ require "mihari/cli/database"
15
+ require "mihari/cli/rule"
16
+
15
17
  module Mihari
16
18
  module CLI
17
19
  class Main < Base
18
20
  include Mihari::Commands::Searcher
19
21
  include Mihari::Commands::Version
20
22
  include Mihari::Commands::Web
21
- include Mihari::Commands::Validator
22
- include Mihari::Commands::Initializer
23
+
24
+ desc "db", "Sub commands for DB"
25
+ subcommand "db", Database
26
+
27
+ desc "rule", "Sub commands for rule"
28
+ subcommand "rule", Rule
23
29
  end
24
30
  end
25
31
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "mihari/commands/rule"
4
+
5
+ module Mihari
6
+ module CLI
7
+ class Rule < Base
8
+ include Mihari::Commands::Rule
9
+ end
10
+ end
11
+ end