mihari 5.7.0 → 5.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (192) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/lib/mihari/actor.rb +10 -4
  4. data/lib/mihari/cli/main.rb +2 -0
  5. data/lib/mihari/clients/base.rb +23 -1
  6. data/lib/mihari/clients/binaryedge.rb +1 -3
  7. data/lib/mihari/clients/censys.rb +1 -2
  8. data/lib/mihari/clients/crtsh.rb +2 -3
  9. data/lib/mihari/clients/dnstwister.rb +1 -2
  10. data/lib/mihari/clients/fofa.rb +1 -3
  11. data/lib/mihari/clients/greynoise.rb +1 -2
  12. data/lib/mihari/clients/hunterhow.rb +1 -2
  13. data/lib/mihari/clients/misp.rb +1 -2
  14. data/lib/mihari/clients/onyphe.rb +1 -2
  15. data/lib/mihari/clients/otx.rb +2 -14
  16. data/lib/mihari/clients/passivetotal.rb +3 -16
  17. data/lib/mihari/clients/publsedive.rb +2 -17
  18. data/lib/mihari/clients/securitytrails.rb +3 -25
  19. data/lib/mihari/clients/shodan.rb +1 -2
  20. data/lib/mihari/clients/the_hive.rb +1 -2
  21. data/lib/mihari/clients/urlscan.rb +1 -2
  22. data/lib/mihari/clients/virustotal.rb +3 -17
  23. data/lib/mihari/clients/zoomeye.rb +9 -19
  24. data/lib/mihari/commands/alert.rb +11 -9
  25. data/lib/mihari/commands/database.rb +4 -1
  26. data/lib/mihari/commands/mixins.rb +11 -0
  27. data/lib/mihari/commands/search.rb +13 -32
  28. data/lib/mihari/constants.rb +1 -1
  29. data/lib/mihari/database.rb +1 -1
  30. data/lib/mihari/enrichers/ipinfo.rb +1 -1
  31. data/lib/mihari/entities/tag.rb +1 -0
  32. data/lib/mihari/http.rb +13 -11
  33. data/lib/mihari/rule.rb +14 -0
  34. data/lib/mihari/service.rb +12 -2
  35. data/lib/mihari/services/alert_builder.rb +81 -8
  36. data/lib/mihari/services/alert_runner.rb +3 -10
  37. data/lib/mihari/services/rule_builder.rb +8 -10
  38. data/lib/mihari/services/rule_runner.rb +2 -25
  39. data/lib/mihari/structs/binaryedge.rb +9 -0
  40. data/lib/mihari/structs/censys.rb +0 -14
  41. data/lib/mihari/structs/fofa.rb +3 -0
  42. data/lib/mihari/structs/google_public_dns.rb +0 -4
  43. data/lib/mihari/structs/greynoise.rb +0 -6
  44. data/lib/mihari/structs/hunterhow.rb +0 -6
  45. data/lib/mihari/structs/ipinfo.rb +0 -2
  46. data/lib/mihari/structs/onyphe.rb +0 -4
  47. data/lib/mihari/structs/shodan.rb +0 -2
  48. data/lib/mihari/structs/urlscan.rb +0 -6
  49. data/lib/mihari/structs/virustotal_intelligence.rb +0 -8
  50. data/lib/mihari/version.rb +1 -1
  51. data/lib/mihari/web/app.rb +20 -17
  52. data/lib/mihari/web/endpoints/alerts.rb +75 -38
  53. data/lib/mihari/web/endpoints/artifacts.rb +60 -53
  54. data/lib/mihari/web/endpoints/ip_addresses.rb +19 -4
  55. data/lib/mihari/web/endpoints/rules.rb +132 -88
  56. data/lib/mihari/web/endpoints/tags.rb +15 -13
  57. data/lib/mihari/web/middleware/error_notification_adapter.rb +8 -3
  58. data/lib/mihari/web/public/assets/{index-821134e2.js → index-ec641cb0.js} +45 -44
  59. data/lib/mihari/web/public/index.html +1 -1
  60. data/lib/mihari/web/public/redoc-static.html +400 -400
  61. data/lib/mihari.rb +0 -2
  62. data/mihari.gemspec +5 -5
  63. data/mkdocs.yml +14 -7
  64. metadata +13 -140
  65. data/docs/alternatives.md +0 -5
  66. data/docs/analyzers/binaryedge.md +0 -26
  67. data/docs/analyzers/censys.md +0 -31
  68. data/docs/analyzers/circl.md +0 -37
  69. data/docs/analyzers/crtsh.md +0 -26
  70. data/docs/analyzers/dnstwister.md +0 -25
  71. data/docs/analyzers/feed.md +0 -73
  72. data/docs/analyzers/fofa.md +0 -31
  73. data/docs/analyzers/greynoise.md +0 -26
  74. data/docs/analyzers/hunterhow.md +0 -33
  75. data/docs/analyzers/index.md +0 -104
  76. data/docs/analyzers/onyphe.md +0 -26
  77. data/docs/analyzers/otx.md +0 -28
  78. data/docs/analyzers/passivetotal.md +0 -52
  79. data/docs/analyzers/pulsedive.md +0 -28
  80. data/docs/analyzers/securitytrails.md +0 -41
  81. data/docs/analyzers/shodan.md +0 -26
  82. data/docs/analyzers/urlscan.md +0 -28
  83. data/docs/analyzers/virustotal.md +0 -43
  84. data/docs/analyzers/virustotal_intelligence.md +0 -33
  85. data/docs/analyzers/zoomeye.md +0 -38
  86. data/docs/configuration.md +0 -35
  87. data/docs/emitters/database.md +0 -22
  88. data/docs/emitters/hive.md +0 -26
  89. data/docs/emitters/index.md +0 -36
  90. data/docs/emitters/misp.md +0 -21
  91. data/docs/emitters/slack.md +0 -21
  92. data/docs/emitters/webhook.md +0 -63
  93. data/docs/enrichers/google_public_dns.md +0 -19
  94. data/docs/enrichers/index.md +0 -35
  95. data/docs/enrichers/ipinfo.md +0 -26
  96. data/docs/enrichers/shodan.md +0 -22
  97. data/docs/enrichers/whois.md +0 -17
  98. data/docs/github_actions.md +0 -43
  99. data/docs/index.md +0 -11
  100. data/docs/installation.md +0 -31
  101. data/docs/requirements.md +0 -13
  102. data/docs/rule.md +0 -168
  103. data/docs/tags.md +0 -3
  104. data/docs/usage.md +0 -103
  105. data/frontend/.eslintrc.cjs +0 -22
  106. data/frontend/.gitignore +0 -31
  107. data/frontend/.prettierrc.json +0 -8
  108. data/frontend/README.md +0 -3
  109. data/frontend/env.d.ts +0 -5
  110. data/frontend/index.html +0 -21
  111. data/frontend/package-lock.json +0 -7219
  112. data/frontend/package.json +0 -67
  113. data/frontend/public/favicon.ico +0 -0
  114. data/frontend/scripts/swagger_doc_to_yaml.rb +0 -23
  115. data/frontend/src/App.vue +0 -27
  116. data/frontend/src/ace-config.ts +0 -6
  117. data/frontend/src/api-helper.ts +0 -111
  118. data/frontend/src/api.ts +0 -105
  119. data/frontend/src/components/ErrorMessage.vue +0 -31
  120. data/frontend/src/components/Loading.vue +0 -15
  121. data/frontend/src/components/Navbar.vue +0 -42
  122. data/frontend/src/components/Pagination.vue +0 -119
  123. data/frontend/src/components/alert/Alert.vue +0 -87
  124. data/frontend/src/components/alert/Alerts.vue +0 -63
  125. data/frontend/src/components/alert/AlertsWithPagination.vue +0 -90
  126. data/frontend/src/components/alert/AlertsWrapper.vue +0 -128
  127. data/frontend/src/components/alert/Form.vue +0 -169
  128. data/frontend/src/components/artifact/AS.vue +0 -23
  129. data/frontend/src/components/artifact/Artifact.vue +0 -287
  130. data/frontend/src/components/artifact/ArtifactTag.vue +0 -64
  131. data/frontend/src/components/artifact/ArtifactTags.vue +0 -29
  132. data/frontend/src/components/artifact/ArtifactWrapper.vue +0 -57
  133. data/frontend/src/components/artifact/CPEs.vue +0 -23
  134. data/frontend/src/components/artifact/DnsRecords.vue +0 -32
  135. data/frontend/src/components/artifact/Ports.vue +0 -23
  136. data/frontend/src/components/artifact/ReverseDnsNames.vue +0 -23
  137. data/frontend/src/components/artifact/Tags.vue +0 -29
  138. data/frontend/src/components/artifact/WhoisRecord.vue +0 -44
  139. data/frontend/src/components/config/Configs.vue +0 -65
  140. data/frontend/src/components/config/ConfigsWrapper.vue +0 -32
  141. data/frontend/src/components/link/Link.vue +0 -32
  142. data/frontend/src/components/link/Links.vue +0 -42
  143. data/frontend/src/components/rule/EditRule.vue +0 -72
  144. data/frontend/src/components/rule/EditRuleWrapper.vue +0 -48
  145. data/frontend/src/components/rule/Form.vue +0 -158
  146. data/frontend/src/components/rule/InputForm.vue +0 -45
  147. data/frontend/src/components/rule/NewRule.vue +0 -57
  148. data/frontend/src/components/rule/Rule.vue +0 -100
  149. data/frontend/src/components/rule/RuleWrapper.vue +0 -53
  150. data/frontend/src/components/rule/Rules.vue +0 -84
  151. data/frontend/src/components/rule/RulesWrapper.vue +0 -121
  152. data/frontend/src/components/rule/YAML.vue +0 -37
  153. data/frontend/src/components/tag/Tag.vue +0 -65
  154. data/frontend/src/components/tag/Tags.vue +0 -37
  155. data/frontend/src/countries.ts +0 -350
  156. data/frontend/src/index.ts +0 -20
  157. data/frontend/src/links/anyrun.ts +0 -19
  158. data/frontend/src/links/base.ts +0 -14
  159. data/frontend/src/links/censys.ts +0 -20
  160. data/frontend/src/links/crtsh.ts +0 -20
  161. data/frontend/src/links/dnslytics.ts +0 -38
  162. data/frontend/src/links/greynoise.ts +0 -20
  163. data/frontend/src/links/index.ts +0 -40
  164. data/frontend/src/links/intezer.ts +0 -20
  165. data/frontend/src/links/otx.ts +0 -33
  166. data/frontend/src/links/securitytrails.ts +0 -38
  167. data/frontend/src/links/shodan.ts +0 -20
  168. data/frontend/src/links/urlscan.ts +0 -50
  169. data/frontend/src/links/virustotal.ts +0 -72
  170. data/frontend/src/main.ts +0 -41
  171. data/frontend/src/router/index.ts +0 -57
  172. data/frontend/src/rule.ts +0 -14
  173. data/frontend/src/shims-vue.d.ts +0 -6
  174. data/frontend/src/swagger.yaml +0 -771
  175. data/frontend/src/types.ts +0 -188
  176. data/frontend/src/utils.ts +0 -54
  177. data/frontend/src/views/Alerts.vue +0 -20
  178. data/frontend/src/views/Artifact.vue +0 -39
  179. data/frontend/src/views/Configs.vue +0 -20
  180. data/frontend/src/views/EditRule.vue +0 -39
  181. data/frontend/src/views/NewRule.vue +0 -26
  182. data/frontend/src/views/Rule.vue +0 -39
  183. data/frontend/src/views/Rules.vue +0 -20
  184. data/frontend/tests/utils.spec.ts +0 -9
  185. data/frontend/tsconfig.app.json +0 -21
  186. data/frontend/tsconfig.json +0 -14
  187. data/frontend/tsconfig.node.json +0 -13
  188. data/frontend/tsconfig.vitest.json +0 -12
  189. data/frontend/vite.config.ts +0 -24
  190. data/frontend/vitest.config.ts +0 -21
  191. data/lib/mihari/mixins/error_notification.rb +0 -21
  192. data/lib/mihari/services/alert_proxy.rb +0 -97
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f226f30917400448aecfc83808609ff3eb180228c2d10d797d3409cc3ecdb9c0
4
- data.tar.gz: 5ce20637fed160cdecb7d8c22726b44670834843f2e77f5ef235f943a6321701
3
+ metadata.gz: 5c7fa4de39ec815c08930311d4ed642857236021301508c47d298cba157dd811
4
+ data.tar.gz: 1598a9992be6739957bc5145c11d93f8a869588d42985799d527703178f78a8f
5
5
  SHA512:
