mihari 6.3.0 → 7.0.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.
Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -10
  3. data/.rubocop.yml +2 -0
  4. data/Dockerfile +13 -0
  5. data/config.ru +5 -3
  6. data/docker-compose.yml +62 -0
  7. data/exe/mihari +2 -1
  8. data/lefthook.yml +8 -0
  9. data/lib/mihari/actor.rb +4 -4
  10. data/lib/mihari/analyzers/base.rb +16 -0
  11. data/lib/mihari/analyzers/binaryedge.rb +4 -2
  12. data/lib/mihari/analyzers/censys.rb +7 -5
  13. data/lib/mihari/analyzers/circl.rb +5 -3
  14. data/lib/mihari/analyzers/crtsh.rb +4 -1
  15. data/lib/mihari/analyzers/dnstwister.rb +1 -1
  16. data/lib/mihari/analyzers/feed.rb +12 -20
  17. data/lib/mihari/analyzers/fofa.rb +6 -8
  18. data/lib/mihari/analyzers/greynoise.rb +4 -2
  19. data/lib/mihari/analyzers/hunterhow.rb +4 -2
  20. data/lib/mihari/analyzers/onyphe.rb +4 -2
  21. data/lib/mihari/analyzers/otx.rb +5 -3
  22. data/lib/mihari/analyzers/passivetotal.rb +29 -12
  23. data/lib/mihari/analyzers/pulsedive.rb +5 -3
  24. data/lib/mihari/analyzers/securitytrails.rb +32 -8
  25. data/lib/mihari/analyzers/shodan.rb +4 -2
  26. data/lib/mihari/analyzers/urlscan.rb +4 -2
  27. data/lib/mihari/analyzers/virustotal.rb +5 -5
  28. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -2
  29. data/lib/mihari/analyzers/zoomeye.rb +4 -2
  30. data/lib/mihari/cli/{main.rb → application.rb} +17 -5
  31. data/lib/mihari/cli/artifact.rb +14 -0
  32. data/lib/mihari/cli/config.rb +14 -0
  33. data/lib/mihari/cli/rule.rb +1 -0
  34. data/lib/mihari/cli/tag.rb +14 -0
  35. data/lib/mihari/clients/base.rb +2 -2
  36. data/lib/mihari/clients/binaryedge.rb +2 -2
  37. data/lib/mihari/clients/crtsh.rb +2 -9
  38. data/lib/mihari/clients/fofa.rb +1 -1
  39. data/lib/mihari/clients/hunterhow.rb +1 -1
  40. data/lib/mihari/clients/mmdb.rb +28 -0
  41. data/lib/mihari/clients/passivetotal.rb +7 -20
  42. data/lib/mihari/clients/securitytrails.rb +19 -43
  43. data/lib/mihari/clients/shodan_internet_db.rb +28 -0
  44. data/lib/mihari/clients/the_hive.rb +7 -5
  45. data/lib/mihari/commands/alert.rb +53 -11
  46. data/lib/mihari/commands/artifact.rb +66 -0
  47. data/lib/mihari/commands/config.rb +23 -0
  48. data/lib/mihari/commands/database.rb +1 -1
  49. data/lib/mihari/commands/rule.rb +40 -27
  50. data/lib/mihari/commands/search.rb +10 -11
  51. data/lib/mihari/commands/sidekiq.rb +31 -0
  52. data/lib/mihari/commands/tag.rb +46 -0
  53. data/lib/mihari/commands/web.rb +6 -7
  54. data/lib/mihari/{mixins/autonomous_system.rb → concerns/autonomous_system_normalizable.rb} +5 -3
  55. data/lib/mihari/concerns/configurable.rb +72 -0
  56. data/lib/mihari/concerns/database_connectable.rb +16 -0
  57. data/lib/mihari/{mixins/unwrap_error.rb → concerns/error_unwrappable.rb} +5 -3
  58. data/lib/mihari/{mixins/falsepositive.rb → concerns/falsepositive_validatable.rb} +5 -3
  59. data/lib/mihari/{mixins/refang.rb → concerns/refangable.rb} +5 -3
  60. data/lib/mihari/{mixins → concerns}/retriable.rb +4 -2
  61. data/lib/mihari/config.rb +13 -12
  62. data/lib/mihari/database.rb +30 -42
  63. data/lib/mihari/emitters/database.rb +5 -6
  64. data/lib/mihari/emitters/misp.rb +4 -11
  65. data/lib/mihari/emitters/slack.rb +7 -5
  66. data/lib/mihari/emitters/the_hive.rb +8 -58
  67. data/lib/mihari/emitters/webhook.rb +6 -6
  68. data/lib/mihari/enrichers/google_public_dns.rb +1 -1
  69. data/lib/mihari/enrichers/mmdb.rb +28 -0
  70. data/lib/mihari/enrichers/shodan.rb +3 -5
  71. data/lib/mihari/enrichers/whois.rb +3 -3
  72. data/lib/mihari/entities/alert.rb +3 -10
  73. data/lib/mihari/entities/artifact.rb +6 -14
  74. data/lib/mihari/entities/config.rb +2 -2
  75. data/lib/mihari/entities/cpe.rb +1 -0
  76. data/lib/mihari/entities/dns.rb +1 -0
  77. data/lib/mihari/entities/geolocation.rb +1 -0
  78. data/lib/mihari/entities/ip_address.rb +1 -3
  79. data/lib/mihari/entities/messages.rb +17 -0
  80. data/lib/mihari/entities/pagination.rb +11 -0
  81. data/lib/mihari/entities/port.rb +1 -0
  82. data/lib/mihari/entities/reverse_dns.rb +1 -0
  83. data/lib/mihari/entities/rule.rb +2 -20
  84. data/lib/mihari/entities/tag.rb +2 -2
  85. data/lib/mihari/entities/whois.rb +1 -0
  86. data/lib/mihari/errors.rb +2 -4
  87. data/lib/mihari/http.rb +4 -0
  88. data/lib/mihari/models/alert.rb +21 -53
  89. data/lib/mihari/models/artifact.rb +46 -88
  90. data/lib/mihari/models/autonomous_system.rb +5 -13
  91. data/lib/mihari/models/concerns/searchable.rb +50 -0
  92. data/lib/mihari/models/cpe.rb +3 -10
  93. data/lib/mihari/models/dns.rb +2 -6
  94. data/lib/mihari/models/geolocation.rb +7 -12
  95. data/lib/mihari/models/port.rb +3 -10
  96. data/lib/mihari/models/reverse_dns.rb +3 -8
  97. data/lib/mihari/models/rule.rb +16 -57
  98. data/lib/mihari/models/tag.rb +17 -1
  99. data/lib/mihari/models/tagging.rb +1 -1
  100. data/lib/mihari/models/whois.rb +1 -4
  101. data/lib/mihari/rule.rb +35 -24
  102. data/lib/mihari/schemas/alert.rb +1 -0
  103. data/lib/mihari/schemas/analyzer.rb +2 -2
  104. data/lib/mihari/schemas/concerns/orrable.rb +24 -0
  105. data/lib/mihari/schemas/emitter.rb +1 -2
  106. data/lib/mihari/schemas/enricher.rb +3 -4
  107. data/lib/mihari/schemas/macros.rb +1 -1
  108. data/lib/mihari/schemas/options.rb +0 -2
  109. data/lib/mihari/schemas/rule.rb +1 -2
  110. data/lib/mihari/services/{rule_builder.rb → builders.rb} +1 -6
  111. data/lib/mihari/services/creators.rb +22 -0
  112. data/lib/mihari/services/destroyers.rb +41 -0
  113. data/lib/mihari/services/enrichers.rb +25 -0
  114. data/lib/mihari/services/feed.rb +107 -0
  115. data/lib/mihari/services/getters.rb +58 -0
  116. data/lib/mihari/services/initializers.rb +22 -0
  117. data/lib/mihari/services/{alert_builder.rb → proxies.rb} +10 -40
  118. data/lib/mihari/services/searchers.rb +91 -0
  119. data/lib/mihari/sidekiq/application.rb +13 -0
  120. data/lib/mihari/sidekiq/jobs.rb +36 -0
  121. data/lib/mihari/structs/censys.rb +1 -1
  122. data/lib/mihari/structs/config.rb +10 -10
  123. data/lib/mihari/structs/filters.rb +12 -130
  124. data/lib/mihari/structs/google_public_dns.rb +1 -1
  125. data/lib/mihari/structs/greynoise.rb +1 -1
  126. data/lib/mihari/structs/mmdb.rb +115 -0
  127. data/lib/mihari/structs/onyphe.rb +1 -1
  128. data/lib/mihari/structs/shodan.rb +2 -2
  129. data/lib/mihari/version.rb +1 -1
  130. data/lib/mihari/web/{app.rb → application.rb} +28 -15
  131. data/lib/mihari/web/endpoints/alerts.rb +34 -73
  132. data/lib/mihari/web/endpoints/artifacts.rb +27 -111
  133. data/lib/mihari/web/endpoints/configs.rb +3 -5
  134. data/lib/mihari/web/endpoints/ip_addresses.rb +14 -15
  135. data/lib/mihari/web/endpoints/rules.rb +58 -130
  136. data/lib/mihari/web/endpoints/tags.rb +21 -17
  137. data/lib/mihari/web/middleware/capture_exceptions.rb +25 -0
  138. data/lib/mihari/web/middleware/{connection_adapter.rb → connection.rb} +4 -2
  139. data/lib/mihari/web/public/assets/index-cQUcyII5.js +1766 -0
  140. data/lib/mihari/web/public/assets/index-dVaNxqTC.css +1 -0
  141. data/lib/mihari/web/public/index.html +2 -2
  142. data/lib/mihari/web/public/redoc-static.html +385 -385
  143. data/lib/mihari.rb +56 -28
  144. data/mihari.gemspec +12 -4
  145. data/mkdocs.yml +5 -2
  146. data/requirements.txt +1 -1
  147. metadata +164 -34
  148. data/lib/mihari/commands/mixins.rb +0 -11
  149. data/lib/mihari/enrichers/ipinfo.rb +0 -52
  150. data/lib/mihari/entities/message.rb +0 -9
  151. data/lib/mihari/feed/parser.rb +0 -38
  152. data/lib/mihari/feed/reader.rb +0 -111
  153. data/lib/mihari/mixins/configurable.rb +0 -68
  154. data/lib/mihari/schemas/mixins.rb +0 -20
  155. data/lib/mihari/services/alert_runner.rb +0 -20
  156. data/lib/mihari/structs/ipinfo.rb +0 -53
  157. data/lib/mihari/web/endpoints/exports.rb +0 -0
  158. data/lib/mihari/web/middleware/error_notification_adapter.rb +0 -35
  159. data/lib/mihari/web/public/assets/index-81613_nX.js +0 -1763
  160. data/lib/mihari/web/public/assets/index-Wv6xUrTI.css +0 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f027c5c24759f4e09d5dad277df4cad58a1705478eba1f3b9b6b354a896a29a5
