mihari 2.0.0 → 2.3.1
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/.github/ISSUE_TEMPLATE/bug_report.md +43 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +15 -0
- data/.rubocop.yml +6 -0
- data/.standard.yml +4 -0
- data/README.md +11 -1
- data/bin/console +1 -0
- data/docker/Dockerfile +3 -2
- data/examples/ipinfo_hosted_domains.rb +1 -1
- data/images/{eyecatch.png → overview.png} +0 -0
- data/images/tines.png +0 -0
- data/images/web_alerts.png +0 -0
- data/images/web_config.png +0 -0
- data/lib/mihari/analyzers/base.rb +11 -2
- data/lib/mihari/analyzers/circl.rb +3 -3
- data/lib/mihari/analyzers/onyphe.rb +2 -2
- data/lib/mihari/analyzers/securitytrails.rb +2 -2
- data/lib/mihari/analyzers/urlscan.rb +1 -6
- data/lib/mihari/analyzers/zoomeye.rb +2 -2
- data/lib/mihari/cli.rb +72 -289
- data/lib/mihari/commands/binaryedge.rb +21 -0
- data/lib/mihari/commands/censys.rb +22 -0
- data/lib/mihari/commands/circl.rb +21 -0
- data/lib/mihari/commands/config.rb +27 -0
- data/lib/mihari/commands/crtsh.rb +22 -0
- data/lib/mihari/commands/dnpedia.rb +21 -0
- data/lib/mihari/commands/dnstwister.rb +21 -0
- data/lib/mihari/commands/free_text.rb +21 -0
- data/lib/mihari/commands/http_hash.rb +25 -0
- data/lib/mihari/commands/json.rb +42 -0
- data/lib/mihari/commands/onyphe.rb +21 -0
- data/lib/mihari/commands/otx.rb +21 -0
- data/lib/mihari/commands/passive_dns.rb +21 -0
- data/lib/mihari/commands/passive_ssl.rb +21 -0
- data/lib/mihari/commands/passivetotal.rb +21 -0
- data/lib/mihari/commands/pulsedive.rb +21 -0
- data/lib/mihari/commands/reverse_whois.rb +21 -0
- data/lib/mihari/commands/securitytrails.rb +22 -0
- data/lib/mihari/commands/securitytrails_domain_feed.rb +23 -0
- data/lib/mihari/commands/shodan.rb +21 -0
- data/lib/mihari/commands/spyse.rb +22 -0
- data/lib/mihari/commands/ssh_fingerprint.rb +21 -0
- data/lib/mihari/commands/urlscan.rb +23 -0
- data/lib/mihari/commands/virustotal.rb +21 -0
- data/lib/mihari/commands/web.rb +22 -0
- data/lib/mihari/commands/zoomeye.rb +22 -0
- data/lib/mihari/config.rb +14 -3
- data/lib/mihari/configurable.rb +1 -1
- data/lib/mihari/emitters/slack.rb +4 -4
- data/lib/mihari/emitters/the_hive.rb +1 -1
- data/lib/mihari/models/alert.rb +5 -5
- data/lib/mihari/models/artifact.rb +13 -2
- data/lib/mihari/notifiers/exception_notifier.rb +4 -4
- data/lib/mihari/status.rb +2 -10
- data/lib/mihari/version.rb +1 -1
- data/lib/mihari/web/app.rb +25 -100
- data/lib/mihari/web/controllers/alerts_controller.rb +75 -0
- data/lib/mihari/web/controllers/artifacts_controller.rb +24 -0
- data/lib/mihari/web/controllers/base_controller.rb +22 -0
- data/lib/mihari/web/controllers/command_controller.rb +26 -0
- data/lib/mihari/web/controllers/config_controller.rb +13 -0
- data/lib/mihari/web/controllers/sources_controller.rb +12 -0
- data/lib/mihari/web/controllers/tags_controller.rb +28 -0
- data/lib/mihari/web/helpers/json.rb +53 -0
- data/lib/mihari/web/public/index.html +2 -2
- data/lib/mihari/web/public/redoc-static.html +519 -0
- data/lib/mihari/web/public/static/js/{app.58b32d15.js → app.cccddb2b.js} +4 -4
- data/lib/mihari/web/public/static/js/app.cccddb2b.js.map +1 -0
- data/mihari.gemspec +9 -3
- metadata +146 -23
- data/lib/mihari/web/public/static/js/app.58b32d15.js.map +0 -1
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module SecurityTrailsDomainFeed
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "securitytrails_domain_feed [REGEXP]", "SecurityTrails new domain feed search by a regexp"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
method_option :type, type: :string, default: "registered", desc: "A type of domain feed ('all', 'new' or 'registered')"
|
13
|
+
def securitytrails_domain_feed(regexp)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::SecurityTrailsDomainFeed, query: regexp, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
map "st_domain_feed" => :securitytrails_domain_feedd
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Shodan
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "shodan [QUERY]", "Shodan host search by a query"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
def shodan(query)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::Shodan, query: query, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Spyse
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "spyse [QUERY]", "Spyse search by a query"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
method_option :type, type: :string, desc: "type to search (ip or domain)", default: "doamin"
|
13
|
+
def spyse(query)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::Spyse, query: query, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module SSHFingerprint
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "ssh_fingerprint [FINGERPRINT]", "Cross search with search engines by an SSH fingerprint (e.g. dc:14:de:8e:d7:c1:15:43:23:82:25:81:d2:59:e8:c0)"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
def ssh_fingerprint(fingerprint)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::SSHFingerprint, query: fingerprint, options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Urlscan
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "urlscan [QUERY]", "urlscan search by a given query"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
method_option :target_type, type: :string, default: "url", desc: "target type to fetch from lookup results (target type should be 'url', 'domain' or 'ip')"
|
13
|
+
method_option :use_similarity, type: :boolean, default: false, desc: "use similarity API or not"
|
14
|
+
def urlscan(query)
|
15
|
+
with_error_handling do
|
16
|
+
run_analyzer Analyzers::Urlscan, query: query, options: options
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module VirusTotal
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "virustotal [IP|DOMAIN]", "VirusTotal resolutions lookup by an ip or domain"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
def virustotal(indiactor)
|
13
|
+
with_error_handling do
|
14
|
+
run_analyzer Analyzers::VirusTotal, query: refang(indiactor), options: options
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module Web
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "web", "Launch the web app"
|
9
|
+
method_option :port, type: :numeric, default: 9292
|
10
|
+
method_option :host, type: :string, default: "localhost"
|
11
|
+
def web
|
12
|
+
port = options["port"].to_i || 9292
|
13
|
+
host = options["host"] || "localhost"
|
14
|
+
|
15
|
+
load_configuration
|
16
|
+
Mihari::App.run!(port: port, host: host)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mihari
|
4
|
+
module Commands
|
5
|
+
module ZoomEye
|
6
|
+
def self.included(thor)
|
7
|
+
thor.class_eval do
|
8
|
+
desc "zoomeye [QUERY]", "ZoomEye search by a query"
|
9
|
+
method_option :title, type: :string, desc: "title"
|
10
|
+
method_option :description, type: :string, desc: "description"
|
11
|
+
method_option :tags, type: :array, desc: "tags"
|
12
|
+
method_option :type, type: :string, desc: "type to search(host / web)", default: "host"
|
13
|
+
def zoomeye(query)
|
14
|
+
with_error_handling do
|
15
|
+
run_analyzer Analyzers::ZoomEye, query: query, options: options
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/mihari/config.rb
CHANGED
@@ -4,7 +4,7 @@ require "yaml"
|
|
4
4
|
|
5
5
|
module Mihari
|
6
6
|
class Config
|
7
|
-
attr_accessor :binaryedge_api_key, :censys_id, :censys_secret, :circl_passive_password, :circl_passive_username, :misp_api_endpoint, :misp_api_key, :onyphe_api_key, :otx_api_key, :passivetotal_api_key, :passivetotal_username, :pulsedive_api_key, :securitytrails_api_key, :shodan_api_key, :slack_channel, :slack_webhook_url, :spyse_api_key, :thehive_api_endpoint, :thehive_api_key, :urlscan_api_key, :virustotal_api_key, :
|
7
|
+
attr_accessor :binaryedge_api_key, :censys_id, :censys_secret, :circl_passive_password, :circl_passive_username, :misp_api_endpoint, :misp_api_key, :onyphe_api_key, :otx_api_key, :passivetotal_api_key, :passivetotal_username, :pulsedive_api_key, :securitytrails_api_key, :shodan_api_key, :slack_channel, :slack_webhook_url, :spyse_api_key, :thehive_api_endpoint, :thehive_api_key, :urlscan_api_key, :virustotal_api_key, :zoomeye_api_key, :database
|
8
8
|
|
9
9
|
def initialize
|
10
10
|
load_from_env
|
@@ -32,8 +32,7 @@ module Mihari
|
|
32
32
|
@thehive_api_key = ENV["THEHIVE_API_KEY"]
|
33
33
|
@urlscan_api_key = ENV["URLSCAN_API_KEY"]
|
34
34
|
@virustotal_api_key = ENV["VIRUSTOTAL_API_KEY"]
|
35
|
-
@
|
36
|
-
@zoomeye_username = ENV["ZOOMEYE_USERNAME"]
|
35
|
+
@zoomeye_api_key = ENV["ZOOMEYE_API_KEY"]
|
37
36
|
|
38
37
|
@database = ENV["DATABASE"] || "mihari.db"
|
39
38
|
end
|
@@ -55,6 +54,18 @@ module Mihari
|
|
55
54
|
end
|
56
55
|
end
|
57
56
|
end
|
57
|
+
|
58
|
+
def initialize_yaml(filename)
|
59
|
+
keys = new.instance_variables.map do |key|
|
60
|
+
key.to_s[1..]
|
61
|
+
end
|
62
|
+
|
63
|
+
config = keys.map do |key|
|
64
|
+
[key, nil]
|
65
|
+
end.to_h
|
66
|
+
|
67
|
+
YAML.dump(config, File.open(filename, "w"))
|
68
|
+
end
|
58
69
|
end
|
59
70
|
end
|
60
71
|
|
data/lib/mihari/configurable.rb
CHANGED
@@ -25,25 +25,25 @@ module Mihari
|
|
25
25
|
def vt_link
|
26
26
|
return nil unless _vt_link
|
27
27
|
|
28
|
-
{type: "button", text: "VirusTotal", url: _vt_link}
|
28
|
+
{ type: "button", text: "VirusTotal", url: _vt_link }
|
29
29
|
end
|
30
30
|
|
31
31
|
def urlscan_link
|
32
32
|
return nil unless _urlscan_link
|
33
33
|
|
34
|
-
{type: "button", text: "urlscan.io", url: _urlscan_link}
|
34
|
+
{ type: "button", text: "urlscan.io", url: _urlscan_link }
|
35
35
|
end
|
36
36
|
|
37
37
|
def censys_link
|
38
38
|
return nil unless _censys_link
|
39
39
|
|
40
|
-
{type: "button", text: "Censys", url: _censys_link}
|
40
|
+
{ type: "button", text: "Censys", url: _censys_link }
|
41
41
|
end
|
42
42
|
|
43
43
|
def shodan_link
|
44
44
|
return nil unless _shodan_link
|
45
45
|
|
46
|
-
{type: "button", text: "Shodan", url: _shodan_link}
|
46
|
+
{ type: "button", text: "Shodan", url: _shodan_link }
|
47
47
|
end
|
48
48
|
|
49
49
|
# @return [Array]
|
@@ -17,7 +17,7 @@ module Mihari
|
|
17
17
|
api.alert.create(
|
18
18
|
title: title,
|
19
19
|
description: description,
|
20
|
-
artifacts: artifacts.map { |artifact| {data: artifact.data, data_type: artifact.data_type, message: description} },
|
20
|
+
artifacts: artifacts.map { |artifact| { data: artifact.data, data_type: artifact.data_type, message: description } },
|
21
21
|
tags: tags,
|
22
22
|
type: "external",
|
23
23
|
source: "mihari"
|
data/lib/mihari/models/alert.rb
CHANGED
@@ -44,16 +44,16 @@ module Mihari
|
|
44
44
|
relation = joins(:tags) if tag_name
|
45
45
|
relation = joins(:artifacts) if artifact_data
|
46
46
|
|
47
|
-
relation = relation.where(artifacts: {data: artifact_data}) if artifact_data
|
48
|
-
relation = relation.where(tags: {name: tag_name}) if tag_name
|
47
|
+
relation = relation.where(artifacts: { data: artifact_data }) if artifact_data
|
48
|
+
relation = relation.where(tags: { name: tag_name }) if tag_name
|
49
49
|
|
50
50
|
relation = relation.where(source: source) if source
|
51
51
|
relation = relation.where(title: title) if title
|
52
52
|
|
53
|
-
relation = relation.filter(description: {like: "%#{description}%"}) if description
|
53
|
+
relation = relation.filter(description: { like: "%#{description}%" }) if description
|
54
54
|
|
55
|
-
relation = relation.filter(created_at: {gte: from_at}) if from_at
|
56
|
-
relation = relation.filter(created_at: {lte: to_at}) if to_at
|
55
|
+
relation = relation.filter(created_at: { gte: from_at }) if from_at
|
56
|
+
relation = relation.filter(created_at: { lte: to_at }) if to_at
|
57
57
|
|
58
58
|
relation
|
59
59
|
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_record"
|
4
|
+
require "active_record/filter"
|
5
|
+
require "active_support/core_ext/integer/time"
|
6
|
+
require "active_support/core_ext/numeric/time"
|
4
7
|
|
5
8
|
class ArtifactValidator < ActiveModel::Validator
|
6
9
|
def validate(record)
|
@@ -20,8 +23,16 @@ module Mihari
|
|
20
23
|
self.data_type = TypeChecker.type(data)
|
21
24
|
end
|
22
25
|
|
23
|
-
def unique?
|
24
|
-
self.class.
|
26
|
+
def unique?(ignore_old_artifacts: false, ignore_threshold: 0)
|
27
|
+
artifact = self.class.where(data: data).order(created_at: :desc).first
|
28
|
+
return true if artifact.nil?
|
29
|
+
|
30
|
+
return false unless ignore_old_artifacts
|
31
|
+
|
32
|
+
days_before = (-ignore_threshold).days.from_now
|
33
|
+
# if an artifact is created before {ignore_threshold} days, ignore it
|
34
|
+
# within {ignore_threshold} days, do not ignore it
|
35
|
+
artifact.created_at < days_before
|
25
36
|
end
|
26
37
|
end
|
27
38
|
end
|
@@ -51,20 +51,20 @@ module Mihari
|
|
51
51
|
|
52
52
|
def to_fields(clean_message, backtrace)
|
53
53
|
fields = [
|
54
|
-
{title: "Exception", value: clean_message},
|
55
|
-
{title: "Hostname", value: hostname}
|
54
|
+
{ title: "Exception", value: clean_message },
|
55
|
+
{ title: "Hostname", value: hostname }
|
56
56
|
]
|
57
57
|
|
58
58
|
if backtrace
|
59
59
|
formatted_backtrace = format_backtrace(backtrace)
|
60
|
-
fields << {title: "Backtrace", value: formatted_backtrace}
|
60
|
+
fields << { title: "Backtrace", value: formatted_backtrace }
|
61
61
|
end
|
62
62
|
fields
|
63
63
|
end
|
64
64
|
|
65
65
|
def hostname
|
66
66
|
Socket.gethostname
|
67
|
-
rescue => _e
|
67
|
+
rescue StandardError => _e
|
68
68
|
"N/A"
|
69
69
|
end
|
70
70
|
|
data/lib/mihari/status.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module Mihari
|
4
4
|
class Status
|
5
5
|
def check
|
6
|
-
statuses
|
6
|
+
statuses
|
7
7
|
end
|
8
8
|
|
9
9
|
def self.check
|
@@ -12,14 +12,6 @@ module Mihari
|
|
12
12
|
|
13
13
|
private
|
14
14
|
|
15
|
-
def convert(is_configured:, values:, type:)
|
16
|
-
{
|
17
|
-
is_configured: is_configured,
|
18
|
-
values: values,
|
19
|
-
type: type
|
20
|
-
}
|
21
|
-
end
|
22
|
-
|
23
15
|
def statuses
|
24
16
|
(Mihari.analyzers + Mihari.emitters).map do |klass|
|
25
17
|
name = klass.to_s.split("::").last.to_s
|
@@ -36,7 +28,7 @@ module Mihari
|
|
36
28
|
values = instance.configuration_values
|
37
29
|
type = is_analyzer ? "Analyzer" : "Emitter"
|
38
30
|
|
39
|
-
values ? {is_configured: is_configured, values: values, type: type} : nil
|
31
|
+
values ? { is_configured: is_configured, values: values, type: type } : nil
|
40
32
|
rescue ArgumentError => _e
|
41
33
|
nil
|
42
34
|
end
|
data/lib/mihari/version.rb
CHANGED
data/lib/mihari/web/app.rb
CHANGED
@@ -1,119 +1,44 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "launchy"
|
3
4
|
require "rack"
|
5
|
+
require "rack/handler/puma"
|
4
6
|
require "sinatra"
|
5
|
-
|
6
|
-
require "
|
7
|
+
|
8
|
+
require "mihari/web/helpers/json"
|
9
|
+
|
10
|
+
require "mihari/web/controllers/base_controller"
|
11
|
+
|
12
|
+
require "mihari/web/controllers/alerts_controller"
|
13
|
+
require "mihari/web/controllers/artifacts_controller"
|
14
|
+
require "mihari/web/controllers/command_controller"
|
15
|
+
require "mihari/web/controllers/config_controller"
|
16
|
+
require "mihari/web/controllers/sources_controller"
|
17
|
+
require "mihari/web/controllers/tags_controller"
|
7
18
|
|
8
19
|
module Mihari
|
9
20
|
class App < Sinatra::Base
|
10
|
-
register Sinatra::Reloader
|
11
|
-
|
12
21
|
set :root, File.dirname(__FILE__)
|
13
|
-
set :public_folder,
|
22
|
+
set :public_folder, File.join(root, "public")
|
14
23
|
|
15
24
|
get "/" do
|
16
25
|
send_file File.join(settings.public_folder, "index.html")
|
17
26
|
end
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
description = params["description"]
|
26
|
-
source = params["source"]
|
27
|
-
tag_name = params["tag"]
|
28
|
-
title = params["title"]
|
29
|
-
|
30
|
-
from_at = params["from_at"] || params["fromAt"]
|
31
|
-
from_at = DateTime.parse(from_at) if from_at
|
32
|
-
to_at = params["to_at"] || params["toAt"]
|
33
|
-
to_at = DateTime.parse(to_at) if to_at
|
34
|
-
|
35
|
-
alerts = Mihari::Alert.search(
|
36
|
-
artifact_data: artifact_data,
|
37
|
-
description: description,
|
38
|
-
from_at: from_at,
|
39
|
-
limit: limit,
|
40
|
-
page: page,
|
41
|
-
source: source,
|
42
|
-
tag_name: tag_name,
|
43
|
-
title: title,
|
44
|
-
to_at: to_at
|
45
|
-
)
|
46
|
-
total = Mihari::Alert.count(
|
47
|
-
artifact_data: artifact_data,
|
48
|
-
description: description,
|
49
|
-
from_at: from_at,
|
50
|
-
source: source,
|
51
|
-
tag_name: tag_name,
|
52
|
-
title: title,
|
53
|
-
to_at: to_at
|
54
|
-
)
|
55
|
-
|
56
|
-
json = {alerts: alerts, total: total, current_page: page, page_size: limit}
|
57
|
-
json json.to_camelback_keys
|
58
|
-
end
|
59
|
-
|
60
|
-
delete "/api/alerts/:id" do
|
61
|
-
id = params["id"]
|
62
|
-
id = id.to_i
|
63
|
-
|
64
|
-
begin
|
65
|
-
alert = Mihari::Alert.find(id)
|
66
|
-
alert.destroy
|
67
|
-
|
68
|
-
status 204
|
69
|
-
body ""
|
70
|
-
rescue ActiveRecord::RecordNotFound
|
71
|
-
status 404
|
72
|
-
|
73
|
-
message = {message: "ID:#{id} is not found"}
|
74
|
-
json message
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
delete "/api/artifacts/:id" do
|
79
|
-
id = params["id"]
|
80
|
-
id = id.to_i
|
81
|
-
|
82
|
-
begin
|
83
|
-
alert = Mihari::Artifact.find(id)
|
84
|
-
alert.delete
|
85
|
-
|
86
|
-
status 204
|
87
|
-
body ""
|
88
|
-
rescue ActiveRecord::RecordNotFound
|
89
|
-
status 404
|
90
|
-
|
91
|
-
message = {message: "ID:#{id} is not found"}
|
92
|
-
json message
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
get "/api/sources" do
|
97
|
-
tags = Mihari::Alert.distinct.pluck(:source)
|
98
|
-
json tags
|
99
|
-
end
|
100
|
-
|
101
|
-
get "/api/tags" do
|
102
|
-
tags = Mihari::Tag.distinct.pluck(:name)
|
103
|
-
json tags
|
104
|
-
end
|
105
|
-
|
106
|
-
get "/api/config" do
|
107
|
-
report = Status.check
|
108
|
-
|
109
|
-
json report.to_camelback_keys
|
110
|
-
end
|
28
|
+
use Mihari::Controllers::AlertsController
|
29
|
+
use Mihari::Controllers::ArtifactsController
|
30
|
+
use Mihari::Controllers::CommandController
|
31
|
+
use Mihari::Controllers::ConfigController
|
32
|
+
use Mihari::Controllers::SourcesController
|
33
|
+
use Mihari::Controllers::TagsController
|
111
34
|
|
112
35
|
class << self
|
113
36
|
def run!(port: 9292, host: "localhost")
|
114
|
-
|
37
|
+
url = "http://#{host}:#{port}"
|
38
|
+
|
39
|
+
Rack::Handler::Puma.run self, Port: port, Host: host do |server|
|
40
|
+
Launchy.open url
|
115
41
|
|
116
|
-
Rack::Handler::WEBrick.run self, Port: port, Host: host do |server|
|
117
42
|
[:INT, :TERM].each do |sig|
|
118
43
|
trap(sig) do
|
119
44
|
server.shutdown
|