6
- metadata.gz: 3900c2cc6a8ac2010b4579f574be0ce4d620a180dcfadf00c97b7597a7bccd79de9efdfdce402b40f06d7afeaaec0062210796391123e3a145f54d3be4270261
7
- data.tar.gz: 7655638dd621bf03f0d9178eb2e0ca6bf4d161b6563c266380d3cc8bf37bef692bc06765ef3050aaf7683a0f1be2ca51d8a9d7e7c3f34a9e184389fcd31b2885
6
+ metadata.gz: 6c96715d51778d724b4df1c502d3083c4af084997019cc7ef43fc5d131cfeb02c4b0f06d6353c0d8e75e26dec0fb20038fa36718f9a65bb1a3a771224442bc3e
7
+ data.tar.gz: 655c0efa77ff2602fef509b351ebf02ab9c222728ddfcfc0da36ba8fa27a4e1518f1d70406b5ba3ace86012c196954a98c9af10a4de58c5dcdf73bbc760d2056
data/.rubocop.yml CHANGED
@@ -3,7 +3,7 @@ Style/HashSyntax:
3
3
  Style/StringLiterals:
4
4
  EnforcedStyle: double_quotes
5
5
  Metrics/BlockLength:
6
- Max: 100
6
+ Max: 150
7
7
  Exclude:
