mihari 5.6.1 → 5.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (153) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -1
  3. data/README.md +1 -0
  4. data/config.ru +1 -1
  5. data/docs/analyzers/fofa.md +31 -0
  6. data/docs/analyzers/index.md +1 -0
  7. data/frontend/package-lock.json +183 -186
  8. data/frontend/package.json +10 -10
  9. data/frontend/src/components/alert/Form.vue +1 -14
  10. data/frontend/src/components/artifact/AS.vue +2 -8
  11. data/frontend/src/components/artifact/DnsRecords.vue +2 -8
  12. data/frontend/src/components/artifact/ReverseDnsNames.vue +2 -10
  13. data/frontend/src/components/artifact/WhoisRecord.vue +1 -1
  14. data/lib/mihari/{base.rb → actor.rb} +27 -3
  15. data/lib/mihari/analyzers/base.rb +16 -20
  16. data/lib/mihari/analyzers/binaryedge.rb +4 -1
  17. data/lib/mihari/analyzers/censys.rb +5 -3
  18. data/lib/mihari/analyzers/circl.rb +4 -1
  19. data/lib/mihari/analyzers/crtsh.rb +4 -1
  20. data/lib/mihari/analyzers/dnstwister.rb +4 -1
  21. data/lib/mihari/analyzers/feed.rb +3 -0
  22. data/lib/mihari/analyzers/fofa.rb +65 -0
  23. data/lib/mihari/analyzers/greynoise.rb +4 -1
  24. data/lib/mihari/analyzers/hunterhow.rb +7 -2
  25. data/lib/mihari/analyzers/onyphe.rb +4 -1
  26. data/lib/mihari/analyzers/otx.rb +4 -1
  27. data/lib/mihari/analyzers/passivetotal.rb +5 -2
  28. data/lib/mihari/analyzers/pulsedive.rb +4 -1
  29. data/lib/mihari/analyzers/securitytrails.rb +5 -2
  30. data/lib/mihari/analyzers/shodan.rb +4 -1
  31. data/lib/mihari/analyzers/urlscan.rb +5 -2
  32. data/lib/mihari/analyzers/virustotal.rb +9 -6
  33. data/lib/mihari/analyzers/virustotal_intelligence.rb +4 -1
  34. data/lib/mihari/analyzers/zoomeye.rb +8 -5
  35. data/lib/mihari/cli/alert.rb +3 -0
  36. data/lib/mihari/cli/base.rb +3 -0
  37. data/lib/mihari/cli/database.rb +3 -0
  38. data/lib/mihari/cli/main.rb +3 -0
  39. data/lib/mihari/cli/rule.rb +3 -0
  40. data/lib/mihari/clients/base.rb +3 -0
  41. data/lib/mihari/clients/binaryedge.rb +5 -2
  42. data/lib/mihari/clients/censys.rb +7 -4
  43. data/lib/mihari/clients/circl.rb +3 -0
  44. data/lib/mihari/clients/crtsh.rb +5 -2
  45. data/lib/mihari/clients/dnstwister.rb +3 -0
  46. data/lib/mihari/clients/fofa.rb +83 -0
  47. data/lib/mihari/clients/greynoise.rb +5 -2
  48. data/lib/mihari/clients/hunterhow.rb +5 -2
  49. data/lib/mihari/clients/misp.rb +3 -0
  50. data/lib/mihari/clients/onyphe.rb +5 -2
  51. data/lib/mihari/clients/otx.rb +3 -0
  52. data/lib/mihari/clients/passivetotal.rb +7 -4
  53. data/lib/mihari/clients/publsedive.rb +4 -1
  54. data/lib/mihari/clients/securitytrails.rb +6 -3
  55. data/lib/mihari/clients/shodan.rb +5 -2
  56. data/lib/mihari/clients/the_hive.rb +3 -0
  57. data/lib/mihari/clients/urlscan.rb +7 -4
  58. data/lib/mihari/clients/virustotal.rb +5 -2
  59. data/lib/mihari/clients/zoomeye.rb +3 -0
  60. data/lib/mihari/commands/alert.rb +5 -14
  61. data/lib/mihari/commands/database.rb +3 -0
  62. data/lib/mihari/commands/rule.rb +11 -11
  63. data/lib/mihari/commands/search.rb +9 -6
  64. data/lib/mihari/commands/version.rb +3 -0
  65. data/lib/mihari/commands/web.rb +4 -1
  66. data/lib/mihari/config.rb +139 -150
  67. data/lib/mihari/constants.rb +1 -1
  68. data/lib/mihari/database.rb +6 -0
  69. data/lib/mihari/emitters/base.rb +16 -25
  70. data/lib/mihari/emitters/database.rb +10 -9
  71. data/lib/mihari/emitters/misp.rb +20 -41
  72. data/lib/mihari/emitters/slack.rb +16 -13
  73. data/lib/mihari/emitters/the_hive.rb +18 -46
  74. data/lib/mihari/emitters/webhook.rb +34 -23
  75. data/lib/mihari/enrichers/base.rb +16 -15
  76. data/lib/mihari/enrichers/google_public_dns.rb +6 -5
  77. data/lib/mihari/enrichers/ipinfo.rb +10 -8
  78. data/lib/mihari/enrichers/shodan.rb +4 -6
  79. data/lib/mihari/enrichers/whois.rb +13 -10
  80. data/lib/mihari/errors.rb +6 -0
  81. data/lib/mihari/feed/parser.rb +3 -0
  82. data/lib/mihari/feed/reader.rb +3 -0
  83. data/lib/mihari/http.rb +6 -0
  84. data/lib/mihari/mixins/autonomous_system.rb +3 -0
  85. data/lib/mihari/mixins/configurable.rb +3 -0
  86. data/lib/mihari/mixins/error_notification.rb +3 -0
  87. data/lib/mihari/mixins/falsepositive.rb +3 -0
  88. data/lib/mihari/mixins/refang.rb +3 -0
  89. data/lib/mihari/mixins/retriable.rb +6 -2
  90. data/lib/mihari/models/alert.rb +78 -73
  91. data/lib/mihari/models/artifact.rb +186 -178
  92. data/lib/mihari/models/autonomous_system.rb +25 -20
  93. data/lib/mihari/models/cpe.rb +24 -19
  94. data/lib/mihari/models/dns.rb +27 -22
  95. data/lib/mihari/models/geolocation.rb +25 -20
  96. data/lib/mihari/models/port.rb +24 -19
  97. data/lib/mihari/models/reverse_dns.rb +24 -19
  98. data/lib/mihari/models/rule.rb +71 -66
  99. data/lib/mihari/models/tag.rb +8 -3
  100. data/lib/mihari/models/tagging.rb +8 -3
  101. data/lib/mihari/models/whois.rb +20 -17
  102. data/lib/mihari/rule.rb +357 -0
  103. data/lib/mihari/schemas/alert.rb +3 -0
  104. data/lib/mihari/schemas/analyzer.rb +105 -87
  105. data/lib/mihari/schemas/emitter.rb +12 -5
  106. data/lib/mihari/schemas/enricher.rb +11 -4
  107. data/lib/mihari/schemas/macros.rb +4 -0
  108. data/lib/mihari/schemas/mixins.rb +20 -0
  109. data/lib/mihari/schemas/rule.rb +6 -10
  110. data/lib/mihari/service.rb +16 -0
  111. data/lib/mihari/services/alert_builder.rb +8 -5
  112. data/lib/mihari/services/alert_proxy.rb +16 -7
  113. data/lib/mihari/services/alert_runner.rb +10 -14
  114. data/lib/mihari/services/rule_builder.rb +10 -7
  115. data/lib/mihari/services/rule_runner.rb +11 -13
  116. data/lib/mihari/structs/binaryedge.rb +14 -29
  117. data/lib/mihari/structs/censys.rb +54 -133
  118. data/lib/mihari/structs/config.rb +20 -31
  119. data/lib/mihari/structs/filters.rb +38 -0
  120. data/lib/mihari/structs/fofa.rb +44 -0
  121. data/lib/mihari/structs/google_public_dns.rb +10 -28
  122. data/lib/mihari/structs/greynoise.rb +38 -89
  123. data/lib/mihari/structs/hunterhow.rb +27 -25
  124. data/lib/mihari/structs/ipinfo.rb +14 -35
  125. data/lib/mihari/structs/onyphe.rb +36 -81
  126. data/lib/mihari/structs/shodan.rb +53 -118
  127. data/lib/mihari/structs/urlscan.rb +27 -66
  128. data/lib/mihari/structs/virustotal_intelligence.rb +23 -59
  129. data/lib/mihari/type_checker.rb +4 -0
  130. data/lib/mihari/types.rb +3 -0
  131. data/lib/mihari/version.rb +1 -1
  132. data/lib/mihari/web/api.rb +15 -10
  133. data/lib/mihari/web/app.rb +59 -54
  134. data/lib/mihari/web/endpoints/alerts.rb +94 -89
  135. data/lib/mihari/web/endpoints/artifacts.rb +115 -110
  136. data/lib/mihari/web/endpoints/configs.rb +18 -13
  137. data/lib/mihari/web/endpoints/ip_addresses.rb +21 -16
  138. data/lib/mihari/web/endpoints/rules.rb +202 -204
  139. data/lib/mihari/web/endpoints/tags.rb +41 -36
  140. data/lib/mihari/web/middleware/connection_adapter.rb +16 -9
  141. data/lib/mihari/web/middleware/error_notification_adapter.rb +17 -10
  142. data/lib/mihari/web/public/assets/{index-9cc489e6.js → index-821134e2.js} +54 -54
  143. data/lib/mihari/web/public/assets/mode-yaml-24faa242.js +8 -0
  144. data/lib/mihari/web/public/index.html +1 -1
  145. data/lib/mihari.rb +30 -13
  146. data/mihari.gemspec +9 -3
  147. data/mkdocs.yml +3 -2
  148. data/requirements.txt +1 -1
  149. metadata +44 -26
  150. data/lib/mihari/analyzers/rule.rb +0 -232
  151. data/lib/mihari/services/rule_proxy.rb +0 -182
  152. data/lib/mihari/templates/rule.yml.erb +0 -5
  153. data/lib/mihari/web/public/assets/mode-yaml-a21faa53.js +0 -8
