mihari 6.3.0 → 7.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +4 -10
  3. data/.rubocop.yml +2 -0
  4. data/Dockerfile +14 -0
  5. data/config.ru +5 -3
  6. data/docker-compose.yml +61 -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 +10 -2
  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 +3 -10
  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 +61 -97
  90. data/lib/mihari/models/autonomous_system.rb +0 -24
  91. data/lib/mihari/models/concerns/searchable.rb +50 -0
  92. data/lib/mihari/models/cpe.rb +0 -23
  93. data/lib/mihari/models/dns.rb +0 -20
  94. data/lib/mihari/models/geolocation.rb +0 -24
  95. data/lib/mihari/models/port.rb +3 -10
  96. data/lib/mihari/models/reverse_dns.rb +0 -23
  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 +0 -17
  101. data/lib/mihari/rule.rb +35 -24
  102. data/lib/mihari/schemas/alert.rb +1 -0
  103. data/lib/mihari/schemas/analyzer.rb +3 -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/builders.rb +158 -0
  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/services/rule_builder.rb +0 -46
  157. data/lib/mihari/structs/ipinfo.rb +0 -53
  158. data/lib/mihari/web/endpoints/exports.rb +0 -0
  159. data/lib/mihari/web/middleware/error_notification_adapter.rb +0 -35
  160. data/lib/mihari/web/public/assets/index-81613_nX.js +0 -1763
  161. 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: bc368e612c78350f6b66f4fdcf815a63f4a292e185a2348dce8110b7d17e1692
4
+ data.tar.gz: b3e9939de4ee9488bb6b48793cf5ebe196f50e92eb8f6c1eadb3ed0b201fd2c0
5
5
  SHA512:
6
- metadata.gz: 8110df87f854b6e06ea8477c94c6563b2450dae4585738f256da9c94203d14c6fb3ce11e775a470dae04d4d3934549ae71068e6b3f3d3eca48ea3689d87a4cd4
7
- data.tar.gz: 375855d7dba59d13ff894472f5f6d5ccc82f36de73aeb12c4144c05863c64283f2ff451dd4531643ba3ddbb218181937d57da1a42bb28970f78170e3fae5dfbf
6
+ metadata.gz: 217918561a441c15d4c55e12fa90792230dee66186ad12db8629c30ec848a2a4711eb154d1a008f153abadb3d9cc97ad43ce574d175d167873f3b7c44f0de011
7
+ data.tar.gz: 2d16db3598a3d5918499ce7119f7e69a548f0891dd6f9c5ee5764508244486c6ba255e190f65cca79559db888936b7975db86eadefb7e548b476fb3925316f32
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,14 @@
1
+ FROM ruby:3.2.2-alpine3.19
2
+
3
+ ARG MIHARI_VERSION=0.0.0
4
+
5
+ RUN apk --no-cache add build-base ruby-dev libpq-dev && \
6
+ echo 'gem: --no-document' >> /usr/local/etc/gemrc && \
7
+ gem install pg && \
8
+ gem install mihari -v ${MIHARI_VERSION} && \
9
+ apk del --purge build-base ruby-dev && \
10
+ rm -rf /usr/local/bundle/cache/*
11
+
12
+ ENTRYPOINT ["mihari"]
13
+
14
+ 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,61 @@
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
+ - SIDEKIQ_REDIS_URL=${REDIS_URL:-redis://redis:${REDIS_PORT:-6379}}
51
+ env_file:
52
+ - .env
53
+ entrypoint: ["mihari", "sidekiq"]
54
+ restart: always
55
+ depends_on:
56
+ - mihari-init
57
+ - redis
58
+
59
+ volumes:
60
+ postgresql:
61
+ 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
@@ -9,20 +9,28 @@ module Mihari
9
9
  # @return [Boolean]
10
10
  attr_reader :exclude_expired
11
11
 
12
+ # @return [String, nil]
13
+ attr_reader :match
14
+
12
15
  #
13
16
  # @param [String] query
14
17
  # @param [Hash, nil] options
15
18
  # @param [Bool] exclude_expired
19
+ # @param [String, nil] match
16
20
  #
17
- def initialize(query, options: nil, exclude_expired: true)
21
+ def initialize(query, options: nil, exclude_expired: true, match: nil)
18
22
  super(query, options: options)
19
23
 
20
24
  @exclude_expired = exclude_expired
25
+ @match = match
21
26
  end
22
27
 
23
28
  def artifacts
24
29
  exclude = exclude_expired ? "expired" : nil
25
- client.search(query, exclude: exclude)
30
+ client.search(query, exclude: exclude, match: match).map do |result|
31
+ values = result["name_value"].to_s.lines.map(&:chomp).reject { |value| value.starts_with?("*.") }
32
+ values.map { |value| Models::Artifact.new(data: value, metadata: result) }
33
+ end.flatten
26
34
  end
27
35
 
28
36
  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