8
8
  - "spec/**/*"
9
9
  - "*.gemspec"
data/lib/mihari/actor.rb CHANGED
@@ -2,9 +2,11 @@
2
2
 
3
3
  module Mihari
4
4
  #
5
- # Base class for Analyzer, Emitter and Enricher
5
+ # Yet another base service class for Analyzer, Emitter and Enricher
6
6
  #
7
- class Actor < Service
7
+ class Actor
8
+ include Dry::Monads[:result, :try]
9
+
8
10
  include Mixins::Configurable
9
11
  include Mixins::Retriable
10
12
 
@@ -57,13 +59,17 @@ module Mihari
57
59
  raise ConfigurationError, message
58
60
  end
59
61
 
60
- def result
62
+ def call(*args, **kwargs)
63
+ raise NotImplementedError, "You must implement #{self.class}##{__method__}"
64
+ end
65
+
66
+ def result(...)
61
67
  Try[StandardError] do
62
68
  retry_on_error(
63
69
  times: retry_times,
64
70
  interval: retry_interval,
65
71
  exponential_backoff: retry_exponential_backoff
66
- ) { call }
72
+ ) { call(...) }
67
73
  end.to_result
68
74
  end
69
75
 
@@ -4,6 +4,8 @@ require "thor"
4
4
  require "thor/hollaback"