@@ -1,24 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- module Endpoints
5
- class IPAddresses < Grape::API
6
- namespace :ip_addresses do
7
- desc "Get an IP address", {
8
- success: Entities::IPAddress,
9
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
10
- summary: "Get an IP address"
11
- }
12
- params do
13
- requires :ip, type: String, regexp: /\A[0-9.]+\z/
14
- end
15
- get "/:ip", requirements: { ip: %r{[^/]+} } do
16
- ip = params[:ip].to_s
4
+ module Web
5
+ module Endpoints
6
+ #
7
+ # IP address API endpoint
8
+ #
9
+ class IPAddresses < Grape::API
10
+ namespace :ip_addresses do
11
+ desc "Get an IP address", {
12
+ success: Entities::IPAddress,
13
+ failure: [{ code: 404, message: "Not found", model: Entities::Message }],
14
+ summary: "Get an IP address"
15
+ }
16
+ params do
17
+ requires :ip, type: String, regexp: /\A[0-9.]+\z/
18
+ end
19
+ get "/:ip", requirements: { ip: %r{[^/]+} } do
20
+ ip = params[:ip].to_s
17
21
 
18
- data = Enrichers::IPInfo.new.query(ip)
19
- error!({ message: "IP:#{ip} is not found" }, 404) if data.nil?
22
+ data = Enrichers::IPInfo.new.call(ip)
23
+ error!({ message: "IP:#{ip} is not found" }, 404) if data.nil?
20
24
 
