mihari 7.0.5 → 7.1.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.
- checksums.yaml +4 -4
- data/lib/mihari/cli/application.rb +3 -0
- data/lib/mihari/commands/alert.rb +37 -2
- data/lib/mihari/commands/artifact.rb +37 -2
- data/lib/mihari/commands/config.rb +1 -1
- data/lib/mihari/commands/rule.rb +37 -2
- data/lib/mihari/commands/tag.rb +37 -2
- data/lib/mihari/concerns/retriable.rb +1 -1
- data/lib/mihari/data_type.rb +3 -3
- data/lib/mihari/emitters/webhook.rb +15 -53
- data/lib/mihari/errors.rb +2 -2
- data/lib/mihari/http.rb +1 -1
- data/lib/mihari/services/renderer.rb +31 -0
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/endpoints/ip_addresses.rb +1 -1
- data/lib/mihari/web/public/assets/{index-geliIfjB.js → index-U5u7qHZZ.js} +18 -18
- data/lib/mihari/web/public/index.html +1 -1
- data/lib/mihari.rb +1 -0
- data/mihari.gemspec +5 -2
- data/test.json.jbuilder +7 -0
- metadata +51 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6930da0e95068ca8e30d1f226be5692e85375f796b7246cafdd2bec566d00ff7
|
4
|
+
data.tar.gz: 2bf34b1231bffcd88d402ffda335960ad929b1de91cd51b257c9c24f7b2fc16f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd515cdbde67d10c3fcae14c8e45a7929a34931701be176c9f9a294d3db310f522a3e186aefe548d6f119c5c8552723114da4ee6f790dbbe0391138dca9cc00e
|
7
|
+
data.tar.gz: 5f4a3e1049ad55af018cf9ed2186dda49bd18517d37bc84cad6e6f60b10589834ac3bd1f09333e7f9773fab43442400c097c1063f1c304d5be5eb8991af7ec77
|
@@ -43,6 +43,9 @@ module Mihari
|
|
43
43
|
rescue StandardError => e
|
44
44
|
error = unwrap_error(e)
|
45
45
|
|
46
|
+
# Raise error if it's a Thor::Error to follow Thor's manner
|
47
|
+
raise error if error.is_a?(Thor::Error)
|
48
|
+
# Raise error if debug is set as true
|
46
49
|
raise error if options["debug"]
|
47
50
|
|
48
51
|
data = Entities::ErrorMessage.represent(
|
@@ -12,6 +12,20 @@ module Mihari
|
|
12
12
|
thor.class_eval do
|
13
13
|
include Concerns::DatabaseConnectable
|
14
14
|
|
15
|
+
no_commands do
|
16
|
+
#
|
17
|
+
# @param [String] q
|
18
|
+
# @param [Integer] page
|
19
|
+
# @param [Integer] limit
|
20
|
+
#
|
21
|
+
# @return [Mihari::Services::ResultValue]
|
22
|
+
#
|
23
|
+
def _search(q, page: 1, limit: 10)
|
24
|
+
filter = Structs::Filters::Search.new(q: q, page: page, limit: limit)
|
25
|
+
Services::AlertSearcher.result(filter).value!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
15
29
|
desc "create [PATH]", "Create an alert"
|
16
30
|
around :with_db_connection
|
17
31
|
#
|
@@ -40,8 +54,7 @@ module Mihari
|
|
40
54
|
# @param [String] q
|
41
55
|
#
|
42
56
|
def list(q = "")
|
43
|
-
|
44
|
-
value = Services::AlertSearcher.result(filter).value!
|
57
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
45
58
|
data = Entities::AlertsWithPagination.represent(
|
46
59
|
results: value.results,
|
47
60
|
total: value.total,
|
@@ -51,6 +64,28 @@ module Mihari
|
|
51
64
|
puts JSON.pretty_generate(data.as_json)
|
52
65
|
end
|
53
66
|
|
67
|
+
desc "list-transform QUERY", "List/search alerts with transformation"
|
68
|
+
around :with_db_connection
|
69
|
+
method_option :template, type: :string, required: true, aliases: "-t",
|
70
|
+
description: "Jbuilder template itself or a path to a template file"
|
71
|
+
method_option :page, type: :numeric, default: 1
|
72
|
+
method_option :limit, type: :numeric, default: 10
|
73
|
+
#
|
74
|
+
# @param [String] q
|
75
|
+
#
|
76
|
+
def list_transform(q = "")
|
77
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
78
|
+
puts Services::JbuilderRenderer.call(
|
79
|
+
options["template"],
|
80
|
+
{
|
81
|
+
results: value.results,
|
82
|
+
total: value.total,
|
83
|
+
current_page: value.filter[:page].to_i,
|
84
|
+
page_size: value.filter[:limit].to_i
|
85
|
+
}
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
54
89
|
desc "get [ID]", "Get an alert"
|
55
90
|
around :with_db_connection
|
56
91
|
#
|
@@ -11,6 +11,20 @@ module Mihari
|
|
11
11
|
thor.class_eval do
|
12
12
|
include Concerns::DatabaseConnectable
|
13
13
|
|
14
|
+
no_commands do
|
15
|
+
#
|
16
|
+
# @param [String] q
|
17
|
+
# @param [Integer] page
|
18
|
+
# @param [Integer] limit
|
19
|
+
#
|
20
|
+
# @return [Mihari::Services::ResultValue]
|
21
|
+
#
|
22
|
+
def _search(q, page: 1, limit: 10)
|
23
|
+
filter = Structs::Filters::Search.new(q: q, page: page, limit: limit)
|
24
|
+
Services::ArtifactSearcher.result(filter).value!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
14
28
|
desc "list [QUERY]", "List/search artifacts"
|
15
29
|
around :with_db_connection
|
16
30
|
method_option :page, type: :numeric, default: 1
|
@@ -19,8 +33,7 @@ module Mihari
|
|
19
33
|
# @param [String] q
|
20
34
|
#
|
21
35
|
def list(q = "")
|
22
|
-
|
23
|
-
value = Services::ArtifactSearcher.result(filter).value!
|
36
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
24
37
|
data = Entities::ArtifactsWithPagination.represent(
|
25
38
|
results: value.results,
|
26
39
|
total: value.total,
|
@@ -30,6 +43,28 @@ module Mihari
|
|
30
43
|
puts JSON.pretty_generate(data.as_json)
|
31
44
|
end
|
32
45
|
|
46
|
+
desc "list-transform QUERY", "List/search artifacts with transformation"
|
47
|
+
around :with_db_connection
|
48
|
+
method_option :template, type: :string, required: true, aliases: "-t",
|
49
|
+
description: "Jbuilder template itself or a path to a template file"
|
50
|
+
method_option :page, type: :numeric, default: 1
|
51
|
+
method_option :limit, type: :numeric, default: 10
|
52
|
+
#
|
53
|
+
# @param [String] q
|
54
|
+
#
|
55
|
+
def list_transform(q = "")
|
56
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
57
|
+
puts Services::JbuilderRenderer.call(
|
58
|
+
options["template"],
|
59
|
+
{
|
60
|
+
results: value.results,
|
61
|
+
total: value.total,
|
62
|
+
current_page: value.filter[:page].to_i,
|
63
|
+
page_size: value.filter[:limit].to_i
|
64
|
+
}
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
33
68
|
desc "get [ID]", "Get an artifact"
|
34
69
|
around :with_db_connection
|
35
70
|
#
|
data/lib/mihari/commands/rule.rb
CHANGED
@@ -12,6 +12,20 @@ module Mihari
|
|
12
12
|
thor.class_eval do
|
13
13
|
include Concerns::DatabaseConnectable
|
14
14
|
|
15
|
+
no_commands do
|
16
|
+
#
|
17
|
+
# @param [String] q
|
18
|
+
# @param [Integer] page
|
19
|
+
# @param [Integer] limit
|
20
|
+
#
|
21
|
+
# @return [Mihari::Services::ResultValue]
|
22
|
+
#
|
23
|
+
def _search(q, page: 1, limit: 10)
|
24
|
+
filter = Structs::Filters::Search.new(q: q, page: page, limit: limit)
|
25
|
+
Services::RuleSearcher.result(filter).value!
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
15
29
|
desc "validate [PATH]", "Validate a rule file"
|
16
30
|
#
|
17
31
|
# Validate format of a rule
|
@@ -44,8 +58,7 @@ module Mihari
|
|
44
58
|
# @param [String] q
|
45
59
|
#
|
46
60
|
def list(q = "")
|
47
|
-
|
48
|
-
value = Services::RuleSearcher.result(filter).value!
|
61
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
49
62
|
data = Entities::RulesWithPagination.represent(
|
50
63
|
results: value.results,
|
51
64
|
total: value.total,
|
@@ -55,6 +68,28 @@ module Mihari
|
|
55
68
|
puts JSON.pretty_generate(data.as_json)
|
56
69
|
end
|
57
70
|
|
71
|
+
desc "list-transform QUERY", "List/search rules with transformation"
|
72
|
+
around :with_db_connection
|
73
|
+
method_option :template, type: :string, required: true, aliases: "-t",
|
74
|
+
description: "Jbuilder template itself or a path to a template file"
|
75
|
+
method_option :page, type: :numeric, default: 1
|
76
|
+
method_option :limit, type: :numeric, default: 10
|
77
|
+
#
|
78
|
+
# @param [String] q
|
79
|
+
#
|
80
|
+
def list_transform(q = "")
|
81
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
82
|
+
puts Services::JbuilderRenderer.call(
|
83
|
+
options["template"],
|
84
|
+
{
|
85
|
+
results: value.results,
|
86
|
+
total: value.total,
|
87
|
+
current_page: value.filter[:page].to_i,
|
88
|
+
page_size: value.filter[:limit].to_i
|
89
|
+
}
|
90
|
+
)
|
91
|
+
end
|
92
|
+
|
58
93
|
desc "get [ID]", "Get a rule"
|
59
94
|
around :with_db_connection
|
60
95
|
def get(id)
|
data/lib/mihari/commands/tag.rb
CHANGED
@@ -11,6 +11,20 @@ module Mihari
|
|
11
11
|
thor.class_eval do
|
12
12
|
include Concerns::DatabaseConnectable
|
13
13
|
|
14
|
+
no_commands do
|
15
|
+
#
|
16
|
+
# @param [String] q
|
17
|
+
# @param [Integer] page
|
18
|
+
# @param [Integer] limit
|
19
|
+
#
|
20
|
+
# @return [Mihari::Services::ResultValue]
|
21
|
+
#
|
22
|
+
def _search(q, page: 1, limit: 10)
|
23
|
+
filter = Structs::Filters::Search.new(q: q, page: page, limit: limit)
|
24
|
+
Services::TagSearcher.result(filter).value!
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
14
28
|
desc "list", "List/search tags"
|
15
29
|
around :with_db_connection
|
16
30
|
method_option :page, type: :numeric, default: 1
|
@@ -19,8 +33,7 @@ module Mihari
|
|
19
33
|
# @param [String] q
|
20
34
|
#
|
21
35
|
def list(q = "")
|
22
|
-
|
23
|
-
value = Services::TagSearcher.result(filter).value!
|
36
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
24
37
|
data = Entities::TagsWithPagination.represent(
|
25
38
|
results: value.results,
|
26
39
|
total: value.total,
|
@@ -30,6 +43,28 @@ module Mihari
|
|
30
43
|
puts JSON.pretty_generate(data.as_json)
|
31
44
|
end
|
32
45
|
|
46
|
+
desc "list-transform QUERY", "List/search tags with transformation"
|
47
|
+
around :with_db_connection
|
48
|
+
method_option :template, type: :string, required: true, aliases: "-t",
|
49
|
+
description: "Jbuilder template itself or a path to a template file"
|
50
|
+
method_option :page, type: :numeric, default: 1
|
51
|
+
method_option :limit, type: :numeric, default: 10
|
52
|
+
#
|
53
|
+
# @param [String] q
|
54
|
+
#
|
55
|
+
def list_transform(q = "")
|
56
|
+
value = _search(q, page: options["page"], limit: options["limit"])
|
57
|
+
puts Services::JbuilderRenderer.call(
|
58
|
+
options["template"],
|
59
|
+
{
|
60
|
+
results: value.results,
|
61
|
+
total: value.total,
|
62
|
+
current_page: value.filter[:page].to_i,
|
63
|
+
page_size: value.filter[:limit].to_i
|
64
|
+
}
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
33
68
|
desc "delete [ID]", "Delete a tag"
|
34
69
|
around :with_db_connection
|
35
70
|
#
|
data/lib/mihari/data_type.rb
CHANGED
@@ -28,7 +28,7 @@ module Mihari
|
|
28
28
|
def ip?
|
29
29
|
Try[IPAddr::InvalidAddressError] do
|
30
30
|
IPAddr.new(data).to_s == data
|
31
|
-
end.
|
31
|
+
end.recover { false }.value!
|
32
32
|
end
|
33
33
|
|
34
34
|
# @return [Boolean]
|
@@ -36,7 +36,7 @@ module Mihari
|
|
36
36
|
Try[Addressable::URI::InvalidURIError] do
|
37
37
|
uri = Addressable::URI.parse("http://#{data}")
|
38
38
|
uri.host == data && PublicSuffix.valid?(uri.host)
|
39
|
-
end.
|
39
|
+
end.recover { false }.value!
|
40
40
|
end
|
41
41
|
|
42
42
|
# @return [Boolean]
|
@@ -44,7 +44,7 @@ module Mihari
|
|
44
44
|
Try[Addressable::URI::InvalidURIError] do
|
45
45
|
uri = Addressable::URI.parse(data)
|
46
46
|
uri.scheme && uri.host && uri.path && PublicSuffix.valid?(uri.host)
|
47
|
-
end.
|
47
|
+
end.recover { false }.value!
|
48
48
|
end
|
49
49
|
|
50
50
|
# @return [Boolean]
|
@@ -1,49 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "erb"
|
4
|
-
|
5
3
|
module Mihari
|
6
4
|
module Emitters
|
7
|
-
class ERBTemplate < ERB
|
8
|
-
class << self
|
9
|
-
def template
|
10
|
-
%{
|
11
|
-
{
|
12
|
-
"rule": {
|
13
|
-
"id": "<%= @rule.id %>",
|
14
|
-
"title": "<%= @rule.title %>",
|
15
|
-
"description": "<%= @rule.description %>"
|
16
|
-
},
|
17
|
-
"artifacts": [
|
18
|
-
<% @artifacts.each_with_index do |artifact, idx| %>
|
19
|
-
"<%= artifact.data %>"
|
20
|
-
<%= ',' if idx < (@artifacts.length - 1) %>
|
21
|
-
<% end %>
|
22
|
-
],
|
23
|
-
"tags": [
|
24
|
-
<% @rule.tags.each_with_index do |tag, idx| %>
|
25
|
-
"<%= tag.name %>"
|
26
|
-
<%= ',' if idx < (@rule.tags.length - 1) %>
|
27
|
-
<% end %>
|
28
|
-
]
|
29
|
-
}
|
30
|
-
}
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def initialize(artifacts:, rule:, options: {})
|
35
|
-
@artifacts = artifacts
|
36
|
-
@rule = rule
|
37
|
-
|
38
|
-
@template = options.fetch(:template, self.class.template)
|
39
|
-
super(@template)
|
40
|
-
end
|
41
|
-
|
42
|
-
def result
|
43
|
-
super(binding)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
5
|
class Webhook < Base
|
48
6
|
# @return [Addressable::URI, nil]
|
49
7
|
attr_reader :url
|
@@ -54,12 +12,24 @@ module Mihari
|
|
54
12
|
# @return [String]
|
55
13
|
attr_reader :method
|
56
14
|
|
57
|
-
# @return [String
|
15
|
+
# @return [String]
|
58
16
|
attr_reader :template
|
59
17
|
|
60
18
|
# @return [Array<Mihari::Models::Artifact>]
|
61
19
|
attr_accessor :artifacts
|
62
20
|
|
21
|
+
DEFAULT_TEMPLATE = %{
|
22
|
+
json.rule do
|
23
|
+
json.id rule.id
|
24
|
+
json.title rule.title
|
25
|
+
json.description rule.description
|
26
|
+
end
|
27
|
+
|
28
|
+
json.artifacts artifacts.map(&:data)
|
29
|
+
|
30
|
+
json.tags rule.tags.map(&:name)
|
31
|
+
}
|
32
|
+
|
63
33
|
#
|
64
34
|
# @param [Mihari::Rule] rule
|
65
35
|
# @param [Hash, nil] options
|
@@ -71,7 +41,7 @@ module Mihari
|
|
71
41
|
@url = Addressable::URI.parse(params[:url])
|
72
42
|
@headers = params[:headers] || {}
|
73
43
|
@method = params[:method] || "POST"
|
74
|
-
@template = params[:template]
|
44
|
+
@template = params[:template] || DEFAULT_TEMPLATE
|
75
45
|
|
76
46
|
@artifacts = []
|
77
47
|
end
|
@@ -114,15 +84,7 @@ module Mihari
|
|
114
84
|
# @return [String]
|
115
85
|
#
|
116
86
|
def render
|
117
|
-
|
118
|
-
options[:template] = File.read(template) unless template.nil?
|
119
|
-
|
120
|
-
erb_template = ERBTemplate.new(
|
121
|
-
artifacts: artifacts,
|
122
|
-
rule: rule,
|
123
|
-
options: options
|
124
|
-
)
|
125
|
-
erb_template.result
|
87
|
+
Services::JbuilderRenderer.call(template, { rule: rule, artifacts: artifacts })
|
126
88
|
end
|
127
89
|
|
128
90
|
#
|
data/lib/mihari/errors.rb
CHANGED
data/lib/mihari/http.rb
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
require "tilt/jbuilder"
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Services
|
5
|
+
#
|
6
|
+
# Jbuilder based JSON renderer
|
7
|
+
#
|
8
|
+
class JbuilderRenderer < Service
|
9
|
+
attr_reader :template
|
10
|
+
|
11
|
+
#
|
12
|
+
# @param [String] template
|
13
|
+
# @param [Hash] params
|
14
|
+
#
|
15
|
+
# @return [String]
|
16
|
+
#
|
17
|
+
def call(template, params = {})
|
18
|
+
@template = template
|
19
|
+
|
20
|
+
jbuilder_template = Tilt::JbuilderTemplate.new { template_string }
|
21
|
+
jbuilder_template.render(nil, params)
|
22
|
+
end
|
23
|
+
|
24
|
+
def template_string
|
25
|
+
return File.read(template) if Pathname(template).exist?
|
26
|
+
|
27
|
+
template
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/mihari/version.rb
CHANGED
@@ -36,7 +36,7 @@ module Mihari
|
|
36
36
|
|
37
37
|
failure = result.failure
|
38
38
|
case failure
|
39
|
-
when Mihari::
|
39
|
+
when Mihari::StatusError
|
40
40
|
error!({ message: "IP:#{ip} not found" }, failure.status_code) if failure.status_code == 404
|
41
41
|
error!({ message: "IP format invalid" }, failure.status_code) if failure.status_code == 422
|
42
42
|
end
|