5
5
 
6
6
  # Commands
7
+ require "mihari/commands/mixins"
8
+
7
9
  require "mihari/commands/alert"
8
10
  require "mihari/commands/database"
9
11
  require "mihari/commands/search"
@@ -41,7 +41,7 @@ module Mihari
41
41
  # @return [::HTTP::Client]
42
42
  #
43
43
  def http
44
- HTTP::Factory.build headers: headers, timeout: timeout
44
+ @http ||= HTTP::Factory.build(headers: headers, timeout: timeout)
45
45
  end
46
46
 
47
47
  #
@@ -63,6 +63,17 @@ module Mihari
63
63
  http.get(url_for(path), params: params)
64
64
  end
65
65
 
66
+ #
67
+ # @param [String] path
68
+ # @param [Hash, nil] params
69
+ #
70
+ # @return [Hash]
71
+ #
72
+ def get_json(path, params: nil)
73
+ res = get(path, params: params)
74
+ JSON.parse res.body.to_s
75
+ end
76
+
66
77
  #
67
78
  # @param [String] path
68
79
  # @param [Hash, nil] json
@@ -72,6 +83,17 @@ module Mihari
72
83
  def post(path, json: {})
73
84
  http.post(url_for(path), json: json)
74
85
  end
86
+
87
+ #
88
+ # @param [String] path
89
+ # @param [Hash, nil] json
90
+ #
91
+ # @return [Hash]
92
+ #
93
+ def post_json(path, json: {})
94
+ res = http.post(url_for(path), json: json)
95
+ JSON.parse res.body.to_s
96
+ end
75
97
  end
76
98
  end
77
99
  end
@@ -38,9 +38,7 @@ module Mihari
38
38
  page: page,
39
39
  only_ips: only_ips
40
40
  }.compact
41
-
42
- res = get("/query/search", params: params)
43
- Structs::BinaryEdge::Response.from_dynamic! JSON.parse(res.body.to_s)
41
+ Structs::BinaryEdge::Response.from_dynamic! get_json("/query/search", params: params)
44
42
  end
45
43
 
46
44
  #
@@ -46,8 +46,7 @@ module Mihari
46
46
  #
47
47
  def search(query, per_page: nil, cursor: nil)
48
48
  params = { q: query, per_page: per_page, cursor: cursor }.compact
49
- res = get("/api/v2/hosts/search", params: params)
50
- Structs::Censys::Response.from_dynamic! JSON.parse(res.body.to_s)
49
+ Structs::Censys::Response.from_dynamic! get_json("/api/v2/hosts/search", params: params)
51
50
  end
52
51
 
53
52
  #
@@ -27,9 +27,8 @@ module Mihari
27
27
  def search(identity, match: nil, exclude: nil)
28
28
  params = { identity: identity, match: match, exclude: exclude, output: "json" }.compact
29
29
 
30
- res = get("/", params: params)
31
- parsed = JSON.parse(res.body.to_s)
32
-
30
+ # @type [Array[Hash]]
31
+ parsed = get_json("/", params: params)
33
32
  parsed.map do |result|
34
33
  values = result["name_value"].to_s.lines.map(&:chomp)
35
34
  values.map { |value| Models::Artifact.new(data: value, metadata: result) }
@@ -23,8 +23,7 @@ module Mihari
23
23
  # @return [Array<String>]