21
- present data, with: Entities::IPAddress
25
+ present data, with: Entities::IPAddress
26
+ end
22
27
  end
23
28
  end
24
29
  end
@@ -1,232 +1,230 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- module Endpoints
5
- class Rules < Grape::API
6
- namespace :rules do
7
- desc "Get Rule IDs", {
8
- is_array: true,
9
- success: Entities::RuleIDs,
10
- summary: "Get rule IDs"
11
- }
12
- get "/ids" do
13
- rule_ids = Mihari::Rule.distinct.pluck(:id)
14
- present({ rule_ids: rule_ids }, with: Entities::RuleIDs)
15
- end
16
-
17
- desc "Search rules", {
18
- is_array: true,
19
- success: Entities::RulesWithPagination,
20
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
21
- summary: "Search rules"
22
- }
23
- params do
24
- optional :page, type: Integer, default: 1
25
- optional :limit, type: Integer, default: 10
26
-
27
- optional :title, type: String
28
- optional :description, type: String
29
- optional :tag, type: String
30
-
31
- optional :fromAt, type: DateTime
32
- optional :toAt, type: DateTime
33
- end
34
- get "/" do
35
- filter = params.to_h.to_snake_keys
36
-
37
- # normalize keys
38
- filter["tag_name"] = filter["tag"]
39
- # symbolize hash keys
40
- filter = filter.to_h.symbolize_keys
41
-
42
- search_filter_with_pagenation = Structs::Filters::Rule::SearchFilterWithPagination.new(**filter)
43
- rules = Mihari::Rule.search(search_filter_with_pagenation)
44
- total = Mihari::Rule.count(search_filter_with_pagenation.without_pagination)
45
-
46
- present(
47
- { rules: rules,
48
- total: total,
49
- current_page: filter[:page].to_i,
50
- page_size: filter[:limit].to_i },
51
- with: Entities::RulesWithPagination
52
- )
53
- end
54
-
55
- desc "Get a rule", {
56
- success: Entities::Rule,
57
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
58
- summary: "Get a rule"
59
- }
60
- params do
61
- requires :id, type: String
62
- end
63
- get "/:id" do
64
- extend Dry::Monads[:result, :try]
65
-
66
- id = params["id"].to_s
67
-
68
- result = Try do
69
- Mihari::Rule.find(id)
70
- end.to_result
4
+ module Web
5
+ module Endpoints
6
+ #
7
+ # Rule API endpoint
8
+ #
9
+ class Rules < Grape::API
10
+ namespace :rules do
11
+ desc "Get Rule IDs", {
12
+ is_array: true,
13
+ success: Entities::RuleIDs,
14
+ summary: "Get rule IDs"
15
+ }
16
+ get "/ids" do
17
+ rule_ids = Mihari::Models::Rule.distinct.pluck(:id)
18
+ present({ rule_ids: rule_ids }, with: Entities::RuleIDs)
19
+ end
71
20
 
