sqreen 1.19.1-java → 1.21.0.beta3-java

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 (101) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +34 -0
  3. data/lib/sqreen/actions/block_user.rb +1 -1
  4. data/lib/sqreen/actions/redirect_ip.rb +1 -1
  5. data/lib/sqreen/actions/redirect_user.rb +1 -1
  6. data/lib/sqreen/agent_message.rb +20 -0
  7. data/lib/sqreen/aggregated_metric.rb +25 -0
  8. data/lib/sqreen/attack_detected.html +1 -2
  9. data/lib/sqreen/ca.crt +24 -0
  10. data/lib/sqreen/condition_evaluator.rb +9 -2
  11. data/lib/sqreen/conditionable.rb +24 -6
  12. data/lib/sqreen/configuration.rb +11 -5
  13. data/lib/sqreen/deferred_logger.rb +50 -14
  14. data/lib/sqreen/deliveries/batch.rb +12 -2
  15. data/lib/sqreen/deliveries/simple.rb +4 -0
  16. data/lib/sqreen/deprecation.rb +38 -0
  17. data/lib/sqreen/ecosystem.rb +96 -0
  18. data/lib/sqreen/ecosystem/dispatch_table.rb +43 -0
  19. data/lib/sqreen/ecosystem/exception_reporting.rb +26 -0
  20. data/lib/sqreen/ecosystem/http/net_http.rb +50 -0
  21. data/lib/sqreen/ecosystem/http/rack_request.rb +39 -0
  22. data/lib/sqreen/ecosystem/loggable.rb +13 -0
  23. data/lib/sqreen/ecosystem/module_api.rb +30 -0
  24. data/lib/sqreen/ecosystem/module_api/event_listener.rb +18 -0
  25. data/lib/sqreen/ecosystem/module_api/instrumentation.rb +23 -0
  26. data/lib/sqreen/ecosystem/module_api/message_producer.rb +51 -0
  27. data/lib/sqreen/ecosystem/module_api/signal_producer.rb +24 -0
  28. data/lib/sqreen/ecosystem/module_api/tracing.rb +45 -0
  29. data/lib/sqreen/ecosystem/module_api/tracing/client_data.rb +31 -0
  30. data/lib/sqreen/ecosystem/module_api/tracing/server_data.rb +27 -0
  31. data/lib/sqreen/ecosystem/module_api/tracing_id_generation.rb +16 -0
  32. data/lib/sqreen/ecosystem/module_api/transaction_storage.rb +71 -0
  33. data/lib/sqreen/ecosystem/module_registry.rb +44 -0
  34. data/lib/sqreen/ecosystem/redis/redis_connection.rb +43 -0
  35. data/lib/sqreen/ecosystem/tracing/modules/client.rb +31 -0
  36. data/lib/sqreen/ecosystem/tracing/modules/server.rb +30 -0
  37. data/lib/sqreen/ecosystem/tracing/sampler.rb +160 -0
  38. data/lib/sqreen/ecosystem/tracing/sampling_configuration.rb +150 -0
  39. data/lib/sqreen/ecosystem/tracing/signals/tracing_client.rb +53 -0
  40. data/lib/sqreen/ecosystem/tracing/signals/tracing_server.rb +53 -0
  41. data/lib/sqreen/ecosystem/tracing_broker.rb +101 -0
  42. data/lib/sqreen/ecosystem/tracing_id_setup.rb +34 -0
  43. data/lib/sqreen/ecosystem/transaction_storage.rb +64 -0
  44. data/lib/sqreen/ecosystem/util/call_writers_from_init.rb +13 -0
  45. data/lib/sqreen/ecosystem_integration.rb +87 -0
  46. data/lib/sqreen/ecosystem_integration/around_callbacks.rb +99 -0
  47. data/lib/sqreen/ecosystem_integration/instrumentation_service.rb +42 -0
  48. data/lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb +58 -0
  49. data/lib/sqreen/ecosystem_integration/signal_consumption.rb +35 -0
  50. data/lib/sqreen/endpoint_testing.rb +184 -0
  51. data/lib/sqreen/event.rb +7 -5
  52. data/lib/sqreen/events/attack.rb +23 -18
  53. data/lib/sqreen/events/remote_exception.rb +0 -22
  54. data/lib/sqreen/events/request_record.rb +15 -71
  55. data/lib/sqreen/frameworks/generic.rb +24 -1
  56. data/lib/sqreen/frameworks/rails.rb +0 -7
  57. data/lib/sqreen/frameworks/request_recorder.rb +15 -2
  58. data/lib/sqreen/graft/call.rb +106 -19
  59. data/lib/sqreen/graft/callback.rb +1 -1
  60. data/lib/sqreen/graft/hook.rb +212 -100
  61. data/lib/sqreen/graft/hook_point.rb +18 -11
  62. data/lib/sqreen/kit/signals/specialized/aggregated_metric.rb +72 -0
  63. data/lib/sqreen/kit/signals/specialized/attack.rb +57 -0
  64. data/lib/sqreen/kit/signals/specialized/binning_metric.rb +76 -0
  65. data/lib/sqreen/kit/signals/specialized/http_trace.rb +26 -0
  66. data/lib/sqreen/kit/signals/specialized/sdk_track_call.rb +50 -0
  67. data/lib/sqreen/kit/signals/specialized/sqreen_exception.rb +57 -0
  68. data/lib/sqreen/legacy/instrumentation.rb +22 -10
  69. data/lib/sqreen/legacy/old_event_submission_strategy.rb +228 -0
  70. data/lib/sqreen/legacy/waf_redactions.rb +49 -0
  71. data/lib/sqreen/log.rb +3 -2
  72. data/lib/sqreen/log/loggable.rb +2 -1
  73. data/lib/sqreen/logger.rb +24 -0
  74. data/lib/sqreen/metrics.rb +1 -0
  75. data/lib/sqreen/metrics/base.rb +3 -0
  76. data/lib/sqreen/metrics/req_detailed.rb +41 -0
  77. data/lib/sqreen/metrics_store.rb +33 -12
  78. data/lib/sqreen/null_logger.rb +22 -0
  79. data/lib/sqreen/performance_notifications/binned_metrics.rb +8 -2
  80. data/lib/sqreen/remote_command.rb +4 -0
  81. data/lib/sqreen/rules.rb +12 -6
  82. data/lib/sqreen/rules/blacklist_ips_cb.rb +2 -2
  83. data/lib/sqreen/rules/custom_error_cb.rb +3 -3
  84. data/lib/sqreen/rules/not_found_cb.rb +2 -0
  85. data/lib/sqreen/rules/rule_cb.rb +6 -2
  86. data/lib/sqreen/rules/waf_cb.rb +16 -13
  87. data/lib/sqreen/runner.rb +138 -16
  88. data/lib/sqreen/sensitive_data_redactor.rb +19 -31
  89. data/lib/sqreen/session.rb +53 -43
  90. data/lib/sqreen/signals/conversions.rb +288 -0
  91. data/lib/sqreen/signals/http_trace_redaction.rb +111 -0
  92. data/lib/sqreen/signals/signals_submission_strategy.rb +78 -0
  93. data/lib/sqreen/version.rb +1 -1
  94. data/lib/sqreen/weave/budget.rb +35 -0
  95. data/lib/sqreen/weave/legacy/instrumentation.rb +277 -135
  96. data/lib/sqreen/worker.rb +6 -2
  97. metadata +86 -10
  98. data/lib/sqreen/backport.rb +0 -9
  99. data/lib/sqreen/backport/clock_gettime.rb +0 -74
  100. data/lib/sqreen/backport/original_name.rb +0 -88
  101. data/lib/sqreen/encoding_sanitizer.rb +0 -27
