mihari 5.7.1 → 6.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config.ru +2 -0
- data/lib/mihari/analyzers/dnstwister.rb +2 -4
- data/lib/mihari/analyzers/urlscan.rb +1 -4
- data/lib/mihari/cli/main.rb +4 -12
- data/lib/mihari/clients/base.rb +23 -1
- data/lib/mihari/clients/binaryedge.rb +1 -3
- data/lib/mihari/clients/censys.rb +1 -2
- data/lib/mihari/clients/crtsh.rb +2 -3
- data/lib/mihari/clients/dnstwister.rb +1 -2
- data/lib/mihari/clients/fofa.rb +1 -3
- data/lib/mihari/clients/greynoise.rb +1 -2
- data/lib/mihari/clients/hunterhow.rb +1 -2
- data/lib/mihari/clients/misp.rb +1 -2
- data/lib/mihari/clients/onyphe.rb +1 -2
- data/lib/mihari/clients/otx.rb +2 -14
- data/lib/mihari/clients/passivetotal.rb +3 -16
- data/lib/mihari/clients/publsedive.rb +2 -17
- data/lib/mihari/clients/securitytrails.rb +3 -25
- data/lib/mihari/clients/shodan.rb +1 -2
- data/lib/mihari/clients/the_hive.rb +1 -2
- data/lib/mihari/clients/urlscan.rb +1 -2
- data/lib/mihari/clients/virustotal.rb +3 -17
- data/lib/mihari/clients/zoomeye.rb +9 -19
- data/lib/mihari/commands/alert.rb +11 -11
- data/lib/mihari/commands/database.rb +4 -2
- data/lib/mihari/commands/mixins.rb +11 -0
- data/lib/mihari/commands/search.rb +15 -15
- data/lib/mihari/constants.rb +1 -1
- data/lib/mihari/database.rb +3 -5
- data/lib/mihari/emitters/slack.rb +3 -6
- data/lib/mihari/emitters/the_hive.rb +3 -7
- data/lib/mihari/enrichers/google_public_dns.rb +2 -7
- data/lib/mihari/enrichers/ipinfo.rb +1 -3
- data/lib/mihari/enrichers/shodan.rb +1 -3
- data/lib/mihari/enrichers/whois.rb +0 -4
- data/lib/mihari/http.rb +13 -11
- data/lib/mihari/mixins/refang.rb +1 -4
- data/lib/mihari/mixins/unwrap_error.rb +27 -0
- data/lib/mihari/models/alert.rb +1 -3
- data/lib/mihari/models/artifact.rb +5 -7
- data/lib/mihari/models/rule.rb +1 -2
- data/lib/mihari/rule.rb +14 -10
- data/lib/mihari/service.rb +2 -0
- data/lib/mihari/services/rule_builder.rb +2 -4
- data/lib/mihari/structs/fofa.rb +2 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +3 -1
- data/lib/mihari/web/endpoints/alerts.rb +14 -18
- data/lib/mihari/web/endpoints/artifacts.rb +17 -22
- data/lib/mihari/web/endpoints/configs.rb +0 -1
- data/lib/mihari/web/endpoints/ip_addresses.rb +1 -1
- data/lib/mihari/web/endpoints/rules.rb +27 -32
- data/lib/mihari/web/endpoints/tags.rb +7 -9
- data/lib/mihari/web/middleware/connection_adapter.rb +3 -5
- data/lib/mihari/web/middleware/error_notification_adapter.rb +15 -6
- data/lib/mihari/web/public/assets/{index-07fafab5.js → index-07cddfcd.js} +44 -44
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari/web/public/redoc-static.html +381 -401
- data/lib/mihari.rb +1 -2
- data/mihari.gemspec +14 -16
- data/mkdocs.yml +14 -8
- data/requirements.txt +1 -1
- metadata +81 -39
- data/lib/mihari/mixins/error_notification.rb +0 -21
- data/lib/mihari/services/rule_runner.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2846f5154fcdde4cda4f0237c79e047fc498b96b5c21a6152287ac9ab11faac9
|
4
|
+
data.tar.gz: f43b4e20a59b1274b62c5e9768f153429540067882508b34f0c36932cc9cb5ef
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b54da0da25e57531c1efef94bdc42df715569b9e88842ca330d1d0893f4c20990bb2ded22a001f31816cbd72f00f43473f0254f222a9849308be746576128e3c
|
7
|
+
data.tar.gz: 7167afd356c4f945e66631bb3c6cefc06678961b480511d85939e6ede9eccec9a5f83a948a169be9ee7ba5cc79af918a447b8f01e5280faff3138071e7808beb
|
data/config.ru
CHANGED
@@ -25,9 +25,7 @@ module Mihari
|
|
25
25
|
raise ValueError, "#{query}(type: #{type || "unknown"}) is not supported." unless valid_type?
|
26
26
|
|
27
27
|
domains = client.fuzz(query)
|
28
|
-
Parallel.map(domains)
|
29
|
-
resolvable?(domain) ? domain : nil
|
30
|
-
end.compact
|
28
|
+
Parallel.map(domains) { |domain| resolvable?(domain) ? domain : nil }.compact
|
31
29
|
end
|
32
30
|
|
33
31
|
private
|
@@ -55,7 +53,7 @@ module Mihari
|
|
55
53
|
def resolvable?(domain)
|
56
54
|
Resolv.getaddress domain
|
57
55
|
true
|
58
|
-
rescue Resolv::ResolvError
|
56
|
+
rescue Resolv::ResolvError
|
59
57
|
false
|
60
58
|
end
|
61
59
|
end
|
@@ -34,10 +34,7 @@ module Mihari
|
|
34
34
|
def artifacts
|
35
35
|
# @type [Array<Mihari::Models::Artifact>]
|
36
36
|
artifacts = client.search_with_pagination(query, pagination_limit: pagination_limit).map(&:artifacts).flatten
|
37
|
-
|
38
|
-
artifacts.select do |artifact|
|
39
|
-
allowed_data_types.include? artifact.data_type
|
40
|
-
end
|
37
|
+
artifacts.select { |artifact| allowed_data_types.include? artifact.data_type }
|
41
38
|
end
|
42
39
|
|
43
40
|
def configuration_keys
|
data/lib/mihari/cli/main.rb
CHANGED
@@ -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"
|
@@ -30,19 +32,9 @@ module Mihari
|
|
30
32
|
include Mihari::Commands::Version
|
31
33
|
include Mihari::Commands::Web
|
32
34
|
|
33
|
-
|
34
|
-
def unwrap_error(err)
|
35
|
-
return err unless err.is_a?(Dry::Monads::UnwrapError)
|
36
|
-
|
37
|
-
# NOTE: UnwrapError's receiver can be either of:
|
38
|
-
# - Dry::Monads::Try::Error
|
39
|
-
# - Dry::Monads::Result::Failure
|
40
|
-
receiver = err.receiver
|
41
|
-
return receiver.exception if receiver.is_a?(Dry::Monads::Try::Error)
|
42
|
-
|
43
|
-
receiver.failure
|
44
|
-
end
|
35
|
+
include Mihari::Mixins::UnwrapError
|
45
36
|
|
37
|
+
no_commands do
|
46
38
|
def safe_execute
|
47
39
|
yield
|
48
40
|
rescue StandardError => e
|
data/lib/mihari/clients/base.rb
CHANGED
@@ -41,7 +41,7 @@ module Mihari
|
|
41
41
|
# @return [::HTTP::Client]
|
42
42
|
#
|
43
43
|
def http
|
44
|
-
HTTP::Factory.build
|
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
|
-
|
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
|
#
|
data/lib/mihari/clients/crtsh.rb
CHANGED
@@ -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
|
-
|
31
|
-
parsed =
|
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 =
|
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
|
data/lib/mihari/clients/fofa.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
#
|
data/lib/mihari/clients/misp.rb
CHANGED
@@ -40,8 +40,7 @@ module Mihari
|
|
40
40
|
#
|
41
41
|
def datascan(query, page: 1)
|
42
42
|
params = { page: page, apikey: api_key }
|
43
|
-
|
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
|
#
|
data/lib/mihari/clients/otx.rb
CHANGED
@@ -65,7 +65,7 @@ module Mihari
|
|
65
65
|
# @return [Hash]
|
66
66
|
#
|
67
67
|
def query_by_ip(ip)
|
68
|
-
|
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
|
-
|
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 =
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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 =
|
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 =
|
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
|
-
|
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
|
-
|
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
|
#
|
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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,24 +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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end.to_result
|
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
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
27
|
+
# @type [Mihari::Models::Alert]
|
28
|
+
alert = result.value!
|
29
|
+
data = Entities::Alert.represent(alert)
|
30
|
+
puts JSON.pretty_generate(data.as_json)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -9,15 +9,17 @@ 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
|
16
19
|
#
|
17
20
|
def migrate(direction = "up")
|
18
21
|
ActiveRecord::Migration.verbose = options["verbose"]
|
19
|
-
|
20
|
-
Mihari::Database.with_db_connection { Mihari::Database.migrate direction.to_sym }
|
22
|
+
Mihari::Database.migrate direction.to_sym
|
21
23
|
end
|
22
24
|
end
|
23
25
|
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,24 +21,22 @@ module Mihari
|
|
19
21
|
# @param [String] path_or_id
|
20
22
|
#
|
21
23
|
def search(path_or_id)
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rule = Services::RuleBuilder.call(path_or_id)
|
24
|
+
result = Dry::Monads::Try[StandardError] do
|
25
|
+
# @type [Mihari::Rule]
|
26
|
+
rule = Services::RuleBuilder.call(path_or_id)
|
26
27
|
|
27
|
-
|
28
|
-
|
29
|
-
|
28
|
+
force_overwrite = options["force_overwrite"] || false
|
29
|
+
message = "There is a diff in the rule. Are you sure you want to overwrite the rule? (y/n)"
|
30
|
+
exit 0 if rule.diff? && !force_overwrite && !yes?(message)
|
30
31
|
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
rule.update_or_create
|
33
|
+
rule.call
|
34
|
+
end.to_result
|
34
35
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
end
|
36
|
+
# @type [Mihari::Models::Alert]
|
37
|
+
alert = result.value!
|
38
|
+
data = Entities::Alert.represent(alert)
|
39
|
+
puts JSON.pretty_generate(data.as_json)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
end
|
data/lib/mihari/constants.rb
CHANGED
@@ -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
|