72
- return present(result.value!, with: Entities::Rule) if result.success?
21
+ desc "Search rules", {
22
+ is_array: true,
23
+ success: Entities::RulesWithPagination,
24
+ failure: [{ code: 404, message: "Not found", model: Entities::Message }],
25
+ summary: "Search rules"
26
+ }
27
+ params do
28
+ optional :page, type: Integer, default: 1
29
+ optional :limit, type: Integer, default: 10
30
+
31
+ optional :title, type: String
32
+ optional :description, type: String
33
+ optional :tag, type: String
34
+
35
+ optional :fromAt, type: DateTime
36
+ optional :toAt, type: DateTime
37
+ end
38
+ get "/" do
39
+ filter = params.to_h.to_snake_keys
40
+
41
+ # normalize keys
42
+ filter["tag_name"] = filter["tag"]
43
+ # symbolize hash keys
44
+ filter = filter.to_h.symbolize_keys
45
+
46
+ search_filter_with_pagenation = Structs::Filters::Rule::SearchFilterWithPagination.new(**filter)
47
+ rules = Mihari::Models::Rule.search(search_filter_with_pagenation)
48
+ total = Mihari::Models::Rule.count(search_filter_with_pagenation.without_pagination)
49
+
50
+ present(
51
+ { rules: rules,
52
+ total: total,
53
+ current_page: filter[:page].to_i,
54
+ page_size: filter[:limit].to_i },
55
+ with: Entities::RulesWithPagination
56
+ )
57
+ end
73
58
 
74
- failure = result.failure
75
- case failure
76
- when ActiveRecord::RecordNotFound
77
- error!({ message: "ID:#{id} is not found" }, 404)
78
- else
79
- raise failure
59
+ desc "Get a rule", {
60
+ success: Entities::Rule,
61
+ failure: [{ code: 404, message: "Not found", model: Entities::Message }],
62
+ summary: "Get a rule"
63
+ }
64
+ params do
65
+ requires :id, type: String
80
66
  end
81
- end
67
+ get "/:id" do
68
+ extend Dry::Monads[:result, :try]
82
69
 
83
- desc "Run a rule", {
84
- success: Entities::Message,
85
- summary: "Run a rule"
86
- }
87
- params do
88
- requires :id, type: String
89
- end
90
- get "/:id/run" do
91
- extend Dry::Monads[:result, :try]
70
+ id = params["id"].to_s
92
71
 
93
- id = params["id"].to_s
72
+ result = Try do
73
+ Mihari::Models::Rule.find(id)
74
+ end.to_result
94
75
 