@@ -23,11 +23,15 @@ module Sqreen
23
23
  Sqreen.log.debug("Starting Sqreen #{Sqreen::VERSION}")
24
24
  prevent_startup = Sqreen.framework.prevent_startup
25
25
  if !prevent_startup
26
- warn "[#{Process.pid}] Sqreen logging at level #{Sqreen.log.instance_eval { @logger }.level} to #{Sqreen.log.instance_eval { @logger }.instance_eval { @logdev.filename }}"
26
+ logger = Sqreen.log.instance_eval { @logger }
27
+ log_level = logger.send(:format_severity, logger.level)
28
+ log_filename = logger.instance_eval { @logdev.filename }
29
+ warn "process.pid:#{Process.pid} sqreen.log.level:#{log_level} sqreen.log.location:#{log_filename.inspect}"
27
30
  runner = Sqreen::Runner.new(configuration, framework)
28
31
  runner.run_watcher
32
+ Sqreen.log.info("process.pid:#{Process.pid} sqreen.start:true")
29
33
  else
30
- Sqreen.log.debug("#{prevent_startup} prevented Sqreen startup")
34
+ Sqreen.log.info("process.pid:#{Process.pid} sqreen.start:false cause:#{prevent_startup}")
31
35
  end
32
36
  rescue Sqreen::TokenNotFoundException
