sqreen 1.18.3.beta1 → 1.18.3.beta2

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.
Files changed (121) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +0 -5
  3. data/lib/sqreen/actions.rb +11 -337
  4. data/lib/sqreen/actions/base.rb +110 -0
  5. data/lib/sqreen/actions/block_ip.rb +32 -0
  6. data/lib/sqreen/actions/block_user.rb +44 -0
  7. data/lib/sqreen/actions/ip_range_indexed_action_class.rb +36 -0
  8. data/lib/sqreen/actions/ip_ranges_index.rb +36 -0
  9. data/lib/sqreen/actions/redirect_ip.rb +40 -0
  10. data/lib/sqreen/actions/redirect_user.rb +45 -0
  11. data/lib/sqreen/actions/repository.rb +24 -0
  12. data/lib/sqreen/actions/unknown_action_type.rb +16 -0
  13. data/lib/sqreen/actions/user_action_class.rb +41 -0
  14. data/lib/sqreen/agent.rb +4 -1
  15. data/lib/sqreen/attack_blocked.rb +17 -0
  16. data/lib/sqreen/binding_accessor.rb +9 -102
  17. data/lib/sqreen/binding_accessor/path_elem.rb +8 -0
  18. data/lib/sqreen/binding_accessor/transforms.rb +107 -0
  19. data/lib/sqreen/capped_queue.rb +2 -0
  20. data/lib/sqreen/{callbacks.rb → cb.rb} +1 -53
  21. data/lib/sqreen/{callback_tree.rb → cb_tree.rb} +2 -2
  22. data/lib/sqreen/condition_evaluator.rb +22 -5
  23. data/lib/sqreen/configuration.rb +3 -0
  24. data/lib/sqreen/default_cb.rb +20 -0
  25. data/lib/sqreen/deferred_logger.rb +63 -0
  26. data/lib/sqreen/deliveries.rb +10 -0
  27. data/lib/sqreen/deliveries/batch.rb +7 -1
  28. data/lib/sqreen/deliveries/simple.rb +5 -0
  29. data/lib/sqreen/dependency/rails.rb +4 -0
  30. data/lib/sqreen/dependency/sinatra.rb +4 -0
  31. data/lib/sqreen/error_handling_middleware.rb +30 -0
  32. data/lib/sqreen/event.rb +2 -0
  33. data/lib/sqreen/events/attack.rb +2 -0
  34. data/lib/sqreen/events/request_record.rb +11 -56
  35. data/lib/sqreen/exception.rb +9 -40
  36. data/lib/sqreen/formatter_with_tid.rb +45 -0
  37. data/lib/sqreen/framework_cb.rb +28 -0
  38. data/lib/sqreen/frameworks.rb +7 -0
  39. data/lib/sqreen/frameworks/generic.rb +5 -1
  40. data/lib/sqreen/frameworks/rails.rb +2 -0
  41. data/lib/sqreen/frameworks/request_recorder.rb +3 -0
  42. data/lib/sqreen/frameworks/sinatra.rb +2 -0
  43. data/lib/sqreen/frameworks/sqreen_test.rb +2 -0
  44. data/lib/sqreen/instrumentation.rb +5 -5
  45. data/lib/sqreen/invalid_signature_exception.rb +8 -0
  46. data/lib/{sqreen-alt.rb → sqreen/js.rb} +6 -1
  47. data/lib/sqreen/js/call_context.rb +10 -0
  48. data/lib/sqreen/js/context_pool.rb +60 -0
  49. data/lib/sqreen/js/exec_js_runnable.rb +20 -0
  50. data/lib/sqreen/js/execjs_adapter.rb +6 -47
  51. data/lib/sqreen/js/executable_js.rb +12 -0
  52. data/lib/sqreen/js/js_service.rb +2 -22
  53. data/lib/sqreen/js/js_service_adapter.rb +18 -0
  54. data/lib/sqreen/js/mini_racer_adapter.rb +6 -180
  55. data/lib/sqreen/js/mini_racer_executable_js.rb +142 -0
  56. data/lib/sqreen/js/thread_local_exec_js_runnable.rb +47 -0
  57. data/lib/sqreen/log.rb +8 -188
  58. data/lib/sqreen/logger.rb +83 -0
  59. data/lib/sqreen/metrics_store.rb +3 -11
  60. data/lib/sqreen/metrics_store/already_registered_metric.rb +11 -0
  61. data/lib/sqreen/metrics_store/unknown_metric.rb +11 -0
  62. data/lib/sqreen/metrics_store/unregistered_metric.rb +11 -0
  63. data/lib/sqreen/middleware.rb +0 -44
  64. data/lib/sqreen/mono_time.rb +2 -0
  65. data/lib/sqreen/node.rb +44 -0
  66. data/lib/sqreen/not_implemented_yet.rb +8 -0
  67. data/lib/sqreen/null_logger.rb +24 -0
  68. data/lib/sqreen/payload_creator.rb +2 -19
  69. data/lib/sqreen/payload_creator/header_section.rb +28 -0
  70. data/lib/sqreen/prefix.rb +33 -0
  71. data/lib/sqreen/rails_middleware.rb +14 -0
  72. data/lib/sqreen/remote_command.rb +1 -8
  73. data/lib/sqreen/remote_command/failure_output.rb +11 -0
  74. data/lib/sqreen/rules.rb +32 -2
  75. data/lib/sqreen/{rule_attributes.rb → rules/attrs.rb} +0 -0
  76. data/lib/sqreen/{rules_callbacks/sdk_auth_track.rb → rules/auth_track_cb.rb} +2 -2
  77. data/lib/sqreen/{rules_callbacks/binding_accessor_matcher.rb → rules/binding_accessor_matcher_cb.rb} +4 -8
  78. data/lib/sqreen/{rules_callbacks → rules}/binding_accessor_metrics.rb +1 -1
  79. data/lib/sqreen/{rules_callbacks/blacklist_ips.rb → rules/blacklist_ips_cb.rb} +3 -2
  80. data/lib/sqreen/{rules_callbacks → rules}/count_http_codes.rb +2 -2
  81. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches.rb → rules/crawler_user_agent_matches_cb.rb} +1 -1
  82. data/lib/sqreen/{rules_callbacks/crawler_user_agent_matches_metrics.rb → rules/crawler_user_agent_matches_metrics_cb.rb} +1 -1
  83. data/lib/sqreen/{rules_callbacks/custom_error.rb → rules/custom_error_cb.rb} +1 -1
  84. data/lib/sqreen/{rules_callbacks/devise_auth_track.rb → rules/devise_auth_track_cb.rb} +2 -2
  85. data/lib/sqreen/{rules_callbacks/devise_signup_track.rb → rules/devise_signup_track_cb.rb} +2 -2
  86. data/lib/sqreen/{rules_callbacks/execjs.rb → rules/execjs_cb.rb} +49 -50
  87. data/lib/sqreen/{rules_callbacks/headers_insert.rb → rules/headers_insert_cb.rb} +1 -1
  88. data/lib/sqreen/{rules_callbacks → rules}/matcher_rule.rb +2 -2
  89. data/lib/sqreen/{rules_callbacks/not_found.rb → rules/not_found_cb.rb} +2 -2
  90. data/lib/sqreen/{rules_callbacks/rails_parameters.rb → rules/rails_parameters_cb.rb} +1 -1
  91. data/lib/sqreen/{rules_callbacks → rules}/record_request_context.rb +1 -1
  92. data/lib/sqreen/{rules_callbacks/regexp_rule.rb → rules/regexp_rule_cb.rb} +1 -1
  93. data/lib/sqreen/{rule_callback.rb → rules/rule_cb.rb} +2 -2
  94. data/lib/sqreen/{rules_callbacks → rules}/run_req_start_actions.rb +4 -2
  95. data/lib/sqreen/{rules_callbacks → rules}/run_user_actions.rb +1 -1
  96. data/lib/sqreen/{rules_callbacks/shell_env.rb → rules/shell_env_cb.rb} +1 -1
  97. data/lib/sqreen/{rules_callbacks/sdk_signup_track.rb → rules/signup_track_cb.rb} +2 -2
  98. data/lib/sqreen/{rules_callbacks → rules}/update_request_context.rb +1 -1
  99. data/lib/sqreen/{rules_callbacks/url_matches.rb → rules/url_matches_cb.rb} +1 -1
  100. data/lib/sqreen/{rules_callbacks/user_agent_matches.rb → rules/user_agent_matches_cb.rb} +1 -1
  101. data/lib/sqreen/{rules_callbacks/waf.rb → rules/waf_cb.rb} +7 -3
  102. data/lib/sqreen/{rules_callbacks/reflected_xss.rb → rules/xss_cb.rb} +10 -7
  103. data/lib/sqreen/run_when_called_cb.rb +21 -0
  104. data/lib/sqreen/sensitive_data_redactor.rb +111 -0
  105. data/lib/sqreen/signature_verifier.rb +20 -0
  106. data/lib/sqreen/sinatra_middleware.rb +14 -0
  107. data/lib/sqreen/{rules_signature.rb → sqreen_signed_verifier.rb} +5 -17
  108. data/lib/sqreen/token_invalid_exception.rb +8 -0
  109. data/lib/sqreen/token_not_found_exception.rb +9 -0
  110. data/lib/sqreen/trie.rb +3 -64
  111. data/lib/sqreen/unauthorized.rb +8 -0
  112. data/lib/sqreen/util.rb +2 -0
  113. data/lib/sqreen/util/capped_array.rb +30 -0
  114. data/lib/sqreen/util/capped_hash.rb +36 -0
  115. data/lib/sqreen/util/capped_string.rb +22 -0
  116. data/lib/sqreen/util/capper.rb +57 -0
  117. data/lib/sqreen/version.rb +1 -1
  118. data/lib/sqreen/waf_error.rb +18 -0
  119. metadata +85 -36
  120. data/lib/sqreen/rules_callbacks.rb +0 -36
  121. data/lib/sqreen/rules_callbacks/inspect_rule.rb +0 -25
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0cb385fddb3e1bb873a5def8b85d4e0865650ba97268d8cd3f67d84640439010
4
- data.tar.gz: 65d395b3926571d088603a7e604a3c377a6e57c334ab4c106354812e65d8f84d
3
+ metadata.gz: 1a1340b0e4265b69cea5bb84456f52586f310ccc03aadd9d6974779707d55329
4
+ data.tar.gz: 4da37a0e4bd305d18fc06d164683f46dddf830c54a67c3a3f3481a6314efbc34
5
5
  SHA512:
6
- metadata.gz: b0ae2a6ebe375573a26372a63fb383e7176bda425e52d977b9e42172c6e95b13143f3be83f069985bdcbea5816f61a53a4b6fabc98ed004ffb8142a17f10400c
7
- data.tar.gz: 8d233a01e2ef20ed7b1f1fd6d1ddbb384b482ca62d01ebec4100a1138430064e04368d9e078313364e8c99885bb0b137e2cc19a52b5e91e1ab5f50dbeaf67967
6
+ metadata.gz: 662b2f798f20452c4a8cd328608277f68748584e2e335a9e2f4cc5a3acdc97fd5345136048f23813c76dee8974a0ae1e62bb2018b97b0d2bbe729d31603fbfec
7
+ data.tar.gz: 9f4d4c1efad12ed3831dedb528a677d1cf92bb7a0c3c7a07c21c26b5838a5081e2b3a8944bfb3a89c80b6f80f09c9cb676af23839c401187702038aae014c8cf
data/CHANGELOG.md CHANGED
@@ -1,8 +1,3 @@
1
- ## 1.18.3.beta1
2
-
3
- * Improve middleware hookpoints on Sinatra
4
- * Support application/json payloads on Sinatra
5
-
6
1
  ## 1.18.2
7
2
 
8
3
  * Improve internal WAF error reporting