95
- result = Try do
96
- Mihari::Services::RuleProxy.from_model(Mihari::Rule.find(id))
97
- end.to_result
76
+ return present(result.value!, with: Entities::Rule) if result.success?
98
77
 
99
- if result.success?
100
- result.value!.analyzer.run
101
- status 201
102
- return present({ message: "ID:#{id} is ran successfully" }, with: Entities::Message)
78
+ failure = result.failure
79
+ case failure
80
+ when ActiveRecord::RecordNotFound
81
+ error!({ message: "ID:#{id} is not found" }, 404)
82
+ else
83
+ raise failure
84
+ end
103
85
  end
104
86
 
105
- failure = result.failure
106
- case failure
107
- when ActiveRecord::RecordNotFound
108
- error!({ message: "ID:#{id} is not found" }, 404)
109
- else
110
- raise failure
87
+ desc "Run a rule", {
88
+ success: Entities::Message,
89
+ summary: "Run a rule"
90
+ }
91
+ params do
92
+ requires :id, type: String
111
93
  end
112
- end
113
-
114
- desc "Create a rule", {
115
- success: Entities::Rule,
116
- summary: "Create a rule"
117
- }
118
- params do
119
- requires :yaml, type: String, documentation: { param_type: "body" }
120
- end
121
- post "/" do
122
- extend Dry::Monads[:result, :try]
123
-
124
- yaml = params[:yaml]
125
- result = Try do
126
- Services::RuleProxy.from_yaml(yaml)
127
- end.to_result.bind do |rule|
128
- Try do
129
- found = Mihari::Rule.find_by_id(rule.id)
130
- error!({ message: "ID:#{rule.id} is already registered" }, 400) unless found.nil?
131
- rule
132
- end.to_result
133
- end.bind do |rule|
134
- Try do
135
- rule.model.save
136
- rule
137
- end.to_result
94
+ get "/:id/run" do
95
+ extend Dry::Monads[:result, :try]
96
+
97
+ id = params["id"].to_s
98
+
99
+ result = Try { Rule.from_model(Mihari::Models::Rule.find(id)) }.to_result
100
+ if result.success?
101
+ result.value!.analyzer.run
102
+ status 201
103
+ return present({ message: "ID:#{id} is ran successfully" }, with: Entities::Message)
104
+ end
105
+
106
+ failure = result.failure
107
+ case failure
108
+ when ActiveRecord::RecordNotFound
109
+ error!({ message: "ID:#{id} is not found" }, 404)
110
+ else
111
+ raise failure
112
+ end
138
113
  end
139
114
 
140
- if result.success?
141
- status 201
142
- return present(result.value!.model, with: Entities::Rule)
115
+ desc "Create a rule", {
116
+ success: Entities::Rule,
117
+ summary: "Create a rule"
118
+ }
119
+ params do
120
+ requires :yaml, type: String, documentation: { param_type: "body" }
143
121
  end
144
-
145
- failure = result.failure
146
- case failure
147
- when Psych::SyntaxError
148
- error!({ message: failure.message }, 400)
149
- when ValidationError
150
- error!({ message: "Data format is invalid", details: failure.errors.to_h }, 400)
151
- else
152
- raise failure
122
+ post "/" do
123
+ extend Dry::Monads[:result, :try]
124
+
125
+ yaml = params[:yaml]
126
+ result = Try { Rule.from_yaml(yaml) }.to_result.bind do |rule|
127
+ Try do
128
+ found = Mihari::Models::Rule.find_by_id(rule.id)
129
+ error!({ message: "ID:#{rule.id} is already registered" }, 400) unless found.nil?
130
+ rule
131
+ end.to_result
132
+ end.bind do |rule|
133
+ Try do
134
+ rule.model.save
135
+ rule
136
+ end.to_result
137
+ end
138
+
139
+ if result.success?
140
+ status 201
141
+ return present(result.value!.model, with: Entities::Rule)
142
+ end
143
+
144
+ failure = result.failure
145
+ case failure
146
+ when Psych::SyntaxError
147
+ error!({ message: failure.message }, 400)
148
+ when ValidationError
149
+ error!({ message: "Data format is invalid", details: failure.errors.to_h }, 400)
150
+ else
151
+ raise failure
152
+ end
153
153
  end
154
- end
155
154
 
