mihari 4.1.1 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +26 -4
  3. data/README.md +1 -1
  4. data/lib/mihari/analyzers/base.rb +18 -10
  5. data/lib/mihari/analyzers/rule.rb +50 -7
  6. data/lib/mihari/cli/base.rb +0 -4
  7. data/lib/mihari/commands/init.rb +1 -1
  8. data/lib/mihari/commands/search.rb +11 -58
  9. data/lib/mihari/commands/validator.rb +1 -2
  10. data/lib/mihari/constants.rb +2 -0
  11. data/lib/mihari/emitters/base.rb +8 -2
  12. data/lib/mihari/emitters/http.rb +127 -0
  13. data/lib/mihari/emitters/slack.rb +40 -4
  14. data/lib/mihari/emitters/webhook.rb +7 -16
  15. data/lib/mihari/enrichers/base.rb +5 -2
  16. data/lib/mihari/enrichers/ipinfo.rb +4 -3
  17. data/lib/mihari/{web/entities → entities}/alert.rb +0 -0
  18. data/lib/mihari/{web/entities → entities}/artifact.rb +0 -0
  19. data/lib/mihari/{web/entities → entities}/autonomous_system.rb +0 -0
  20. data/lib/mihari/{web/entities → entities}/command.rb +0 -0
  21. data/lib/mihari/{web/entities → entities}/config.rb +0 -0
  22. data/lib/mihari/{web/entities → entities}/dns.rb +0 -0
  23. data/lib/mihari/{web/entities → entities}/geolocation.rb +0 -0
  24. data/lib/mihari/{web/entities → entities}/ip_address.rb +0 -0
  25. data/lib/mihari/{web/entities → entities}/message.rb +0 -0
  26. data/lib/mihari/{web/entities → entities}/reverse_dns.rb +0 -0
  27. data/lib/mihari/{web/entities → entities}/rule.rb +5 -0
  28. data/lib/mihari/{web/entities → entities}/source.rb +0 -0
  29. data/lib/mihari/{web/entities → entities}/tag.rb +0 -0
  30. data/lib/mihari/{web/entities → entities}/whois.rb +0 -0
  31. data/lib/mihari/errors.rb +2 -0
  32. data/lib/mihari/feed/reader.rb +16 -58
  33. data/lib/mihari/http.rb +99 -0
  34. data/lib/mihari/mixins/error_notification.rb +20 -0
  35. data/lib/mihari/mixins/retriable.rb +12 -2
  36. data/lib/mihari/mixins/rule.rb +1 -2
  37. data/lib/mihari/schemas/rule.rb +30 -4
  38. data/lib/mihari/structs/ipinfo.rb +2 -3
  39. data/lib/mihari/structs/rule.rb +31 -0
  40. data/lib/mihari/structs/shodan.rb +9 -1
  41. data/lib/mihari/types.rb +11 -3
  42. data/lib/mihari/version.rb +1 -1
  43. data/lib/mihari/web/api.rb +0 -20
  44. data/lib/mihari/web/app.rb +2 -2
  45. data/lib/mihari/web/endpoints/rules.rb +3 -1
  46. data/lib/mihari/web/middleware/error_notification_adapter.rb +19 -0
  47. data/lib/mihari/web/public/index.html +1 -1
  48. data/lib/mihari/web/public/redoc-static.html +1888 -166
  49. data/lib/mihari/web/public/static/css/app.0de4b715.css +1 -0
  50. data/lib/mihari/web/public/static/css/app.43138058.css +1 -0
  51. data/lib/mihari/web/public/static/css/chunk-vendors.3ed9b08e.css +7 -0
  52. data/lib/mihari/web/public/static/css/chunk-vendors.c57bb3fd.css +7 -0
  53. data/lib/mihari/web/public/static/fonts/fa-brands-400.1fd0b4d7.ttf +0 -0
  54. data/lib/mihari/web/public/static/fonts/fa-brands-400.5d5236fb.woff2 +0 -0
  55. data/lib/mihari/web/public/static/fonts/fa-brands-400.edf40f86.woff2 +0 -0
  56. data/lib/mihari/web/public/static/fonts/fa-brands-400.f7223235.ttf +0 -0
  57. data/lib/mihari/web/public/static/fonts/fa-regular-400.3665ebc7.woff2 +0 -0
  58. data/lib/mihari/web/public/static/fonts/fa-regular-400.64b3730e.woff2 +0 -0
  59. data/lib/mihari/web/public/static/fonts/fa-regular-400.95a8a8af.ttf +0 -0
  60. data/lib/mihari/web/public/static/fonts/fa-regular-400.a7fde52b.ttf +0 -0
  61. data/lib/mihari/web/public/static/fonts/fa-solid-900.0d2abd43.woff2 +0 -0
  62. data/lib/mihari/web/public/static/fonts/fa-solid-900.5b03221c.ttf +0 -0
  63. data/lib/mihari/web/public/static/fonts/fa-solid-900.6115ad71.woff2 +0 -0
  64. data/lib/mihari/web/public/static/fonts/fa-solid-900.f0203cfc.ttf +0 -0
  65. data/lib/mihari/web/public/static/fonts/fa-v4compatibility.42932bea.ttf +0 -0
  66. data/lib/mihari/web/public/static/fonts/fa-v4compatibility.e1023515.ttf +0 -0
  67. data/lib/mihari/web/public/static/js/app-legacy.46b666f0.js +2 -0
  68. data/lib/mihari/web/public/static/js/app-legacy.46b666f0.js.map +1 -0
  69. data/lib/mihari/web/public/static/js/app-legacy.e451304b.js +2 -0
  70. data/lib/mihari/web/public/static/js/app-legacy.e451304b.js.map +1 -0
  71. data/lib/mihari/web/public/static/js/app.4818aedd.js +2 -0
  72. data/lib/mihari/web/public/static/js/app.4818aedd.js.map +1 -0
  73. data/lib/mihari/web/public/static/js/app.e74e91d7.js +2 -0
  74. data/lib/mihari/web/public/static/js/app.e74e91d7.js.map +1 -0
  75. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.41357cdf.js +25 -0
  76. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.41357cdf.js.map +1 -0
  77. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.c99e452e.js +17 -0
  78. data/lib/mihari/web/public/static/js/chunk-vendors-legacy.c99e452e.js.map +1 -0
  79. data/lib/mihari/web/public/static/js/chunk-vendors.15e84e22.js +23 -0
  80. data/lib/mihari/web/public/static/js/chunk-vendors.15e84e22.js.map +1 -0
  81. data/lib/mihari/web/public/static/js/chunk-vendors.c5525f1e.js +31 -0
  82. data/lib/mihari/web/public/static/js/chunk-vendors.c5525f1e.js.map +1 -0
  83. data/lib/mihari.rb +71 -21
  84. data/mihari.gemspec +16 -11
  85. data/sig/lib/mihari/constants.rbs +2 -0
  86. data/sig/lib/mihari/emitters/http.rbs +35 -0
  87. data/sig/lib/mihari/emitters/slack.rbs +29 -1
  88. data/sig/lib/mihari/feed/reader.rbs +2 -2
  89. data/sig/lib/mihari/http.rbs +64 -0
  90. data/sig/lib/mihari/mixins/error_notification.rbs +12 -0
  91. data/sig/lib/mihari/structs/rule.rbs +4 -0
  92. data/sig/lib/mihari/types.rbs +2 -0
  93. data/sig/lib/mihari.rbs +4 -8
  94. metadata +137 -62
  95. data/lib/mihari/cli/mixins/utils.rb +0 -72
  96. data/lib/mihari/emitters/stdout.rb +0 -22
  97. data/lib/mihari/notifiers/base.rb +0 -24
  98. data/lib/mihari/notifiers/exception_notifier.rb +0 -126
  99. data/lib/mihari/notifiers/slack.rb +0 -63
  100. data/sig/lib/mihari/cli/mixins/utils.rbs +0 -50
  101. data/sig/lib/mihari/notifiers/base.rbs +0 -18
  102. data/sig/lib/mihari/notifiers/exception_notifier.rbs +0 -75
  103. data/sig/lib/mihari/notifiers/slack.rbs +0 -50