4
- data.tar.gz: a908c432c313bab4f4af70b0b32fb1f2e65c9f40926dc3099c4869330080005c
3
+ metadata.gz: c3f4b3b5ca761f5ca5e6f3697593f8253b1e6aa03f21924726ad5dc78ac3f011
4
+ data.tar.gz: f673dd7775f31c2fa134102c8cf9707e0d6fc74467f496c86202de43db7b3c5a
5
5
  SHA512:
6
- metadata.gz: 8110df87f854b6e06ea8477c94c6563b2450dae4585738f256da9c94203d14c6fb3ce11e775a470dae04d4d3934549ae71068e6b3f3d3eca48ea3689d87a4cd4
7
- data.tar.gz: 375855d7dba59d13ff894472f5f6d5ccc82f36de73aeb12c4144c05863c64283f2ff451dd4531643ba3ddbb218181937d57da1a42bb28970f78170e3fae5dfbf
6
+ metadata.gz: 0f139c2a0795bd6e741ce93681f8be47cb75fcb5b707d187d1fd2c758bfe2877388d0d5a25fe5920ec2e7565532c142b585b0029816899664426becea2f0776c
7
+ data.tar.gz: 6dad7972edcba2090bfa12170539efcd51a20dc1ba94757383546ae630002d374e33dcdbc99675cc719801a80b92a11d2eff308a553d627050f8596d6a877c9a
data/.gitignore CHANGED
@@ -52,20 +52,14 @@ Gemfile.lock
52
52
  # rspec