33
37
  Sqreen.log.error "Sorry but we couldn't find your Sqreen token.\nYour application is NOT currently protected by Sqreen.\n\nHave you filled your config/sqreen.yml?\n\n"
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sqreen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.19.1
4
+ version: 1.21.0.beta3
5
5
  platform: java
6
6
  authors:
7
7
  - Sqreen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-06-01 00:00:00.000000000 Z
11
+ date: 2020-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - "~>"
17
+ - !ruby/object:Gem::Version
18
+ version: 0.1.0
19
+ name: sqreen-backport
20
+ prerelease: false
21
+ type: :runtime
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 0.1.0
27
+ - !ruby/object:Gem::Dependency
28
+ requirement: !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - "~>"
31
+ - !ruby/object:Gem::Version
32
+ version: 0.2.2
33
+ name: sqreen-kit
34
+ prerelease: false
35
+ type: :runtime
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.2.2
13
41
  - !ruby/object:Gem::Dependency
14
42
  requirement: !ruby/object:Gem::Requirement
15
43
  requirements:
@@ -65,11 +93,10 @@ files:
65
93
  - lib/sqreen/actions/user_action_class.rb
66
94
  - lib/sqreen/actions/users_index.rb
67
95
  - lib/sqreen/agent.rb
96
+ - lib/sqreen/agent_message.rb
97
+ - lib/sqreen/aggregated_metric.rb
68
98
  - lib/sqreen/attack_blocked.rb
69
99
  - lib/sqreen/attack_detected.html
70
- - lib/sqreen/backport.rb
71
- - lib/sqreen/backport/clock_gettime.rb
72
- - lib/sqreen/backport/original_name.rb
73
100
  - lib/sqreen/binding_accessor.rb
74
101
  - lib/sqreen/binding_accessor/path_elem.rb
75
102
  - lib/sqreen/binding_accessor/transforms.rb
@@ -95,7 +122,41 @@ files:
95
122
  - lib/sqreen/dependency/rails.rb
96
123
  - lib/sqreen/dependency/sentry.rb
97
124
  - lib/sqreen/dependency/sinatra.rb