@@ -1,51 +1,26 @@
1
1
  # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
2
  # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
3
 
4
- require 'ipaddr'
5
- require 'sqreen/trie'
6
- require 'sqreen/log'
7
- require 'sqreen/exception'
8
- require 'sqreen/sdk'
9
- require 'sqreen/frameworks'
10
- require 'singleton'
4
+ require 'sqreen/actions/unknown_action_type'
5
+ require 'sqreen/actions/base'
6
+
7
+ require 'sqreen/actions/block_user'
8
+ require 'sqreen/actions/redirect_user'
9
+ require 'sqreen/actions/block_ip'
10
+ require 'sqreen/actions/redirect_ip'
11
+ require 'sqreen/actions/repository'
12
+ require 'sqreen/actions/unknown_action_type'
11
13
 
12
14
  module Sqreen
13
15
  # Implements actions (behavior taken in response to agent signals)
14
16
  module Actions
15
- # Exception for when an unknown action type is gotten from the server
16
- class UnknownActionType < ::Sqreen::Exception
17
- attr_reader :action_type
18
- def initialize(action_type)
19
- super("no such action type: #{action_type}. Must be one of #{Base.known_types}")
20
- @action_type = action_type
21
- end
22
- end
23
-
24
- # Where the currently loaded actions are stored. Singleton
25
- class Repository
26
- include Singleton
27
-
28
- def add(params, action)
29
- action.class.index(params || {}, action)
30
- end
31
-
32
- def get(action_class, key)
33
- action_class = Base.get_type_class(action_class) unless action_class.class == Class
34
- action_class.actions_matching key
35
- end
36
-
37
- def clear
38
- Base.known_subclasses.each(&:clear)
39
- end
40
- end
41
-
42
17
  # @return [Sqreen::Actions::Base]