@@ -1,126 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Mihari
4
- module Notifiers
5
- class ExceptionNotifier
6
- def initialize
7
- @backtrace_lines = 10
8
- @color = "danger"
9
-
10
- @slack = Notifiers::Slack.new
11
- end
12
-
13
- def valid?
14
- @slack.valid?
15
- end
16
-
17
- def notify(exception)
18
- notify_to_stdout exception
19
-
20
- clean_message = exception.message.tr("`", "'")
21
- attachments = to_attachments(exception, clean_message)
22
- notify_to_slack(text: clean_message, attachments: attachments) if @slack.valid?
23
- end
24
-
25
- #
26
- # Send notification to Slack
27
- #
28
- # @param [String] text
29
- # @param [Array<Hash>] attachments
30
- #
31
- # @return [nil]
32
- #
33
- def notify_to_slack(text:, attachments:)
34
- @slack.notify(text: text, attachments: attachments)
35
- end
36
-
37
- #
38
- # Send notification to STDOUT
39
- #
40
- # @param [Exception] exception
41
- #
42
- # @return [nil]
43
- #
44
- def notify_to_stdout(exception)
45
- text = to_text(exception.class).chomp
46
- message = "#{text}: #{exception.message}"
47
- puts message
48
- puts format_backtrace(exception.backtrace) if exception.backtrace
49
- end
50
-
51
- #
52
- # Convert exception to attachments (for Slack)
53
- #
54
- # @param [Exception] exception
55
- # @param [String] clean_message
56
- #
57
- # @return [Array<Hash>]
58
- #
59
- def to_attachments(exception, clean_message)
60
- text = to_text(exception.class)
61
- backtrace = exception.backtrace
62
- fields = to_fields(clean_message, backtrace)
63
-
64
- [color: @color, text: text, fields: fields, mrkdwn_in: %w[text fields]]
65
- end
66
-
67
- #
68
- # Convert exception class to text
69
- #
70
- # @param [Class<Exception>] exception_class
71
- #
72
- # @return [String]
73
- #
74
- def to_text(exception_class)
75
- measure_word = /^[aeiou]/i.match?(exception_class.to_s) ? "An" : "A"
76
- exception_name = "*#{measure_word}* `#{exception_class}`"
77
- "#{exception_name} *occured in background*\n"
78
- end
79
-
80
- #
81
- # Convert clean_message and backtrace into fields (for Slack)
82
- #
83
- # @param [String] clean_message
84
- # @param [Array] backtrace
85
- #
86
- # @return [Array<Hash>]
87
- #
88
- def to_fields(clean_message, backtrace)
89
- fields = [
90
- { title: "Exception", value: clean_message },
91
- { title: "Hostname", value: hostname }
92
- ]
93
-
94
- if backtrace
95
- formatted_backtrace = format_backtrace(backtrace)
96
- fields << { title: "Backtrace", value: formatted_backtrace }
97
- end
98
- fields
99
- end
100
-
101
- #
102
- # Hostname of runnning instance
103
- #
104
- # @return [String]
105
- #
106
- def hostname
107
- Socket.gethostname
108
- rescue StandardError => _e
109
- "N/A"
110
- end
111
-
112
- #
113
- # Format backtrace in string
114
- #
115
- # @param [Array] backtrace
116
- #
117
- # @return [String]
118
- #
119
- def format_backtrace(backtrace)
120
- return nil unless backtrace
121
-
122
- "```#{backtrace.first(@backtrace_lines).join("\n")}```"
123
- end
124
- end
125
- end
126
- end
@@ -1,63 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "slack-notifier"
4
-
5
- module Mihari
6
- module Notifiers
7
- class Slack < Base
8
- SLACK_WEBHOOK_URL_KEY = "SLACK_WEBHOOK_URL"
9
- SLACK_CHANNEL_KEY = "SLACK_CHANNEL"
10
- DEFAULT_USERNAME = "mihari"
11
-
12
- #
13
- # Slack channel to post
14
- #
15
- # @return [String]
16
- #
17
- def slack_channel
18
- Mihari.config.slack_channel || "#general"
19
- end
20
-
21
- #
22
- # Slack webhook URL
23
- #
24
- # @return [String]
25
- #
26
- def slack_webhook_url
27
- Mihari.config.slack_webhook_url
28
- end
29
-
30
- #
31
- # Check Slack webhook URL is set
32
- #
33
- # @return [Boolean]
34
- #
35
- def slack_webhook_url?
36
- !Mihari.config.slack_webhook_url.nil?
37
- end
38
-
39
- #
40
- # Check Slack webhook URL is set. Alias of #slack_webhook_url?.
41
- #
42
- # @return [Boolean]
43
- #
44
- def valid?
45
- slack_webhook_url?
46
- end
47
-
48
- #
49
- # Send notification to Slack
50
- #
51
- # @param [String] text
52
- # @param [Array<Hash>] attachments
53
- # @param [Boolean] mrkdwn
54
- #
55
- # @return [nil]
56
- #
57
- def notify(text:, attachments: [], mrkdwn: true)
58
- notifier = ::Slack::Notifier.new(slack_webhook_url, channel: slack_channel, username: DEFAULT_USERNAME)
59
- notifier.post(text: text, attachments: attachments, mrkdwn: mrkdwn)
60
- end
61
- end
62
- end
63
- end
@@ -1,50 +0,0 @@
1
- module Mihari
2
- module CLI
3
- module Mixins
4
- module Utils
5
- #
6
- # Send an exception notification if there is any error in a block
7
- #
8
- # @return [Nil]
9
- #
10
- def with_error_handling: () { () -> untyped } -> void
11
-
12
- #
13
- # Check required keys in JSON
14
- #
15
- # @param [Hash] json
16
- #
17
- # @return [Boolean]
18
- #
19
- def required_alert_keys?: (Hash[(String | Symbol), untyped] json) -> bool
20
-
21
- #
22
- # Load configuration and establish DB connection
23
- #
24
- # @return [Hash]
25
- #
26
- def load_configuration: () -> Hash[(String | Symbol), untyped]
27
-
28
- #
29
- # Run analyzer
30
- #
31
- # @param [Class<Mihari::Analyzers::Base>] analyzer_class
32
- # @param [String] query
33
- # @param [Hash] options
34
- #
35
- # @return [nil]
36
- #
37
- def run_analyzer: (untyped analyzer_class, query: String query, options: untyped options) -> void
38
-
39
- #
40
- # Normalize options (reject keys not for analyzers)
41
- #
42
- # @param [Hash] options
43
- #
44
- # @return [Hash]
45
- #
46
- def normalize_options: (Hash[(String | Symbol), untyped] options) -> Hash[(String | Symbol), untyped]
47
- end
48
- end
49
- end
50
- end
@@ -1,18 +0,0 @@
1
- module Mihari
2
- module Notifiers
3
- class Base
4
- # Validate notifier availability
5
- #
6
- # @return [Boolean]
7
- #
8
- def valid?: () -> bool
9
-
10
- #
11
- # Send a notification
12
- #
13
- # @return [nil]
14
- #
15
- def notify: () -> void
16
- end
17
- end
18
- end
@@ -1,75 +0,0 @@
1
- module Mihari
2
- module Notifiers
3
- class ExceptionNotifier
4
- def initialize: () -> void
5
-
6
- def valid?: () -> bool
7
-
8
- def notify: (Exception exception) -> void
9
-
10
- #
11
- # Send notification to Slack
12
- #
13
- # @param [String] text
14
- # @param [Array<Hash>] attachments
15
- #
16
- # @return [nil]
17
- #
18
- def notify_to_slack: (text: String text, attachments: Array[Hash[(String | Symbol), untyped]] attachments) -> void
19
-
20
- #
21
- # Send notification to STDOUT
22
- #
23
- # @param [Exception] exception
24
- #
25
- # @return [nil]
26
- #
27
- def notify_to_stdout: (Exception exception) -> void
28
-
29
- #
30
- # Convert exception to attachments (for Slack)
31
- #
32
- # @param [Exception] exception
33
- # @param [String] clean_message
34
- #
35
- # @return [Array<Hash>]
36
- #
37
- def to_attachments: (Exception exception, String clean_message) -> ::Array[{ color: untyped, text: untyped, fields: untyped, :mrkdwn_in => ::Array["text" | "fields"] }]
38
-
39
- #
40
- # Convert exception class to text
41
- #
42
- # @param [Class<Exception>] exception_class
43
- #
44
- # @return [String]
45
- #
46
- def to_text: (singleton(Exception) exception_class) -> ::String
47
-
48
- #
49
- # Convert clean_message and backtrace into fields (for Slack)
50
- #
51
- # @param [String] clean_message
52
- # @param [Array] backtrace
53
- #
54
- # @return [Array<Hash>]
55
- #
56
- def to_fields: (String clean_message, untyped backtrace) -> Array[Hash[(String | Symbol), untyped]]
57
-
58
- #
59
- # Hostname of runnning instance
60
- #
61
- # @return [String]
62
- #
63
- def hostname: () -> String
64
-
65
- #
66
- # Format backtrace in string
67
- #
68
- # @param [Array] backtrace
69
- #
70
- # @return [String]
71
- #
72
- def format_backtrace: (untyped backtrace) -> (nil | ::String)
73
- end
74
- end
75
- end
@@ -1,50 +0,0 @@
1
- module Mihari
2
- module Notifiers
3
- class Slack < Base
4
- SLACK_WEBHOOK_URL_KEY: ::String
5
-
6
- SLACK_CHANNEL_KEY: ::String
7
-
8
- DEFAULT_USERNAME: ::String
9
-
10
- #
11
- # Slack channel to post
12
- #
13
- # @return [String]
14
- #
15
- def slack_channel: () -> String
16
-
17
- #
18
- # Slack webhook URL
19
- #
20
- # @return [String]
21
- #
22
- def slack_webhook_url: () -> String
23
-
24
- #
25
- # Check Slack webhook URL is set
26
- #
27
- # @return [Boolean]
28
- #
29
- def slack_webhook_url?: () -> bool
30
-
31
- #
32
- # Check Slack webhook URL is set. Alias of #slack_webhook_url?.
33
- #
34
- # @return [Boolean]
35
- #
36
- def valid?: () -> bool
37
-
38
- #
39
- # Send notification to Slack
40
- #
41
- # @param [String] text
42
- # @param [Array<Hash>] attachments
43
- # @param [Boolean] mrkdwn
44
- #
45
- # @return [nil]
46
- #
47
- def notify: (text: String text, ?attachments: Array[Hash[(String | Symbol), untyped]] attachments, ?mrkdwn: bool mrkdwn) -> untyped
48
- end
49
- end
50
- end