98
- - lib/sqreen/encoding_sanitizer.rb
125
+ - lib/sqreen/deprecation.rb
126
+ - lib/sqreen/ecosystem.rb
127
+ - lib/sqreen/ecosystem/dispatch_table.rb
128
+ - lib/sqreen/ecosystem/exception_reporting.rb
129
+ - lib/sqreen/ecosystem/http/net_http.rb
130
+ - lib/sqreen/ecosystem/http/rack_request.rb
131
+ - lib/sqreen/ecosystem/loggable.rb
132
+ - lib/sqreen/ecosystem/module_api.rb
133
+ - lib/sqreen/ecosystem/module_api/event_listener.rb
134
+ - lib/sqreen/ecosystem/module_api/instrumentation.rb
135
+ - lib/sqreen/ecosystem/module_api/message_producer.rb
136
+ - lib/sqreen/ecosystem/module_api/signal_producer.rb
137
+ - lib/sqreen/ecosystem/module_api/tracing.rb
138
+ - lib/sqreen/ecosystem/module_api/tracing/client_data.rb
139
+ - lib/sqreen/ecosystem/module_api/tracing/server_data.rb
140
+ - lib/sqreen/ecosystem/module_api/tracing_id_generation.rb
141
+ - lib/sqreen/ecosystem/module_api/transaction_storage.rb
142
+ - lib/sqreen/ecosystem/module_registry.rb
143
+ - lib/sqreen/ecosystem/redis/redis_connection.rb
144
+ - lib/sqreen/ecosystem/tracing/modules/client.rb
145
+ - lib/sqreen/ecosystem/tracing/modules/server.rb
146
+ - lib/sqreen/ecosystem/tracing/sampler.rb
147
+ - lib/sqreen/ecosystem/tracing/sampling_configuration.rb
148
+ - lib/sqreen/ecosystem/tracing/signals/tracing_client.rb
149
+ - lib/sqreen/ecosystem/tracing/signals/tracing_server.rb
150
+ - lib/sqreen/ecosystem/tracing_broker.rb
151
+ - lib/sqreen/ecosystem/tracing_id_setup.rb
152
+ - lib/sqreen/ecosystem/transaction_storage.rb
153
+ - lib/sqreen/ecosystem/util/call_writers_from_init.rb
154
+ - lib/sqreen/ecosystem_integration.rb
155
+ - lib/sqreen/ecosystem_integration/around_callbacks.rb
156
+ - lib/sqreen/ecosystem_integration/instrumentation_service.rb
157
+ - lib/sqreen/ecosystem_integration/request_lifecycle_tracking.rb
158
+ - lib/sqreen/ecosystem_integration/signal_consumption.rb
159
+ - lib/sqreen/endpoint_testing.rb
99
160
  - lib/sqreen/error_handling_middleware.rb
100
161
  - lib/sqreen/event.rb
101
162
  - lib/sqreen/events/attack.rb
@@ -129,8 +190,16 @@ files:
129
190
  - lib/sqreen/js/mini_racer_adapter.rb
130
191
  - lib/sqreen/js/mini_racer_executable_js.rb
131
192
  - lib/sqreen/js/thread_local_exec_js_runnable.rb
193
+ - lib/sqreen/kit/signals/specialized/aggregated_metric.rb
194
+ - lib/sqreen/kit/signals/specialized/attack.rb
195
+ - lib/sqreen/kit/signals/specialized/binning_metric.rb
196
+ - lib/sqreen/kit/signals/specialized/http_trace.rb
197
+ - lib/sqreen/kit/signals/specialized/sdk_track_call.rb
198
+ - lib/sqreen/kit/signals/specialized/sqreen_exception.rb
132
199
  - lib/sqreen/legacy.rb
133
200
  - lib/sqreen/legacy/instrumentation.rb
201
+ - lib/sqreen/legacy/old_event_submission_strategy.rb
202
+ - lib/sqreen/legacy/waf_redactions.rb
134
203
  - lib/sqreen/log.rb
135
204
  - lib/sqreen/log/loggable.rb
136
205
  - lib/sqreen/logger.rb
@@ -139,6 +208,7 @@ files:
139
208
  - lib/sqreen/metrics/base.rb
140
209
  - lib/sqreen/metrics/binning.rb
141
210
  - lib/sqreen/metrics/collect.rb
211
+ - lib/sqreen/metrics/req_detailed.rb
142
212
  - lib/sqreen/metrics/sum.rb
143
213
  - lib/sqreen/metrics_store.rb
144
214
  - lib/sqreen/metrics_store/already_registered_metric.rb
@@ -201,6 +271,9 @@ files:
201
271
  - lib/sqreen/shared_storage.rb
202
272
  - lib/sqreen/shared_storage23.rb
203
273
  - lib/sqreen/shrink_wrap.rb
274
+ - lib/sqreen/signals/conversions.rb
275
+ - lib/sqreen/signals/http_trace_redaction.rb
276
+ - lib/sqreen/signals/signals_submission_strategy.rb
204
277
  - lib/sqreen/signature_verifier.rb
205
278
  - lib/sqreen/sinatra_middleware.rb