156
- desc "Update a rule", {
157
- success: Entities::Rule,
158
- summary: "Update a rule"
159
- }
160
- params do
161
- requires :id, type: String, documentation: { param_type: "body" }
162
- requires :yaml, type: String, documentation: { param_type: "body" }
163
- end
164
- put "/" do
165
- extend Dry::Monads[:result, :try]
166
-
167
- id = params[:id]
168
- yaml = params[:yaml]
169
-
170
- result = Try do
171
- Mihari::Rule.find(id)
172
- end.to_result.bind do |_|
173
- Try do
174
- Services::RuleProxy.from_yaml(yaml)
175
- end.to_result
176
- end.bind do |rule|
177
- Try do
178
- rule.model.save
179
- rule
180
- end.to_result
155
+ desc "Update a rule", {
156
+ success: Entities::Rule,
157
+ summary: "Update a rule"
158
+ }
159
+ params do
160
+ requires :id, type: String, documentation: { param_type: "body" }
161
+ requires :yaml, type: String, documentation: { param_type: "body" }
181
162
  end
182
-
183
- if result.success?
184
- status 201
185
- return present(result.value!.model, with: Entities::Rule)
163
+ put "/" do
164
+ extend Dry::Monads[:result, :try]
165
+
166
+ id = params[:id]
167
+ yaml = params[:yaml]
168
+
169
+ result = Try do
170
+ Mihari::Models::Rule.find(id)
171
+ end.to_result.bind do |_|
172
+ Try { Rule.from_yaml(yaml) }.to_result
173
+ end.bind do |rule|
174
+ Try do
175
+ rule.model.save
176
+ rule
177
+ end.to_result
178
+ end
179
+
180
+ if result.success?
181
+ status 201
182
+ return present(result.value!.model, with: Entities::Rule)
183
+ end
184
+
185
+ failure = result.failure
186
+ case failure
187
+ when ActiveRecord::RecordNotFound
188
+ error!({ message: "ID:#{id} is not found" }, 404)
189
+ when Psych::SyntaxError
190
+ error!({ message: failure.message }, 400)
191
+ when ValidationError
192
+ error!({ message: "Data format is invalid", details: failure.errors.to_h }, 400)
193
+ else
194
+ raise failure
195
+ end
186
196
  end
187
197
 
188
- failure = result.failure
189
- case failure
190
- when ActiveRecord::RecordNotFound
191
- error!({ message: "ID:#{id} is not found" }, 404)
192
- when Psych::SyntaxError
193
- error!({ message: failure.message }, 400)
194
- when ValidationError
195
- error!({ message: "Data format is invalid", details: failure.errors.to_h }, 400)
196
- else
197
- raise failure
198
+ desc "Delete a rule", {
199
+ success: Entities::Message,
200
+ failure: [{ code: 404, message: "Not found", model: Entities::Message }],
201
+ summary: "Delete a rule"
202
+ }
203
+ params do
204
+ requires :id, type: String
198
205
  end
199
- end
200
-
201
- desc "Delete a rule", {
202
- success: Entities::Message,
203
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
204
- summary: "Delete a rule"
205
- }
206
- params do
207
- requires :id, type: String
208
- end
209
- delete "/:id" do
210
- extend Dry::Monads[:result, :try]
211
-
212
- id = params["id"].to_s
206
+ delete "/:id" do
207
+ extend Dry::Monads[:result, :try]
213
208
 
214
- result = Try do
215
- rule = Mihari::Rule.find(id)
216
- rule.destroy
217
- end.to_result
209
+ id = params["id"].to_s
218
210
 
219
- if result.success?
220
- status 204
221
- return present({ message: "ID:#{id} is deleted" }, with: Entities::Message)
222
- end
211
+ result = Try do
212
+ rule = Mihari::Models::Rule.find(id)
213
+ rule.destroy
214
+ end.to_result
223
215
 
224
- failure = result.failure
225
- case failure
226
- when ActiveRecord::RecordNotFound
227
- error!({ message: "ID:#{id} is not found" }, 404)
228
- else
229
- raise failure
216
+ if result.success?
217
+ status 204
218
+ return present({ message: "ID:#{id} is deleted" }, with: Entities::Message)
219
+ end
220
+
221
+ failure = result.failure
222
+ case failure
223
+ when ActiveRecord::RecordNotFound
224
+ error!({ message: "ID:#{id} is not found" }, 404)
225
+ else
226
+ raise failure
227
+ end
230
228
  end
231
229
  end
232
230
  end