24
24
  #
25
25
  def fuzz(domain)
26
- res = get("/api/fuzz/#{to_hex(domain)}")
27
- res = JSON.parse(res.body.to_s)
26
+ res = get_json("/api/fuzz/#{to_hex(domain)}")
28
27
  fuzzy_domains = res["fuzzy_domains"] || []
29
28
  fuzzy_domains.map { |d| d["domain"] }
30
29
  end
@@ -52,8 +52,7 @@ module Mihari
52
52
  def search(query, page:, size: PAGE_SIZE)
53
53
  qbase64 = Base64.urlsafe_encode64(query)
54
54
  params = { qbase64: qbase64, size: size, page: page, email: email, key: api_key }.compact
55
- res = get("/api/v1/search/all", params: params)
56
- Structs::Fofa::Response.from_dynamic! JSON.parse(res.body.to_s)
55
+ Structs::Fofa::Response.from_dynamic! get_json("/api/v1/search/all", params: params)
57
56
  end
58
57
 
59
58
  #
@@ -71,7 +70,6 @@ module Mihari
71
70
  y.yield res
72
71
 
73
72
  break if res.error
74
-
75
73
  break if (res.results || []).length < size
76
74
 
77
75
  sleep_pagination_interval
@@ -39,8 +39,7 @@ module Mihari
39
39
  #
40
40
  def gnql_search(query, size: PAGE_SIZE, scroll: nil)
41
41
  params = { query: query, size: size, scroll: scroll }.compact
42
- res = get("/v2/experimental/gnql", params: params)
43
- Structs::GreyNoise::Response.from_dynamic! JSON.parse(res.body.to_s)
42
+ Structs::GreyNoise::Response.from_dynamic! get_json("/v2/experimental/gnql", params: params)
44
43
  end
45
44
 
46
45
  #
@@ -52,8 +52,7 @@ module Mihari
52
52
  end_time: end_time,
53
53
  "api-key": api_key
54
54
  }.compact
55
- res = get("/search", params: params)
56
- Structs::HunterHow::Response.from_dynamic! JSON.parse(res.body.to_s)
55
+ Structs::HunterHow::Response.from_dynamic! get_json("/search", params: params)
57
56
  end
58
57
 
59
58
  #
@@ -27,8 +27,7 @@ module Mihari
27
27
  # @return [Hash]
28
28
  #
29
29
  def create_event(payload)
30
- res = post("/events/add", json: payload)
31
- JSON.parse(res.body.to_s)
30
+ post_json("/events/add", json: payload)
32
31
  end
33
32
  end
34
33
  end
@@ -40,8 +40,7 @@ module Mihari
40
40
  #
41
41
  def datascan(query, page: 1)
42
42
  params = { page: page, apikey: api_key }
43
- res = get("/api/v2/simple/datascan/#{query}", params: params)
44
- Structs::Onyphe::Response.from_dynamic! JSON.parse(res.body.to_s)
43
+ Structs::Onyphe::Response.from_dynamic! get_json("/api/v2/simple/datascan/#{query}", params: params)
45
44
  end
46
45
 
47
46
  #
@@ -65,7 +65,7 @@ module Mihari
65
65
  # @return [Hash]
66
66
  #
67
67
  def query_by_ip(ip)
68
- _get "/api/v1/indicators/IPv4/#{ip}/passive_dns"
68
+ get_json "/api/v1/indicators/IPv4/#{ip}/passive_dns"
69
69
  end
70
70
 
71
71
  #
@@ -74,19 +74,7 @@ module Mihari
74
74
  # @return [Hash]
75
75
  #
76
76
  def query_by_domain(domain)
77
- _get "/api/v1/indicators/domain/#{domain}/passive_dns"
78
- end
79
-
80
- private
81
-
82
- #
83
- # @param [String] path
84
- #
85
- # @return [Hash]
86
- #
87
- def _get(path)
88
- res = get(path)
89
- JSON.parse(res.body.to_s)
77
+ get_json "/api/v1/indicators/domain/#{domain}/passive_dns"
90
78
  end
91
79
  end
92
80
  end
@@ -33,7 +33,7 @@ module Mihari
33
33
  #
34
34
  def passive_dns_search(query)
35
35
  params = { query: query }
36
- res = _get("/v2/dns/passive/unique", params: params)
36
+ res = get_json("/v2/dns/passive/unique", params: params)
37
37
  res["results"] || []
38
38
  end
39
39
 
@@ -49,7 +49,7 @@ module Mihari
49
49
  query: query,
50
50
  field: "email"
51
51
  }.compact
52
- res = _get("/v2/whois/search", params: params)
52
+ res = get_json("/v2/whois/search", params: params)
53
53
  results = res["results"] || []