206
279
  - lib/sqreen/sqreen_signed_verifier.rb
@@ -216,6 +289,7 @@ files:
216
289
  - lib/sqreen/version.rb
217
290
  - lib/sqreen/waf_error.rb
218
291
  - lib/sqreen/weave.rb
292
+ - lib/sqreen/weave/budget.rb
219
293
  - lib/sqreen/weave/hardcoded.rb
220
294
  - lib/sqreen/weave/instrumentor.rb
221
295
  - lib/sqreen/weave/legacy.rb
@@ -238,7 +312,9 @@ metadata:
238
312
  changelog_uri: https://docs.sqreen.com/ruby/release-notes/
239
313
  source_code_uri: https://github.com/sqreen/ruby-agent
240
314
  bug_tracker_uri: https://github.com/sqreen/ruby-agent/issues
241
- post_install_message:
315
+ post_install_message: |2
316
+ This is a Sqreen beta release and may not work in all situations.
317
+ Make sure to review CHANGELOG.md for important details.
242
318
  rdoc_options: []
243
319
  require_paths:
244
320
  - lib
@@ -249,12 +325,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
249
325
  version: 1.9.3
250
326
  required_rubygems_version: !ruby/object:Gem::Requirement
251
327
  requirements:
252
- - - ">="
328
+ - - ">"
253
329
  - !ruby/object:Gem::Version
254
- version: '0'
330
+ version: 1.3.1
255
331
  requirements: []
256
332
  rubyforge_project:
257
- rubygems_version: 2.7.7
333
+ rubygems_version: 2.6.14.1
258
334
  signing_key:
259
335
  specification_version: 4
260
336
  summary: Sqreen Ruby agent