@@ -1,47 +1,52 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Mihari
4
- module Endpoints
5
- class Tags < Grape::API
6
- namespace :tags do
7
- desc "Get tags", {
8
- is_array: true,
9
- success: Entities::Tags,
10
- summary: "Get tags"
11
- }
12
- get "/" do
13
- tags = Mihari::Tag.distinct.pluck(:name)
14
- present({ tags: tags }, with: Entities::Tags)
15
- end
4
+ module Web
5
+ module Endpoints
6
+ #
7
+ # Tag API endpoint
8
+ #
9
+ class Tags < Grape::API
10
+ namespace :tags do
11
+ desc "Get tags", {
12
+ is_array: true,
13
+ success: Entities::Tags,
14
+ summary: "Get tags"
15
+ }
16
+ get "/" do
17
+ tags = Mihari::Models::Tag.distinct.pluck(:name)
18
+ present({ tags: tags }, with: Entities::Tags)
19
+ end
16
20
 
17
- desc "Delete a tag", {
18
- success: Entities::Message,
19
- failure: [{ code: 404, message: "Not found", model: Entities::Message }],
20
- summary: "Delete a tag"
21
- }
22
- params do
23
- requires :name, type: String
24
- end
25
- delete "/:name" do
26
- extend Dry::Monads[:result, :try]
21
+ desc "Delete a tag", {
22
+ success: Entities::Message,
23
+ failure: [{ code: 404, message: "Not found", model: Entities::Message }],
24
+ summary: "Delete a tag"
25
+ }
26
+ params do
27
+ requires :name, type: String
28
+ end
29
+ delete "/:name" do
30
+ extend Dry::Monads[:result, :try]
27
31
 
28
- name = params[:name].to_s
32
+ name = params[:name].to_s
29
33
 
30
- result = Try do
31
- Mihari::Tag.where(name: name).destroy_all
32
- end.to_result
34
+ result = Try do
35
+ Mihari::Models::Tag.where(name: name).destroy_all
36
+ end.to_result
33
37
 
34
- if result.success?
35
- status 204
36
- return present({ message: "" }, with: Entities::Message)
37
- end
38
+ if result.success?
39
+ status 204
40
+ return present({ message: "" }, with: Entities::Message)
41
+ end
38
42
 
39
- failure = result.failure
40
- case failure
41
- when ActiveRecord::RecordNotFound
42
- error!({ message: "Name:#{name} is not found" }, 404)
43
- else
44
- raise failure
43
+ failure = result.failure
44
+ case failure
45
+ when ActiveRecord::RecordNotFound
46
+ error!({ message: "Name:#{name} is not found" }, 404)
47
+ else
48
+ raise failure
49
+ end
45
50
  end
46
51
  end
47
52
  end
@@ -1,15 +1,22 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
- module Middleware
3
- class ConnectionAdapter
4
- def initialize(app)
5
- @app = app
6
- end
4
+ module Web
5
+ module Middleware
6
+ #
7
+ # DB connection adapter for Rack app
8
+ #
9
+ class ConnectionAdapter
10
+ def initialize(app)
11
+ @app = app
12
+ end
7
13
 
8
- def call(env)
9
- Mihari::Database.with_db_connection do
10
- status, headers, body = @app.call(env)
14
+ def call(env)
15
+ Mihari::Database.with_db_connection do
16
+ status, headers, body = @app.call(env)
11
17
 
12
- [status, headers, body]
18
+ [status, headers, body]
19
+ end
13
20
  end
14
21
  end
15
22
  end
@@ -1,17 +1,24 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Mihari
2
- module Middleware
3
- class ErrorNotificationAdapter
4
- include Mixins::ErrorNotification
4
+ module Web
5
+ module Middleware
6
+ #
7
+ # Error notification adapter for Rack app
8
+ #
9
+ class ErrorNotificationAdapter
10
+ include Mixins::ErrorNotification
5
11
 
6
- def initialize(app)
7
- @app = app
8
- end
12
+ def initialize(app)
13
+ @app = app
14
+ end
9
15
 
10
- def call(env)
11
- with_error_notification do
12
- status, headers, body = @app.call(env)
16
+ def call(env)
17
+ with_error_notification do
18
+ status, headers, body = @app.call(env)
13
19
 
14
- [status, headers, body]
20
+ [status, headers, body]
21
+ end
15
22
  end
16
23
  end
17
24
  end