54
54
  results.map do |result|
55
55
  data = result["domain"]
@@ -66,26 +66,13 @@ module Mihari
66
66
  #
67
67
  def ssl_search(query)
68
68
  params = { query: query }
69
- res = _get("/v2/ssl-certificate/history", params: params)
69
+ res = get_json("/v2/ssl-certificate/history", params: params)
70
70
  results = res["results"] || []
71
71
  results.map do |result|
72
72
  data = result["ipAddresses"]
73
73
  data.map { |d| Models::Artifact.new(data: d, metadata: result) }
74
74
  end.flatten
75
75
  end
76
-
77
- private
78
-
79
- #
80
- # @param [String] path
81
- # @param [Hash] params
82
- #
83
- # @return [Hash]
84
- #
85
- def _get(path, params: {})
86
- res = get(path, params: params)
87
- JSON.parse(res.body.to_s)
88
- end
89
76
  end
90
77
  end
91
78
  end
@@ -29,7 +29,7 @@ module Mihari
29
29
  # @return [Hash]
30
30
  #
31
31
  def get_indicator(ip_or_domain)
32
- _get "/api/info.php", params: { indicator: ip_or_domain }
32
+ get_json "/api/info.php", params: { indicator: ip_or_domain, key: api_key }
33
33
  end
34
34
 
35
35
  #
@@ -38,22 +38,7 @@ module Mihari
38
38
  # @return [Hash]
39
39
  #
40
40
  def get_properties(indicator_id)
41
- _get "/api/info.php", params: { iid: indicator_id, get: "properties" }
42
- end
43
-
44
- private
45
-
46
- #
47
- # @param [String] path
48
- # @param [Hash] params
49
- #
50
- # @return [Hash]
51
- #
52
- def _get(path, params: {})
53
- params["key"] = api_key
54
-
55
- res = get(path, params: params)
56
- JSON.parse res.body.to_s
41
+ get_json "/api/info.php", params: { iid: indicator_id, get: "properties", key: api_key }
57
42
  end
58
43
  end
59
44
  end
@@ -70,7 +70,7 @@ module Mihari
70
70
  # @return [Array<Hash>]
71
71
  #
72
72
  def search_by_mail(mail)
73
- res = _post "/v1/domains/list", json: { filter: { whois_email: mail } }
73
+ res = post_json "/v1/domains/list", json: { filter: { whois_email: mail } }
74
74
  res["records"] || []
75
75
  end
76
76
 
@@ -80,7 +80,7 @@ module Mihari
80
80
  # @return [Array<Hash>]
81
81
  #
82
82
  def search_by_ip(ip)
83
- res = _post "/v1/domains/list", json: { filter: { ipv4: ip } }
83
+ res = post_json "/v1/domains/list", json: { filter: { ipv4: ip } }
84
84
  res["records"] || []
85
85
  end
86
86
 
@@ -114,29 +114,7 @@ module Mihari
114
114
  # @return [Array<Hash>]
115
115
  #
116
116
  def get_dns_history(domain, type:, page:)
117
- _get "/v1/history/#{domain}/dns/#{type}", params: { page: page }
118
- end
119
-
120
- #
121
- # @param [String] path
122
- # @param [Hash, nil] params
123
- #
124
- # @return [Hash]
125
- #
126
- def _get(path, params:)
127
- res = get(path, params: params)
128
- JSON.parse(res.body.to_s)
129
- end
130
-
131
- #
132
- # @param [String] path
133
- # @param [Hash, nil] json
134
- #
135
- # @return [Hash]
136
- #
137
- def _post(path, json:)
138
- res = post(path, json: json)
139
- JSON.parse(res.body.to_s)
117
+ get_json "/v1/history/#{domain}/dns/#{type}", params: { page: page }
140
118
  end
141
119
  end
142
120
  end
@@ -46,8 +46,7 @@ module Mihari
46
46
  minify: minify,
47
47
  key: api_key
48
48
  }
49
- res = get("/shodan/host/search", params: params)
50
- Structs::Shodan::Response.from_dynamic! JSON.parse(res.body.to_s)
49
+ Structs::Shodan::Response.from_dynamic! get_json("/shodan/host/search", params: params)
51
50
  end
52
51
 
53
52
  #
@@ -29,8 +29,7 @@ module Mihari
29
29
  #
30
30
  def alert(json)
31
31
  json = json.to_camelback_keys.compact
32
- res = post("/alert", json: json)
33
- JSON.parse(res.body.to_s)
32
+ post_json("/alert", json: json)
34
33
  end
35
34
  end
36
35
  end
@@ -36,8 +36,7 @@ module Mihari
36
36
  #