@@ -1,9 +0,0 @@
1
- # typed: strong
2
-
3
- # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
- # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
-
6
- module Sqreen
7
- module Backport
8
- end
9
- end
@@ -1,74 +0,0 @@
1
- # typed: ignore
2
-
3
- # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
- # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
-
6
- require 'sqreen/backport'
7
-
8
- module Sqreen
9
- module Backport
10
- module ClockGettime
11
- class << self
12
- def supported?
13
- Process.respond_to?(:clock_gettime)
14
- end
15
- end
16
-
17
- unless supported?
18
- require 'ffi'
19
-
20
- class Timespec < FFI::Struct
21
- layout :tv_sec => :time_t, :tv_nsec => :long
22
- end
23
-
24
- module LibC
25
- extend FFI::Library
26
- ffi_lib FFI::Library::LIBC
27
-
28
- # TODO: FFI::NotFoundError
29
-
30
- if RUBY_PLATFORM =~ /darwin/
31
- attach_function :mach_absolute_time, [], :uint64
32
- end
33
-
34
- attach_function :clock_gettime, [:int, :pointer], :int
35
- end
36
-
37
- module Constants
38
- case RUBY_PLATFORM
39
- when /darwin/
40
- CLOCK_REALTIME = 0
41
- CLOCK_MONOTONIC = 6
42
- CLOCK_PROCESS_CPUTIME_ID = 12
43
- CLOCK_THERAD_CPUTIME_ID = 16
44
- when /linux/
45
- CLOCK_REALTIME = 0
46
- CLOCK_MONOTONIC = 1
47
- CLOCK_PROCESS_CPUTIME_ID = 2
48
- CLOCK_THREAD_CPUTIME_ID = 3
49
- end
50
- end
51
-
52
- def clock_gettime(clock_id, unit = :float_second)
53
- unless unit == :float_second
54
- raise "Process.clock_gettime: unsupported unit #{unit.inspect}"
55
- end
56
-
57
- t = Timespec.new
58
- ret = LibC.clock_gettime(clock_id, t.pointer)
59
-
60
- raise SystemCallError, "Errno #{FFI.errno}" if ret == -1
61
-
62
- t[:tv_sec].to_f + t[:tv_nsec].to_f / 1_000_000_000
63
- end
64
- end
65
- end
66
- end
67
- end
68
-
69
- unless Sqreen::Backport::ClockGettime.supported?
70
- Process.instance_eval do
71
- extend Sqreen::Backport::ClockGettime
72
- include Sqreen::Backport::ClockGettime::Constants
73
- end
74
- end
@@ -1,88 +0,0 @@
1
- # typed: false
2
-
3
- # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
- # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
-
6
- module Sqreen
7
- module Backport
8
- module OriginalName
9
- HAS_UNBOUND_METHOD_ORIGINAL_NAME = ::UnboundMethod.instance_methods(false).include?(:original_name)
10
- HAS_METHOD_ORIGINAL_NAME = ::Method.instance_methods(false).include?(:original_name)
11
-
12
- def original_name
13
- self.class.get_original_name(owner, original_name_key) || self.original_name = name
14
- end
15
-
16
- private
17
-
18
- def original_name=(name)
19
- self.class.set_original_name(owner, original_name_key, name)
20
- end
21
-
22
- def original_name_key
23
- return hash if is_a?(::UnboundMethod)
24
-
25
- owner.instance_method(name).hash
26
- end
27
-
28
- class << self
29
- def supported?
30
- !::Kernel.const_defined?(:JRUBY_VERSION) && HAS_UNBOUND_METHOD_ORIGINAL_NAME && HAS_METHOD_ORIGINAL_NAME
31
- end
32
-
33
- def included(klass)
34
- klass.extend(ClassMethods)
35
- end
36
-
37
- def prepended(klass)
38
- klass.extend(ClassMethods)
39
- end
40
- end
41
-
42
- class Store < ::Hash; end
43
-
44
- module ClassMethods
45
- def original_names(owner)
46
- owner.instance_eval { @__sqreen_backport_original_names ||= Store.new }
47
- end
48
-
49
- def get_original_name(owner, key)
50
- original_names(owner)[key]
51
- end
52
-
53
- def set_original_name(owner, key, name)
54
- original_names(owner)[key] ||= name
55
- end
56
- end
57
- end
58
- end
59
- end
60
-
61
- class UnboundMethod
62
- if Sqreen::Backport::OriginalName::HAS_UNBOUND_METHOD_ORIGINAL_NAME
63
- prepend Sqreen::Backport::OriginalName
64
- else
65
- include Sqreen::Backport::OriginalName
66
- end
67
- end unless Sqreen::Backport::OriginalName.supported?
68
-
69
- class Method
70
- if Sqreen::Backport::OriginalName::HAS_METHOD_ORIGINAL_NAME
71
- prepend Sqreen::Backport::OriginalName
72
- else
73
- include Sqreen::Backport::OriginalName
74
- end
75
- end unless Sqreen::Backport::OriginalName.supported?
76
-
77
- class Module
78
- alias_method(:alias_method_without_original_name, :alias_method)
79
-
80
- def alias_method_with_original_name(newname, oldname)
81
- alias_method_without_original_name(newname, oldname).tap do
82
- instance_method(newname).send(:original_name=, :"#{oldname}")
83
- end
84
- end
85
-
86
- alias_method_with_original_name(:alias_method_without_original_name, :alias_method)
87
- alias_method_with_original_name(:alias_method, :alias_method_with_original_name)
88
- end unless Sqreen::Backport::OriginalName.supported?
@@ -1,27 +0,0 @@
1
- # typed: true
2
-
3
- # Copyright (c) 2015 Sqreen. All Rights Reserved.
4
- # Please refer to our terms for more information: https://www.sqreen.com/terms.html
5
-
6
- module Sqreen
7
- class EncodingSanitizer
8
- def self.sanitize(obj)
9
- case obj
10
- when String
11
- sanitize_string(obj)
12
- when Array
13
- obj.map { |e| sanitize(e) }
14
- when Hash
15
- obj.each_with_object({}) { |(k, v), h| h[k] = sanitize(v) }
16
- else
17
- obj
18
- end
19
- end
20
-
21
- def self.sanitize_string(s)
22
- return s if s.encoding.name == 'UTF-8' && s.valid_encoding?
23
-
24
- s.encode('UTF-16', :invalid => :replace, :undef => :replace).encode('UTF-8')
25
- end
26
- end
27
- end