43
18
  def self.deserialize_action(hash)
44
19
  action_type = hash['action']
45
20
  raise 'no action type available' unless action_type
46
21
 
47
- subclass = Base.get_type_class(action_type)
48
- raise UnknownActionType, action_type unless subclass
22
+ subclass = Sqreen::Actions::Base.get_type_class(action_type)
23
+ raise Sqreen::Actions::UnknownActionType, action_type unless subclass
49
24
 
50
25
  id = hash['action_id']
51
26
  raise 'no action id available' unless id
@@ -63,306 +38,5 @@ module Sqreen
63
38
 
64
39
  subclass.new(id, opts, hash['parameters'] || {})
65
40
  end
66
-
67
- # Base class for actions
68
- # subclasses must also implement some methods in their singleton classes
69
- # (actions_matching, index and clear)
70
- class Base
71
- attr_reader :id, :expiry, :send_response
72
-
73
- def initialize(id, opts)
74
- @id = id
75
- duration = opts[:duration]
76
- @expiry = Time.new + duration unless duration.nil?
77
- @send_response = if opts[:send_response].nil?
78
- true
79
- else
80
- !!opts[:send_response]
81
- end
82
- end
83
-
84
- # See Sqreen::CB for return values
85
- def run(*args)
86
- return if expiry && Time.new > expiry
87
- ret = do_run *args
88
- unless ret.nil? || !@send_response
89
- Sqreen.internal_track(event_name,
90
- 'properties' => {
91
- 'output' => event_properties(*args),
92
- 'action_id' => id,
93
- })
94
- end
95
- ret
96
- end
97
-
98
- protected
99
-
100
- def do_run(*_args)
101
- raise ::Sqreen::NotImplementedYet, "do_run not implemented in #{self.class}"
102
- # implement in subclasses
103
- end
104
-
105
- def event_properties(*_run_args)
106
- raise ::Sqreen::NotImplementedYet, "event_properties not implemented in #{self.class}"
107
- # implement in subclasses
108
- end
109
-
110
- private
111
-
112
- def event_name
113
- "sq.action.#{self.class.type_name}"
114
- end
115
-
116
- @@subclasses = {}
117
- class << self
118
- private :new
119
-
120
- attr_reader :type_name
121
-
122
- def get_type_class(name)
123
- @@subclasses[name]
124
- end
125
-
126
- def known_subclasses
127
- @@subclasses.values
128
- end
129
-
130
- def known_types
131
- @@subclasses.keys
132
- end
133
-
134
- # all actions matching, possibly already expired
135
- def actions_matching(_key)
136
- raise 'implement in singletons of subclasses'
137
- end
138
-
139
- def index(_params, _action)
140
- raise 'implement in singletons of subclasses'
141
- end
142
-
143
- def clear
144
- raise 'implement in singletons of subclasses'
145
- end
146
-
147
- def inherited(subclass)
148
- class << subclass
149
- public :new
150
- end
151
- end
152
-
153
- protected
154
-
155
- def type_name=(name)
156
- @type_name = name
157
- @@subclasses[name] = self
158
- end
159
- end
160
- end
161
-
162
- module IpRangesIndex
163
- def add_prefix(prefix_str, data)
164
- @trie_v4 ||= Sqreen::Trie.new
165
- @trie_v6 ||= Sqreen::Trie.new(nil, nil, Socket::AF_INET6)
166
- prefix = Sqreen::Prefix.from_str(prefix_str, data)
167
- trie = prefix.family == Socket::AF_INET6 ? @trie_v6 : @trie_v4
168
- trie.insert prefix
169
- end
170
-
171
- def matching_actions(client_ip)
172
- parsed_ip = IPAddr.new(client_ip.gsub(/%[^%\/]+/, ''))
173
- trie = parsed_ip.family == Socket::AF_INET6 ? @trie_v6 : @trie_v4
174
- return [] unless trie
175
- found = trie.search_matching(parsed_ip.to_i, parsed_ip.family)
176
- return [] unless found.size > 0
177
-
178
- Sqreen.log.debug("Client ip #{client_ip} matches #{found.inspect}")
179
- found.map(&:data)
180
- end
181
-
182
- def clear
183
- @trie_v4 = Sqreen::Trie.new
184
- @trie_v6 = Sqreen::Trie.new(nil, nil, Socket::AF_INET6)
185
- end
186
- end
187
-
188
- module IpRangeIndexedActionClass
189
- include IpRangesIndex
190
-
191
- def actions_matching(client_ip)
192
- matching_actions client_ip
193
- end
194
-
195
- def index(params, action)
196
- ranges = parse_ip_ranges params
197
-
198
- ranges.each do |r|
199
- add_prefix r, action
200
- end
201
- end
202
-
203
- private
204
-
205
- # returns array of prefixes in string form
206
- def parse_ip_ranges(params)
207
- ranges = params['ip_cidr']
208
- unless ranges && ranges.is_a?(Array) && !ranges.empty?
209
- raise 'no non-empty ip_cidr array present'
210
- end
211
-
212
- ranges
213
- end
214
- end
215
-
216
- # Block a list of IP address ranges. Standard "raise" behavior.
217
- class BlockIp < Base
218
- extend IpRangeIndexedActionClass
219
-
220
- self.type_name = 'block_ip'
221
-
222
- def initialize(id, opts, params = {})
223
- # no need to store the ranges for this action, the index filter the class
224
- super(id, opts)
225
- end
226
-
227
- def do_run(client_ip)
228
- e = Sqreen::AttackBlocked.new("Blocked client's IP #{client_ip} " \
229
- "(action: #{id}). No action is required")
230
- { :status => :raise, :exception => e, :skip_rem_cbs => true }
231
- end
232
-
233
- def event_properties(client_ip)
234
- { 'ip_address' => client_ip }
235
- end
236
- end
237
-
238
- # Block a list of IP address ranges by forcefully redirecting the user
239
- # to a specific URL.
240
- class RedirectIp < Base
241
- extend IpRangeIndexedActionClass
242
-
243
- self.type_name = 'redirect_ip'
244
-
245
- attr_reader :redirect_url
246
-
247
- def initialize(id, opts, params = {})
248
- super(id, opts)
249
- @redirect_url = params['url']
250
- raise "no url provided for action #{id}" unless @redirect_url
251
- end
252
-
253
- def do_run(client_ip)
254
- Sqreen.log.info "Will request redirect for client with IP #{client_ip} " \
255
- "(action: #{id})."
256
- {
257
- :status => :skip,
258
- :new_return_value => [303, { 'Location' => @redirect_url }, ['']],
259
- :skip_rem_cbs => true,
260
- }
261
- end
262
-
263
- def event_properties(client_ip)
264
- { 'ip_address' => client_ip, 'url' => @redirect_url }
265
- end
266
- end
267
-
268
- module UserActionClass
269
- def actions_matching(identity_params)
270
- return [] unless @idx
271
- key = stringify_keys(identity_params)
272
- actions = @idx[key]
273
- actions || []
274
- end
275
-
276
- def index(params, action)
277
- @idx ||= {}
278
- users = params['users']
279
- raise ::Sqreen::Exception, 'nil "users" param for block_user action' if users.nil?
280
- raise ::Sqreen::Exception, '"users" param must be an array' unless users.is_a? Array
281
-
282
- users.each do |u|
283
- @idx[u] ||= []
284
- @idx[u] << action
285
- end
286
- end
287
-
288
- def clear
289
- @idx = {}
290
- end
291
-
292
- private
293
-
294
- def stringify_keys(hash)
295
- Hash[
296
- hash.map { |k, v| [k.to_s, v] }
297
- ]
298
- end
299
- end
300
-
301
- # Blocks a user at the point Sqreen::identify()
302
- # or Sqreen::auth_track() are called
303
- class BlockUser < Base
304
- extend UserActionClass
305
-
306
- self.type_name = 'block_user'
307
-
308
- def initialize(id, opts, params = {})
309
- super(id, opts)
310
- end
311
-
312
- def do_run(identity_params)
313
- Sqreen.log.info(
314
- "Will raise due to user being blocked by action #{id}. " \
315
- "Blocked user identity: #{identity_params}"
316
- )
317
-
318
- e = Sqreen::AttackBlocked.new(
319
- "Blocked user with identity #{identity_params} " \
320
- 'due to automatic security response. No action is required'
321
- )
322
-
323
- {
324
- :status => :raise,
325
- :exception => e,
326
- }
327
- end
328
-
329
- def event_properties(identity_params)
330
- { 'user' => identity_params }
331
- end
332
- end
333
-
334
- # Redirects a user at the point Sqreen::identify()
335
- # or Sqreen::auth_track() are called
336
- class RedirectUser < Base
337
- extend UserActionClass
338
-
339
- self.type_name = 'redirect_user'
340
-
341
- def initialize(id, opts, params = {})
342
- super(id, opts)
343
- @redirect_url = params['url']
344
- raise "no url provided for action #{id}" unless @redirect_url
345
- end
346
-
347
- def do_run(identity_params)
348
- Sqreen.log.info 'Will request redirect for user with identity ' \
349
- "#{identity_params} (action: #{id})."
350
-
351
- e = Sqreen::AttackBlocked.new(
352
- "Redirected user with identity #{identity_params} " \
353
- 'due to automatic security response. No action is required'
354
- )
355
- e.redirect_url = @redirect_url
356
-
357
- {
358
- :status => :raise,
359
- :exception => e,
360
- }
361
- end
362
-
363
- def event_properties(identity_params)
364
- { 'user' => identity_params }
365
- end
366
- end
367
41
  end