37
37
  def search(q, size: nil, search_after: nil)
38
38
  params = { q: q, size: size, search_after: search_after }.compact
39
- res = get("/api/v1/search/", params: params)
40
- Structs::Urlscan::Response.from_dynamic! JSON.parse(res.body.to_s)
39
+ Structs::Urlscan::Response.from_dynamic! get_json("/api/v1/search/", params: params)
41
40
  end
42
41
 
43
42
  #
@@ -33,7 +33,7 @@ module Mihari
33
33
  # @return [Hash]
34
34
  #
35
35
  def domain_search(query)
36
- _get("/api/v3/domains/#{query}/resolutions")
36
+ get_json "/api/v3/domains/#{query}/resolutions"
37
37
  end
38
38
 
39
39
  #
@@ -42,7 +42,7 @@ module Mihari
42
42
  # @return [Hash]
43
43
  #
44
44
  def ip_search(query)
45
- _get("/api/v3/ip_addresses/#{query}/resolutions")
45
+ get_json "/api/v3/ip_addresses/#{query}/resolutions"
46
46
  end
47
47
 
48
48
  #
@@ -53,8 +53,7 @@ module Mihari
53
53
  #
54
54
  def intel_search(query, cursor: nil)
55
55
  params = { query: query, cursor: cursor }.compact
56
- res = _get("/api/v3/intelligence/search", params: params)
57
- Structs::VirusTotalIntelligence::Response.from_dynamic! res
56
+ Structs::VirusTotalIntelligence::Response.from_dynamic! get_json("/api/v3/intelligence/search", params: params)
58
57
  end
59
58
 
60
59
  #
@@ -79,19 +78,6 @@ module Mihari
79
78
  end
80
79
  end
81
80
  end
82
-
83
- private
84
-
85
- #
86
- # @param [String] path
87
- # @param [Hash] params
88
- #
89
- # @return [Hash]
90
- #
91
- def _get(path, params: {})
92
- res = get(path, params: params)
93
- JSON.parse(res.body.to_s)
94
- end
95
81
  end
96
82
  end
97
83
  end
@@ -30,6 +30,13 @@ module Mihari
30
30
  super(base_url, headers: headers, pagination_interval: pagination_interval, timeout: timeout)
31
31
  end
32
32
 
33
+ #
34
+ # @return [::HTTP::Client]
35
+ #
36
+ def http
37
+ @http ||= HTTP::Factory.build(headers: headers, timeout: timeout, raise_exception: false)
38
+ end
39
+
33
40
  #
34
41
  # Search the Host devices
35
42
  #
@@ -45,8 +52,7 @@ module Mihari
45
52
  page: page,
46
53
  facets: facets
47
54
  }.compact
48
-
49
- _get("/host/search", params: params)
55
+ get_json "/host/search", params: params
50
56
  end
51
57
 
52
58
  #
@@ -88,8 +94,7 @@ module Mihari
88
94
  page: page,
89
95
  facets: facets
90
96
  }.compact
91
-
92
- _get("/web/search", params: params)
97
+ get_json "/web/search", params: params
93
98
  end
94
99
 
95
100
  #
@@ -115,21 +120,6 @@ module Mihari
115
120
  end
116
121
  end
117
122
  end
118
-
119
- private
120
-
121
- #
122
- # @param [String] path
123
- # @param [Hash] params
124
- #
125
- # @return [Hash, nil]
126
- #
127
- def _get(path, params: {})
128
- res = get(path, params: params)
129
- JSON.parse(res.body.to_s)
130
- rescue HTTPError
131
- nil
132
- end
133
123
  end
134
124
  end
135
125
  end
@@ -10,22 +10,24 @@ module Mihari
10
10
  def included(thor)
11
11
  thor.class_eval do
12
12
  include Dry::Monads[:result, :try]
13
+ include Mixins
13
14
 
14
15
  desc "add [PATH]", "Add an alert"
16
+ around :with_db_connection
15
17
  #
16
18
  # @param [String] path
17
19
  #
18
20
  def add(path)
19
- Mihari::Database.with_db_connection do
20
- builder = Services::AlertBuilder.new(path)
21
+ result = Dry::Monads::Try[StandardError] do
22
+ # @type [Mihari::Services::AlertProxy]
23
+ proxy = Mihari::Services::AlertBuilder.call(path)
24
+ Mihari::Services::AlertRunner.call proxy
25
+ end.to_result
21
26
 
22
- runner_result_l = ->(proxy) { Services::AlertRunner.new(proxy).result }
23
- result = builder.result.bind(runner_result_l)
24
-
25
- alert = result.value!
26
- data = Entities::Alert.represent(alert)
27
- puts JSON.pretty_generate(data.as_json)
28
- end
27
+ # @type [Mihari::Models::Alert]
28
+ alert = result.value!
29
+ data = Entities::Alert.represent(alert)
30
+ puts JSON.pretty_generate(data.as_json)
29
31
  end