53
53
  .rspec_status
54
54
 
55
- # solargraph
56
- .solargraph.yml
57
-
58
55
  # SQLite
59
56
  *.db
60
57
  *.db-shm
61
58
  *.db-wal
62
59
 
63
- # Config
64
- mihari.yml
65
-
66
- # Rule
67
- rule.yml
68
- !lib/mihari/templates/rule.yml
69
-
70
60
  # Frontend assets
71
61
  lib/mihari/web/public/
62
+
63
+ # Rules & Alerts
64
+ rules/
65
+ alerts/
data/.rubocop.yml CHANGED
@@ -18,5 +18,7 @@ RSpec/MultipleMemoizedHelpers:
18
18
  RSpec/ExampleLength:
19
19
  Max: 20
20
20
  require:
21
+ - rubocop-factory_bot
22
+ - rubocop-rake
21
23
  - rubocop-rspec
22
24
  - rubocop-yard
data/Dockerfile ADDED
@@ -0,0 +1,13 @@
1
+ FROM ruby:3.2.2-alpine3.19
2
+
3
+ ARG MIHARI_VERSION=0.0.0
4
+
5
+ RUN apk --no-cache add git build-base ruby-dev postgresql-dev && \
6
+ gem install pg && \
7
+ gem install mihari -v ${MIHARI_VERSION} && \
8
+ apk del --purge git build-base ruby-dev && \
9
+ rm -rf /usr/local/bundle/cache/*
10
+
11
+ ENTRYPOINT ["mihari"]
12
+
13
+ CMD ["--help"]
data/config.ru CHANGED
@@ -1,8 +1,10 @@
1
- require "./lib/mihari"
1
+ $LOAD_PATH.unshift("#{__dir__}/../lib")
2
+
3
+ require "mihari"
4
+ require "mihari/web/application"
2
5
 
3
6
  require "better_errors"
4
7
 
5
- # set rack env as development
6
- ENV["RACK_ENV"] ||= "development"
8
+ ENV["APP_ENV"] ||= "development"
7
9
 
8
10
  run Mihari::Web::App.instance
@@ -0,0 +1,62 @@
1
+ version: "3"
2
+ services:
3
+ database:
4
+ image: postgres:16
5
+ volumes:
6
+ - postgresql:/var/lib/postgresql/data
7
+ ports:
8
+ - ${POSTGRES_PORT:-5432}:5432
9
+ environment:
10
+ - POSTGRES_USER=${POSTGRES_USER:-user}
11
+ - POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-password}
12
+ - POSTGRES_DB=${POSTGRES_DB:-mihari}
13
+ restart: always
14
+
15
+ redis:
16
+ image: "redis/redis-stack:6.2.6-v10"
17
+ restart: always
18
+ ports:
19
+ - ${REDIS_PORT:-6379}:6379
20
+ - ${REDIS_INSIGHT_PORT:-8001}:8001
21
+ volumes:
22
+ - redis:/data
23
+
24
+ mihari-init:
25
+ image: ghcr.io/ninoseki/mihari:latest
26
+ environment:
27
+ - DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
28
+ entrypoint: ["mihari", "db", "migrate"]
29
+ depends_on:
30
+ - database
31
+
32
+ mihari:
33
+ image: ghcr.io/ninoseki/mihari:latest
34
+ ports:
35
+ - ${MIHARI_PORT:-9292}:9292
36
+ environment:
37
+ - DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
38
+ - REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
39
+ env_file:
40
+ - .env
41
+ entrypoint: ["mihari", "web", "--host", "0.0.0.0"]
42
+ restart: always
43
+ depends_on:
44
+ - mihari-init
45
+
46
+ sidekiq:
47
+ image: ghcr.io/ninoseki/mihari:latest
48
+ environment:
49
+ - DATABASE_URL=${DATABASE_URL:-postgresql://${POSTGRES_USER:-user}:${POSTGRES_PASSWORD:-password}@database:${POSTGRES_PORT:-5432}/${POSTGRES_DB:-mihari}}
50
+ - REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
51
+ - USE_SIDEKIQ=true
52
+ env_file:
53
+ - .env
54
+ entrypoint: ["mihari", "sidekiq"]
55
+ restart: always
56
+ depends_on:
57
+ - mihari-init
58
+ - redis
59
+
60
+ volumes:
61
+ postgresql:
62
+ redis:
data/exe/mihari CHANGED
@@ -4,5 +4,6 @@
4
4
  $LOAD_PATH.unshift("#{__dir__}/../lib")
5
5
 
6
6
  require "mihari"
7
+ require "mihari/cli/application"
7
8
 
8
- Mihari::CLI::Main.start
9
+ Mihari::CLI::App.start
data/lefthook.yml CHANGED
@@ -10,3 +10,11 @@ pre-commit:
10
10
  glob: "*.{js,ts,vue}"
11
11
  run: npx eslint --fix {staged_files}
12
12
  stage_fixed: true
13
+ prettier:
14
+ root: "frontend/"
15
+ glob: "*.{js,ts,vue}"
16
+ run: npx prettier --write {staged_files}
17
+ stage_fixed: true
18
+ actionlint:
19
+ glob: ".github/workflows/*.yaml"
20
+ run: actionlint
data/lib/mihari/actor.rb CHANGED
@@ -7,8 +7,8 @@ module Mihari
7
7
  class Actor
8
8
  include Dry::Monads[:result, :try]
9
9
 
10
- include Mixins::Configurable
11
- include Mixins::Retriable
10
+ include Concerns::Configurable
11
+ include Concerns::Retriable
12
12
 
13
13
  # @return [Hash]
14
14
  attr_reader :options
@@ -53,8 +53,8 @@ module Mihari
53
53
  def validate_configuration!
54
54
  return if configured?
55
55
 
56
- joined = configuration_keys.join(", ")
57
- be = (configuration_keys.length > 1) ? "are" : "is"
56
+ joined = self.class.configuration_keys.join(", ")
57
+ be = (self.class.configuration_keys.length > 1) ? "are" : "is"
58
58
  message = "#{self.class.class_key} is not configured correctly. #{joined} #{be} missing."
59
59
  raise ConfigurationError, message
60
60
  end
@@ -79,6 +79,22 @@ module Mihari
79
79
  normalized_artifacts
80
80
  end
81
81
 
82
+ def result(...)
83
+ res = Try[StandardError] do
84
+ retry_on_error(
85
+ times: retry_times,
86
+ interval: retry_interval,
87
+ exponential_backoff: retry_exponential_backoff
88
+ ) do
89
+ call(...)
90
+ end
91
+ end
92
+
93
+ return res.recover { [] } if ignore_error?
94
+
95
+ res.to_result
96
+ end
97
+
82
98
  class << self
83
99
  #
84
100
  # Initialize an analyzer by query params
@@ -24,8 +24,10 @@ module Mihari
24
24
  client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
25
25
  end
26
26
 
27
- def configuration_keys
28
- %w[binaryedge_api_key]
27
+ class << self
28
+ def configuration_keys
29
+ %w[binaryedge_api_key]
30
+ end
29
31
  end
30
32
 
31
33
  private
@@ -41,11 +41,13 @@ module Mihari
41
41
  configuration_keys? || (id? && secret?)
42
42
  end
43
43
 
44
- #
45
- # @return [Array<String>]
46
- #
47
- def configuration_keys
48
- %w[censys_id censys_secret]
44
+ class << self
45
+ #
46
+ # @return [Array<String>]
47
+ #
48
+ def configuration_keys
49
+ %w[censys_id censys_secret]
50
+ end
49
51
  end
50
52
 
51
53
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # CIRCL passive DNS/SSL analyzer
7
7
  #
8
8
  class CIRCL < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String, nil]
12
12
  attr_reader :type
@@ -47,8 +47,10 @@ module Mihari
47
47
  configuration_keys? || (username? && password?)
48
48
  end
49
49
 
50
- def configuration_keys
51
- %w[circl_passive_password circl_passive_username]
50
+ class << self
51
+ def configuration_keys
52
+ %w[circl_passive_password circl_passive_username]
53
+ end
52
54
  end
53
55
 
54
56
  private
@@ -22,7 +22,10 @@ module Mihari
22
22
 
23
23
  def artifacts
24
24
  exclude = exclude_expired ? "expired" : nil
25
- client.search(query, exclude: exclude)
25
+ client.search(query, exclude: exclude).map do |result|
26
+ values = result["name_value"].to_s.lines.map(&:chomp).reject { |value| value.starts_with?("*.") }
27
+ values.map { |value| Models::Artifact.new(data: value, metadata: result) }
28
+ end.flatten
26
29
  end
27
30
 
28
31
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # DNSTwister analyzer
7
7
  #
8
8
  class DNSTwister < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String]
12
12
  attr_reader :type
@@ -1,8 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "mihari/feed/reader"
4
- require "mihari/feed/parser"
5
-
6
3
  module Mihari
7
4
  module Analyzers
8
5
  #
@@ -10,7 +7,7 @@ module Mihari
10
7
  #
11
8
  class Feed < Base
12
9
  # @return [Hash, nil]
13
- attr_reader :data
10
+ attr_reader :form
14
11
 
15
12
  # @return [Hash, nil]
16
13
  attr_reader :json
@@ -37,37 +34,32 @@ module Mihari
37
34
  # @param [Hash, nil] headers
38
35
  # @param [Hash, nil] params
39
36
  # @param [Hash, nil] json
40
- # @param [Hash, nil] data
37
+ # @param [form, nil] form
41
38
  # @param [String] selector
42
39
  #
43
- def initialize(query, options: nil, method: "GET", headers: nil, params: nil, json: nil, data: nil, selector: "")
44
- super(query, options: options)
40
+ # @param [Object] url
41
+ def initialize(url, options: nil, method: "GET", headers: nil, params: nil, json: nil, form: nil, selector: "")
42
+ super(url, options: options)
45
43
 
46
44
  @method = method
47
45
  @headers = headers || {}
48
46
  @params = params
49
47
  @json = json
50
- @data = data
48
+ @form = form
51
49
  @selector = selector
52
50
  end
53
51
 
54
52
  def artifacts
55
- Mihari::Feed::Parser.new(results).parse selector
53
+ data = Services::FeedReader.call(
54
+ url, headers: headers, method: method, params: params, json: json, form: form, timeout: timeout
55
+ )
56
+ Services::FeedParser.call(data, selector)
56
57
  end
57
58
 
58
59
  private
59
60
 
60
- def results
61
- reader = Mihari::Feed::Reader.new(
62
- query,
63
- method: method,
64
- headers: headers,
65
- timeout: timeout,
66
- params: params,
67
- json: json,
68
- data: data
69
- )
70
- reader.read
61
+ def url
62
+ query
71
63
  end
72
64
  end
73
65
  end
@@ -31,20 +31,18 @@ module Mihari
31
31
  end.flatten.compact
32
32
  end
33
33
 
34
- def configuration_keys
35
- %w[fofa_api_key fofa_email]
36
- end
37
-
38
34
  def configured?
39
35
  api_key? && email?
40
36
  end
41
37
 
42
- private
43
-
44
- def api_key?
45
- !api_key.nil?
38
+ class << self
39
+ def configuration_keys
40
+ %w[fofa_api_key fofa_email]
41
+ end
46
42
  end
47
43
 
44
+ private
45
+
48
46
  def email?
49
47
  !email.nil?
50
48
  end
@@ -27,8 +27,10 @@ module Mihari
27
27
  ).map(&:artifacts).flatten
28
28
  end
29
29
 
30
- def configuration_keys
31
- %w[greynoise_api_key]
30
+ class << self
31
+ def configuration_keys
32
+ %w[greynoise_api_key]
33
+ end
32
34
  end
33
35
 
34
36
  private
@@ -44,8 +44,10 @@ module Mihari
44
44
  end.flatten
45
45
  end
46
46
 
47
- def configuration_keys
48
- %w[hunterhow_api_key]
47
+ class << self
48
+ def configuration_keys
49
+ %w[hunterhow_api_key]
50
+ end
49
51
  end
50
52
 
51
53
  private
@@ -29,8 +29,10 @@ module Mihari
29
29
  ).map(&:artifacts).flatten
30
30
  end
31
31
 
32
- def configuration_keys
33
- %w[onyphe_api_key]
32
+ class << self
33
+ def configuration_keys
34
+ %w[onyphe_api_key]
35
+ end
34
36
  end
35
37
 
36
38
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # OTX analyzer
7
7
  #
8
8
  class OTX < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String, nil]
12
12
  attr_reader :type
@@ -38,8 +38,10 @@ module Mihari
38
38
  end
39
39
  end
40
40
 
41
- def configuration_keys
42
- %w[otx_api_key]
41
+ class << self
42
+ def configuration_keys
43
+ %w[otx_api_key]
44
+ end
43
45
  end
44
46
 
45
47
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # PassiveTotal analyzer
7
7
  #
8
8
  class PassiveTotal < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String, nil]
12
12
  attr_reader :type
@@ -35,11 +35,11 @@ module Mihari
35
35
  def artifacts
36
36
  case type
37
37
  when "domain", "ip"
38
- client.passive_dns_search query
38
+ passive_dns_search
39
39
  when "mail"
40
- client.reverse_whois_search query
40
+ reverse_whois_search
41
41
  when "hash"
42
- client.ssl_search query
42
+ ssl_search
43
43
  else
44
44
  raise ValueError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
45
45
  end
@@ -49,11 +49,11 @@ module Mihari
49
49
  configuration_keys? || (username? && api_key?)
50
50
  end
51
51
 
52
- def configuration_keys
53
- %w[passivetotal_username passivetotal_api_key]
54
- end
55
-
56
52
  class << self
53
+ def configuration_keys
54
+ %w[passivetotal_username passivetotal_api_key]
55
+ end
56
+
57
57
  #
58
58
  # @return [Array<String>, nil]
59
59
  #
@@ -64,6 +64,27 @@ module Mihari
64
64
 
65
65
  private
66
66
 
67
+ def passive_dns_search
68
+ res = client.passive_dns_search(query)
69
+ res["results"] || []
70
+ end
71
+
72
+ def reverse_whois_search
73
+ res = client.reverse_whois_search(query)
74
+ (res["results"] || []).map do |result|
75
+ data = result["domain"]
76
+ Models::Artifact.new(data: data, metadata: result)
77
+ end
78
+ end
79
+
80
+ def ssl_search
81
+ res = client.ssl_search(query)
82
+ (res["results"] || []).map do |result|
83
+ data = result["ipAddresses"]
84
+ data.map { |d| Models::Artifact.new(data: d, metadata: result) }
85
+ end.flatten
86
+ end
87
+
67
88
  def client
68
89
  Clients::PassiveTotal.new(username: username, api_key: api_key, timeout: timeout)
69
90
  end
@@ -80,10 +101,6 @@ module Mihari
80
101
  def username?
81
102
  !username.nil?
82
103
  end
83
-
84
- def api_key?
85
- !api_key.nil?
86
- end
87
104
  end
88
105
  end
89
106
  end
@@ -6,7 +6,7 @@ module Mihari
6
6
  # Pulsedive analyzer
7
7
  #
8
8
  class Pulsedive < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String, nil]
12
12
  attr_reader :type
@@ -43,8 +43,10 @@ module Mihari
43
43
  end
44
44
  end
45
45
 
46
- def configuration_keys
47
- %w[pulsedive_api_key]
46
+ class << self
47
+ def configuration_keys
48
+ %w[pulsedive_api_key]
49
+ end
48
50
  end
49
51
 
50
52
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # SecurityTrails
7
7
  #
8
8
  class SecurityTrails < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String, nil]
12
12
  attr_reader :type
@@ -33,21 +33,21 @@ module Mihari
33
33
  def artifacts
34
34
  case type
35
35
  when "domain"
36
- client.domain_search query
36
+ domain_search
37
37
  when "ip"
38
- client.ip_search query
38
+ ip_search
39
39
  when "mail"
40
- client.mail_search query
40
+ mail_search
41
41
  else
42
42
  raise ValueError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
43
43
  end
44
44
  end
45
45
 
46
- def configuration_keys
47
- %w[securitytrails_api_key]
48
- end
49
-
50
46
  class << self
47
+ def configuration_keys
48
+ %w[securitytrails_api_key]
49
+ end
50
+
51
51
  #
52
52
  # @return [Array<String>, nil]
53
53
  #
@@ -58,6 +58,30 @@ module Mihari
58
58
 
59
59
  private
60
60
 
61
+ def domain_search
62
+ client.get_all_dns_history(query, type: "a").map do |res|
63
+ (res["records"] || []).map do |record|
64
+ (record["values"] || []).map { |value| value["ip"] }
65
+ end.flatten.compact.uniq
66
+ end.flatten
67
+ end
68
+
69
+ def ip_search
70
+ res = client.ip_search(query)
71
+ (res["records"] || []).filter_map do |record|
72
+ data = record["hostname"]
73
+ Models::Artifact.new(data: data, metadata: record)
74
+ end
75
+ end
76
+
77
+ def mail_search
78
+ res = client.mail_search(query)
79
+ (res["records"] || []).filter_map do |record|
80
+ data = record["hostname"]
81
+ Models::Artifact.new(data: data, metadata: record)
82
+ end
83
+ end
84
+
61
85
  def client
62
86
  Clients::SecurityTrails.new(api_key: api_key, timeout: timeout)
63
87
  end
@@ -27,8 +27,10 @@ module Mihari
27
27
  ).map(&:artifacts).flatten.uniq(&:data)
28
28
  end
29
29
 
30
- def configuration_keys
31
- %w[shodan_api_key]
30
+ class << self
31
+ def configuration_keys
32
+ %w[shodan_api_key]
33
+ end
32
34
  end
33
35
 
34
36
  private
@@ -37,8 +37,10 @@ module Mihari
37
37
  artifacts.select { |artifact| allowed_data_types.include? artifact.data_type }
38
38
  end
39
39
 
40
- def configuration_keys
41
- %w[urlscan_api_key]
40
+ class << self
41
+ def configuration_keys
42
+ %w[urlscan_api_key]
43
+ end
42
44
  end
43
45
 
44
46
  private
@@ -6,7 +6,7 @@ module Mihari
6
6
  # VirusTotal analyzer
7
7
  #
8
8
  class VirusTotal < Base
9
- include Mixins::Refang
9
+ include Concerns::Refangable
10
10
 
11
11
  # @return [String]
12
12
  attr_reader :type
@@ -38,11 +38,11 @@ module Mihari
38
38
  end
39
39
  end
40
40
 
41
- def configuration_keys
42
- %w[virustotal_api_key]
43
- end
44
-
45
41
  class << self
42
+ def configuration_keys
43
+ %w[virustotal_api_key]
44
+ end
45
+
46
46
  #
47
47
  # @return [Array<String>, nil]
48
48
  #
@@ -24,8 +24,10 @@ module Mihari
24
24
  client.intel_search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
25
25
  end
26
26
 
27
- def configuration_keys
28
- %w[virustotal_api_key]
27
+ class << self
28
+ def configuration_keys
29
+ %w[virustotal_api_key]
30
+ end
29
31
  end
30
32
 
31
33
  class << self