368
42
  end
@@ -0,0 +1,110 @@
1
+ # Copyright (c) 2015 Sqreen. All Rights Reserved.
2
+ # Please refer to our terms for more information: https://www.sqreen.com/terms.html
3
+
4
+ # TODO: remove class vars
5
+
6
+ require 'sqreen/exception'
7
+
8
+ module Sqreen
9
+ # Implements actions (behavior taken in response to agent signals)
10
+ module Actions
11
+ # Base class for actions
12
+ # subclasses must also implement some methods in their singleton classes
13
+ # (actions_matching, index and clear)
14
+ class Base
15
+ attr_reader :id, :expiry, :send_response
16
+
17
+ def initialize(id, opts)
18
+ @id = id
19
+ duration = opts[:duration]
20
+ @expiry = Time.new + duration unless duration.nil?
21
+ @send_response = if opts[:send_response].nil?
22
+ true
23
+ else
24
+ opts[:send_response] ? true : false
25
+ end
26
+ end
27
+
28
+ # See Sqreen::CB for return values
29
+ def run(*args)
30
+ return if expiry && Time.new > expiry
31
+ ret = do_run(*args)
32
+ unless ret.nil? || !@send_response
33
+ Sqreen.internal_track(event_name,
34
+ 'properties' => {
35
+ 'output' => event_properties(*args),
36
+ 'action_id' => id,
37
+ })
38
+ end
39
+ ret
40
+ end
41
+
42
+ protected
43
+
44
+ def do_run(*_args)
45
+ raise ::Sqreen::NotImplementedYet, "do_run not implemented in #{self.class}"
46
+ # implement in subclasses
47
+ end
48
+
49
+ def event_properties(*_run_args)
50
+ raise ::Sqreen::NotImplementedYet, "event_properties not implemented in #{self.class}"
51
+ # implement in subclasses
52
+ end
53
+
54
+ private
55
+
56
+ def event_name
57
+ "sq.action.#{self.class.type_name}"
58
+ end
59
+
60
+ @@subclasses = {} # rubocop:disable Style/ClassVars
61
+ class << self
62
+ private :new
63
+
64
+ attr_reader :type_name
65
+
66
+ def get_type_class(name)
67
+ subclasses[name]
68
+ end
69
+
70
+ def known_subclasses
71
+ subclasses.values
72
+ end
73
+
74
+ def known_types
75
+ subclasses.keys
76
+ end
77
+
78
+ # all actions matching, possibly already expired
79
+ def actions_matching(_key)
80
+ raise 'implement in singletons of subclasses'
81
+ end
82
+
83
+ def index(_params, _action)
84
+ raise 'implement in singletons of subclasses'
85
+ end
86
+
87
+ def clear
88
+ raise 'implement in singletons of subclasses'
89
+ end
90
+
91
+ def inherited(subclass)
92
+ class << subclass
93
+ public :new
94
+ end
95
+ end
96
+
97
+ protected
98
+
99
+ def subclasses
100
+ @@subclasses
101
+ end
102
+
103
+ def type_name=(name)
104
+ @type_name = name
105
+ subclasses[name] = self
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end