30
32
  end
31
33
  end
@@ -9,7 +9,10 @@ module Mihari
9
9
  class << self
10
10
  def included(thor)
11
11
  thor.class_eval do
12
+ include Mixins
13
+
12
14
  desc "migrate", "Migrate DB schemas"
15
+ around :with_db_connection
13
16
  method_option :verbose, type: :boolean, default: true
14
17
  #
15
18
  # @param [String] direction
@@ -17,7 +20,7 @@ module Mihari
17
20
  def migrate(direction = "up")
18
21
  ActiveRecord::Migration.verbose = options["verbose"]
19
22
 
20
- Mihari::Database.with_db_connection { Mihari::Database.migrate direction.to_sym }
23
+ Mihari::Database.migrate direction.to_sym
21
24
  end
22
25
  end
23
26
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mihari
4
+ module Commands
5
+ module Mixins
6
+ def with_db_connection(&block)
7
+ Mihari::Database.with_db_connection(&block)
8
+ end
9
+ end
10
+ end
11
+ end
@@ -10,8 +10,10 @@ module Mihari
10
10
  def included(thor)
11
11
  thor.class_eval do
12
12
  include Dry::Monads[:try, :result]
13
+ include Mixins
13
14
 
14
15
  desc "search [PATH_OR_ID]", "Search by a rule (Outputs null if there is no new finding)"
16
+ around :with_db_connection
15
17
  method_option :force_overwrite, type: :boolean, aliases: "-f", desc: "Force overwriting a rule"
16
18
  #
17
19
  # Search by a rule
@@ -19,43 +21,22 @@ module Mihari
19
21
  # @param [String] path_or_id
20
22
  #
21
23
  def search(path_or_id)
22
- Mihari::Database.with_db_connection do
23
- builder = Services::RuleBuilder.new(path_or_id)
24
+ result = Dry::Monads::Try[StandardError] do
25
+ # @type [Mihari::Rule]
26
+ rule = Services::RuleBuilder.call(path_or_id)
24
27
 
25
- check_diff_l = ->(rule) { check_diff rule }
26
- update_and_call_l = ->(runner) { update_and_call runner }
27
-
28
- result = builder.result.bind(check_diff_l).bind(update_and_call_l)
29
-
30
- alert = result.value!
31
- data = Entities::Alert.represent(alert)
32
- puts JSON.pretty_generate(data.as_json)
33
- end
34
- end
35
-
36
- no_commands do
37
- #
38
- # @param [Mihari::RuleRunner] rule
39
- #
40
- def check_diff(rule)
41
28
  force_overwrite = options["force_overwrite"] || false
42
29
  message = "There is a diff in the rule. Are you sure you want to overwrite the rule? (y/n)"
43
- runner = Services::RuleRunner.new(rule)
44
-
45
- exit 0 if runner.diff? && !force_overwrite && !yes?(message)
30
+ exit 0 if rule.diff? && !force_overwrite && !yes?(message)
46
31
 
47
- Success runner
48
- end
32
+ rule.update_or_create
33
+ rule.call
34
+ end.to_result
49
35
 
50
- #
51
- # @param [Mihari::RuleRunner] runner
52
- #
53
- def update_and_call(runner)
54
- Dry::Monads::Try[StandardError] do
55
- runner.update_or_create
56
- runner.call
57
- end.to_result
58
- end
36
+ # @type [Mihari::Models::Alert]
37
+ alert = result.value!
38
+ data = Entities::Alert.represent(alert)
39
+ puts JSON.pretty_generate(data.as_json)
59
40
  end
60
41
  end
61
42
  end
@@ -5,7 +5,7 @@ module Mihari
5
5
  DEFAULT_DATA_TYPES = Types::DataTypes.values.freeze
6
6
 
7
7
  # @return [Array<Hash>]
8
- DEFAULT_EMITTERS = Emitters::Database.class_keys.map { |name| { emitter: name } }.freeze
8
+ DEFAULT_EMITTERS = Emitters::Database.class_keys.map { |name| { emitter: name.downcase } }.freeze
9
9
 
10
10
  # @return [Array<Hash>]
11
11
  DEFAULT_ENRICHERS = Mihari.enricher_to_class.keys.map { |name| { enricher: name.downcase } }.freeze
@@ -134,7 +134,7 @@ module Mihari
134
134
  class Database
135
135
  class << self
136
136
  #
137
- # DB migraration
137
+ # DB migration
138
138
  #
139
139
  # @param [Symbol] direction
140
140
  #