honeybadger 2.0.6 → 2.0.8
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/CHANGELOG.md +16 -0
- data/lib/honeybadger/agent.rb +8 -2
- data/lib/honeybadger/agent/worker.rb +8 -2
- data/lib/honeybadger/cli/helpers.rb +1 -1
- data/lib/honeybadger/cli/main.rb +1 -2
- data/lib/honeybadger/config.rb +7 -1
- data/lib/honeybadger/config/yaml.rb +0 -3
- data/lib/honeybadger/logging.rb +1 -1
- data/lib/honeybadger/notice.rb +44 -36
- data/lib/honeybadger/plugin.rb +2 -2
- data/lib/honeybadger/util/http.rb +0 -5
- data/lib/honeybadger/util/sanitizer.rb +55 -25
- data/lib/honeybadger/version.rb +1 -1
- metadata +2 -3
- data/lib/honeybadger/util/request_sanitizer.rb +0 -35
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f7f7f0ed185071b638c1397c651de08defdd67f
|
4
|
+
data.tar.gz: dc426f168bc4fc433638826c744df12f2f11e137
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 19f26d5077e250b8faee7309504bc93ae568d87f8fb5eed8274a4810181dcb865e6688190bfba68c43cc3ac5dbd405f6ddd9ebc98aacf4e736605386c2a6b943
|
7
|
+
data.tar.gz: 1227af632c510f6255b24766622a921a5f2487d71450453a700db852da47cf4b0991b27b11714b0c71227ce224bd9d55a7701c90596704fdbd81fe405b278c35
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
* Handle bad encodings in exception payloads.
|
2
|
+
|
3
|
+
*Joshua Wood*
|
4
|
+
|
5
|
+
* Include full backtrace when logging worker exceptions.
|
6
|
+
|
7
|
+
*Joshua Wood*
|
8
|
+
|
9
|
+
* Always send a test notice on install.
|
10
|
+
|
11
|
+
*Joshua Wood*
|
12
|
+
|
13
|
+
* Send the id of the current process with error reports.
|
14
|
+
|
15
|
+
*Joshua Wood*
|
16
|
+
|
1
17
|
* Don't sub partial project root in backtrace lines.
|
2
18
|
|
3
19
|
*Joshua Wood*
|
data/lib/honeybadger/agent.rb
CHANGED
@@ -282,7 +282,10 @@ module Honeybadger
|
|
282
282
|
def run
|
283
283
|
loop { work }
|
284
284
|
rescue Exception => e
|
285
|
-
error
|
285
|
+
error {
|
286
|
+
msg = "error in agent thread (shutting down) class=%s message=%s\n\t%s"
|
287
|
+
sprintf(msg, e.class, e.message.dump, Array(e.backtrace).join("\n\t"))
|
288
|
+
}
|
286
289
|
ensure
|
287
290
|
d { sprintf('stopping agent') }
|
288
291
|
end
|
@@ -291,7 +294,10 @@ module Honeybadger
|
|
291
294
|
flush_metrics if metrics.flush?
|
292
295
|
flush_traces if traces.flush?
|
293
296
|
rescue StandardError => e
|
294
|
-
error
|
297
|
+
error {
|
298
|
+
msg = "error in agent thread class=%s message=%s\n\t%s"
|
299
|
+
sprintf(msg, e.class, e.message.dump, Array(e.backtrace).join("\n\t"))
|
300
|
+
}
|
295
301
|
ensure
|
296
302
|
sleep(delay)
|
297
303
|
end
|
@@ -131,7 +131,10 @@ module Honeybadger
|
|
131
131
|
d { sprintf('stopping worker feature=%s', feature) }
|
132
132
|
end
|
133
133
|
rescue Exception => e
|
134
|
-
error
|
134
|
+
error {
|
135
|
+
msg = "error in worker thread (shutting down) feature=%s class=%s message=%s\n\t%s"
|
136
|
+
sprintf(msg, feature, e.class, e.message.dump, Array(e.backtrace).join("\n\t"))
|
137
|
+
}
|
135
138
|
ensure
|
136
139
|
release_marker
|
137
140
|
end
|
@@ -140,7 +143,10 @@ module Honeybadger
|
|
140
143
|
handle_response(notify_backend(msg))
|
141
144
|
sleep(throttle_interval)
|
142
145
|
rescue StandardError => e
|
143
|
-
error
|
146
|
+
error {
|
147
|
+
msg = "error in worker thread feature=%s class=%s message=%s\n\t%s"
|
148
|
+
sprintf(msg, feature, e.class, e.message.dump, Array(e.backtrace).join("\n\t"))
|
149
|
+
}
|
144
150
|
sleep(1)
|
145
151
|
end
|
146
152
|
|
@@ -125,7 +125,7 @@ module Honeybadger
|
|
125
125
|
|
126
126
|
def test_honeybadger
|
127
127
|
puts "Raising '#{test_exception_class.name}' to simulate application failure."
|
128
|
-
raise #{test_exception_class}.new, 'Testing honeybadger via "honeybadger
|
128
|
+
raise #{test_exception_class}.new, 'Testing honeybadger via "honeybadger test", it works.'
|
129
129
|
end
|
130
130
|
|
131
131
|
# Ensure we actually have an action to go to.
|
data/lib/honeybadger/cli/main.rb
CHANGED
@@ -127,7 +127,6 @@ module Honeybadger
|
|
127
127
|
|
128
128
|
if (path = config.config_path).exist?
|
129
129
|
say("You're already on Honeybadger, so you're all set.", :yellow)
|
130
|
-
skip_test = true if options[:test].nil? # Only if it wasn't specified.
|
131
130
|
else
|
132
131
|
say("Writing configuration to: #{path}", :yellow)
|
133
132
|
|
@@ -153,7 +152,7 @@ module Honeybadger
|
|
153
152
|
end
|
154
153
|
end
|
155
154
|
|
156
|
-
if
|
155
|
+
if options[:test].nil? || options[:test]
|
157
156
|
Honeybadger.start(config) unless load_rails_env(verbose: true)
|
158
157
|
say('Sending test notice', :yellow)
|
159
158
|
unless Agent.instance && send_test(false)
|
data/lib/honeybadger/config.rb
CHANGED
@@ -352,7 +352,13 @@ api_key: '#{self[:api_key]}'
|
|
352
352
|
end
|
353
353
|
end
|
354
354
|
rescue ConfigError => e
|
355
|
-
|
355
|
+
error("error while loading config from disk: #{e}")
|
356
|
+
nil
|
357
|
+
rescue StandardError => e
|
358
|
+
error {
|
359
|
+
msg = "error while loading config from disk class=%s message=%s\n\t%s"
|
360
|
+
sprintf(msg, e.class, e.message.dump, Array(e.backtrace).join("\n\t"))
|
361
|
+
}
|
356
362
|
nil
|
357
363
|
end
|
358
364
|
|
@@ -19,9 +19,6 @@ module Honeybadger
|
|
19
19
|
yaml.merge!(yaml[env]) if yaml[env].kind_of?(Hash)
|
20
20
|
update(dotify_keys(yaml))
|
21
21
|
end
|
22
|
-
|
23
|
-
rescue StandardError => e
|
24
|
-
raise ConfigError, "An unknown error occured: #{e.class} -- #{e.message}\n\t#{e.backtrace.first}"
|
25
22
|
end
|
26
23
|
|
27
24
|
private
|
data/lib/honeybadger/logging.rb
CHANGED
data/lib/honeybadger/notice.rb
CHANGED
@@ -7,7 +7,6 @@ require 'honeybadger/version'
|
|
7
7
|
require 'honeybadger/backtrace'
|
8
8
|
require 'honeybadger/util/stats'
|
9
9
|
require 'honeybadger/util/sanitizer'
|
10
|
-
require 'honeybadger/util/request_sanitizer'
|
11
10
|
require 'honeybadger/rack/request_hash'
|
12
11
|
|
13
12
|
module Honeybadger
|
@@ -132,10 +131,12 @@ module Honeybadger
|
|
132
131
|
|
133
132
|
def initialize(config, opts = {})
|
134
133
|
@now = Time.now.utc
|
134
|
+
@pid = Process.pid
|
135
135
|
@id = SecureRandom.uuid
|
136
136
|
|
137
137
|
@opts = opts
|
138
138
|
@config = config
|
139
|
+
@sanitizer = Util::Sanitizer.new(filters: config.params_filters)
|
139
140
|
|
140
141
|
@exception = opts[:exception]
|
141
142
|
@error_class = exception_attribute(:error_class) {|exception| exception.class.name }
|
@@ -148,10 +149,9 @@ module Honeybadger
|
|
148
149
|
@source = extract_source_from_backtrace(@backtrace, config, opts)
|
149
150
|
@fingerprint = construct_fingerprint(opts)
|
150
151
|
|
151
|
-
@
|
152
|
-
|
153
|
-
@
|
154
|
-
@context = construct_context_hash(opts, @sanitizer)
|
152
|
+
@request = OpenStruct.new(construct_request_hash(config.request, opts, config.excluded_request_keys))
|
153
|
+
|
154
|
+
@context = construct_context_hash(opts)
|
155
155
|
|
156
156
|
@causes = unwrap_causes(opts[:exception])
|
157
157
|
|
@@ -160,7 +160,7 @@ module Honeybadger
|
|
160
160
|
|
161
161
|
@stats = Util::Stats.all
|
162
162
|
|
163
|
-
@local_variables = local_variables_from_exception(exception, config
|
163
|
+
@local_variables = local_variables_from_exception(exception, config)
|
164
164
|
|
165
165
|
@api_key = opts[:api_key] || config[:api_key]
|
166
166
|
|
@@ -172,34 +172,35 @@ module Honeybadger
|
|
172
172
|
# Returns Hash JSON representation of notice
|
173
173
|
def as_json(*args)
|
174
174
|
{
|
175
|
-
api_key: api_key,
|
175
|
+
api_key: s(api_key),
|
176
176
|
notifier: NOTIFIER,
|
177
177
|
error: {
|
178
178
|
token: id,
|
179
|
-
class: error_class,
|
180
|
-
message: error_message,
|
181
|
-
backtrace: backtrace,
|
182
|
-
source: source,
|
183
|
-
fingerprint: fingerprint,
|
184
|
-
tags: tags,
|
185
|
-
causes: causes
|
179
|
+
class: s(error_class),
|
180
|
+
message: s(error_message),
|
181
|
+
backtrace: s(backtrace),
|
182
|
+
source: s(source),
|
183
|
+
fingerprint: s(fingerprint),
|
184
|
+
tags: s(tags),
|
185
|
+
causes: s(causes)
|
186
186
|
},
|
187
187
|
request: {
|
188
|
-
url:
|
189
|
-
component: component,
|
190
|
-
action: action,
|
191
|
-
params: params,
|
192
|
-
session: session,
|
193
|
-
cgi_data: cgi_data,
|
194
|
-
context: context,
|
195
|
-
local_variables: local_variables
|
188
|
+
url: sanitized_url,
|
189
|
+
component: s(component),
|
190
|
+
action: s(action),
|
191
|
+
params: s(params),
|
192
|
+
session: s(session),
|
193
|
+
cgi_data: s(cgi_data),
|
194
|
+
context: s(context),
|
195
|
+
local_variables: s(local_variables)
|
196
196
|
},
|
197
197
|
server: {
|
198
|
-
project_root: config[:root],
|
199
|
-
environment_name: config[:env],
|
200
|
-
hostname: config[:hostname],
|
198
|
+
project_root: s(config[:root]),
|
199
|
+
environment_name: s(config[:env]),
|
200
|
+
hostname: s(config[:hostname]),
|
201
201
|
stats: stats,
|
202
|
-
time: now
|
202
|
+
time: now,
|
203
|
+
pid: pid
|
203
204
|
}
|
204
205
|
}
|
205
206
|
end
|
@@ -208,7 +209,7 @@ module Honeybadger
|
|
208
209
|
#
|
209
210
|
# Returns valid JSON representation of Notice
|
210
211
|
def to_json(*a)
|
211
|
-
|
212
|
+
::JSON.generate(as_json(*a))
|
212
213
|
end
|
213
214
|
|
214
215
|
# Public: Allows properties to be accessed using a hash-like syntax
|
@@ -236,7 +237,7 @@ module Honeybadger
|
|
236
237
|
|
237
238
|
private
|
238
239
|
|
239
|
-
attr_reader :config, :opts, :context, :stats, :api_key, :now, :causes
|
240
|
+
attr_reader :config, :opts, :context, :stats, :api_key, :now, :pid, :causes, :sanitizer
|
240
241
|
|
241
242
|
def ignore_by_origin?
|
242
243
|
opts[:origin] == :rake && !config[:'exceptions.rescue_rake']
|
@@ -328,7 +329,7 @@ module Honeybadger
|
|
328
329
|
].compact | BACKTRACE_FILTERS
|
329
330
|
end
|
330
331
|
|
331
|
-
def construct_request_hash(rack_request, opts,
|
332
|
+
def construct_request_hash(rack_request, opts, excluded_keys = [])
|
332
333
|
request = {}
|
333
334
|
request.merge!(Rack::RequestHash.new(rack_request)) if rack_request
|
334
335
|
|
@@ -342,14 +343,14 @@ module Honeybadger
|
|
342
343
|
|
343
344
|
request[:session] = request[:session][:data] if request[:session][:data]
|
344
345
|
|
345
|
-
|
346
|
+
request
|
346
347
|
end
|
347
348
|
|
348
|
-
def construct_context_hash(opts
|
349
|
+
def construct_context_hash(opts)
|
349
350
|
context = {}
|
350
351
|
context.merge!(Thread.current[:__honeybadger_context]) if Thread.current[:__honeybadger_context]
|
351
352
|
context.merge!(opts[:context]) if opts[:context]
|
352
|
-
context.empty? ? nil :
|
353
|
+
context.empty? ? nil : context
|
353
354
|
end
|
354
355
|
|
355
356
|
def extract_source_from_backtrace(backtrace, config, opts)
|
@@ -401,12 +402,21 @@ module Honeybadger
|
|
401
402
|
ret
|
402
403
|
end
|
403
404
|
|
405
|
+
def s(data)
|
406
|
+
sanitizer.sanitize(data)
|
407
|
+
end
|
408
|
+
|
409
|
+
def sanitized_url
|
410
|
+
return nil unless url
|
411
|
+
sanitizer.filter_url(s(url))
|
412
|
+
end
|
413
|
+
|
404
414
|
# Internal: Fetch local variables from first frame of backtrace.
|
405
415
|
#
|
406
416
|
# exception - The Exception containing the bindings stack.
|
407
417
|
#
|
408
418
|
# Returns a Hash of local variables
|
409
|
-
def local_variables_from_exception(exception, config
|
419
|
+
def local_variables_from_exception(exception, config)
|
410
420
|
return {} unless send_local_variables?(config)
|
411
421
|
return {} unless Exception === exception
|
412
422
|
return {} unless exception.respond_to?(:__honeybadger_bindings_stack)
|
@@ -419,9 +429,7 @@ module Honeybadger
|
|
419
429
|
binding ||= exception.__honeybadger_bindings_stack[0]
|
420
430
|
|
421
431
|
vars = binding.eval('local_variables')
|
422
|
-
|
423
|
-
|
424
|
-
sanitizer.sanitize(h)
|
432
|
+
Hash[vars.map {|arg| [arg, binding.eval(arg.to_s)]}]
|
425
433
|
end
|
426
434
|
|
427
435
|
# Internal: Should local variables be sent?
|
data/lib/honeybadger/plugin.rb
CHANGED
@@ -71,7 +71,7 @@ module Honeybadger
|
|
71
71
|
def ok?(config)
|
72
72
|
@requirements.all? {|r| Execution.new(config, &r).call }
|
73
73
|
rescue => e
|
74
|
-
config.logger.error(sprintf(
|
74
|
+
config.logger.error(sprintf("plugin error name=%s class=%s message=%s\n\t%s", name, e.class, e.message.dump, Array(e.backtrace).join("\n\t")))
|
75
75
|
false
|
76
76
|
end
|
77
77
|
|
@@ -89,7 +89,7 @@ module Honeybadger
|
|
89
89
|
|
90
90
|
@loaded
|
91
91
|
rescue => e
|
92
|
-
config.logger.error(sprintf(
|
92
|
+
config.logger.error(sprintf("plugin error name=%s class=%s message=%s\n\t%s", name, e.class, e.message.dump, Array(e.backtrace).join("\n\t")))
|
93
93
|
@loaded = true
|
94
94
|
false
|
95
95
|
end
|
@@ -3,41 +3,46 @@ module Honeybadger
|
|
3
3
|
class Sanitizer
|
4
4
|
OBJECT_WHITELIST = [Hash, Array, String, Integer, Float, TrueClass, FalseClass, NilClass]
|
5
5
|
|
6
|
+
FILTERED_REPLACEMENT = '[FILTERED]'.freeze
|
7
|
+
|
6
8
|
def initialize(opts = {})
|
7
|
-
@max_depth = opts
|
8
|
-
@filters = Array(opts
|
9
|
+
@max_depth = opts.fetch(:max_depth, 20)
|
10
|
+
@filters = Array(opts.fetch(:filters, nil)).collect do |f|
|
11
|
+
f.kind_of?(Regexp) ? f : f.to_s
|
12
|
+
end
|
9
13
|
end
|
10
14
|
|
11
|
-
|
12
|
-
|
13
|
-
|
15
|
+
def sanitize(data, depth = 0, stack = nil)
|
16
|
+
if recursive?(data)
|
17
|
+
return '[possible infinite recursion halted]' if stack && stack.include?(data.object_id)
|
18
|
+
stack = stack ? stack.dup : Set.new
|
19
|
+
stack << data.object_id
|
20
|
+
end
|
14
21
|
|
15
|
-
if data.
|
22
|
+
if data.kind_of?(String)
|
23
|
+
sanitize_string(data)
|
24
|
+
elsif data.respond_to?(:to_hash)
|
16
25
|
return '[max depth reached]' if depth >= max_depth
|
17
|
-
data.to_hash
|
18
|
-
|
26
|
+
hash = data.to_hash
|
27
|
+
new_hash = {}
|
28
|
+
hash.each_pair do |key, value|
|
29
|
+
k = key.kind_of?(Symbol) ? key : sanitize(key, depth+1, stack)
|
30
|
+
if filter_key?(k)
|
31
|
+
new_hash[k] = FILTERED_REPLACEMENT
|
32
|
+
else
|
33
|
+
new_hash[k] = sanitize(value, depth+1, stack)
|
34
|
+
end
|
19
35
|
end
|
36
|
+
new_hash
|
20
37
|
elsif data.respond_to?(:to_ary)
|
21
38
|
return '[max depth reached]' if depth >= max_depth
|
22
|
-
data.to_ary.
|
23
|
-
sanitize(value, depth+1, stack
|
24
|
-
end
|
39
|
+
data.to_ary.map do |value|
|
40
|
+
sanitize(value, depth+1, stack)
|
41
|
+
end.compact
|
25
42
|
elsif OBJECT_WHITELIST.any? {|c| data.kind_of?(c) }
|
26
43
|
data
|
27
44
|
else
|
28
|
-
data.to_s
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
def filter(hash)
|
33
|
-
{}.tap do |filtered_hash|
|
34
|
-
hash.each_pair do |key, value|
|
35
|
-
if value.respond_to?(:to_hash)
|
36
|
-
filtered_hash[key] = filter(hash[key])
|
37
|
-
else
|
38
|
-
filtered_hash[key] = filter_key?(key) ? '[FILTERED]' : hash[key]
|
39
|
-
end
|
40
|
-
end
|
45
|
+
sanitize_string(data.to_s)
|
41
46
|
end
|
42
47
|
end
|
43
48
|
|
@@ -53,19 +58,44 @@ module Honeybadger
|
|
53
58
|
|
54
59
|
private
|
55
60
|
|
61
|
+
VALID_ENCODINGS = [Encoding::UTF_8, Encoding::ISO_8859_1].freeze
|
62
|
+
ENCODE_OPTS = { invalid: :replace, undef: :replace, replace: '?'.freeze }.freeze
|
63
|
+
UTF8_STRING = ''.freeze
|
64
|
+
|
56
65
|
attr_reader :max_depth, :filters
|
57
66
|
|
67
|
+
def recursive?(data)
|
68
|
+
data.respond_to?(:to_hash) || data.respond_to?(:to_ary)
|
69
|
+
end
|
70
|
+
|
58
71
|
def filter_key?(key)
|
59
72
|
return false unless filters
|
60
73
|
|
61
74
|
filters.any? do |filter|
|
62
75
|
if filter.is_a?(Regexp)
|
63
|
-
key.to_s
|
76
|
+
filter =~ key.to_s
|
64
77
|
else
|
65
78
|
key.to_s.eql?(filter.to_s)
|
66
79
|
end
|
67
80
|
end
|
68
81
|
end
|
82
|
+
|
83
|
+
def valid_encoding?(data)
|
84
|
+
data.valid_encoding? && (
|
85
|
+
VALID_ENCODINGS.include?(data.encoding) ||
|
86
|
+
VALID_ENCODINGS.include?(Encoding.compatible?(UTF8_STRING, data))
|
87
|
+
)
|
88
|
+
end
|
89
|
+
|
90
|
+
def sanitize_string(data)
|
91
|
+
return data if valid_encoding?(data)
|
92
|
+
|
93
|
+
if data.encoding == Encoding::UTF_8
|
94
|
+
data.encode(Encoding::UTF_16, ENCODE_OPTS).encode!(Encoding::UTF_8)
|
95
|
+
else
|
96
|
+
data.encode(Encoding::UTF_8, ENCODE_OPTS)
|
97
|
+
end
|
98
|
+
end
|
69
99
|
end
|
70
100
|
end
|
71
101
|
end
|
data/lib/honeybadger/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: honeybadger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.
|
4
|
+
version: 2.0.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Honeybadger Industries LLC
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-03-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Make managing application errors a more pleasant experience.
|
14
14
|
email:
|
@@ -73,7 +73,6 @@ files:
|
|
73
73
|
- lib/honeybadger/templates/feedback_form.erb
|
74
74
|
- lib/honeybadger/trace.rb
|
75
75
|
- lib/honeybadger/util/http.rb
|
76
|
-
- lib/honeybadger/util/request_sanitizer.rb
|
77
76
|
- lib/honeybadger/util/sanitizer.rb
|
78
77
|
- lib/honeybadger/util/stats.rb
|
79
78
|
- lib/honeybadger/version.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Honeybadger
|
2
|
-
module Util
|
3
|
-
class RequestSanitizer
|
4
|
-
|
5
|
-
def initialize(sanitizer)
|
6
|
-
@sanitizer = sanitizer
|
7
|
-
end
|
8
|
-
|
9
|
-
def sanitize(request_hash)
|
10
|
-
request_hash.merge({
|
11
|
-
url: sanitize_url(request_hash[:url]),
|
12
|
-
component: request_hash[:component],
|
13
|
-
action: request_hash[:action],
|
14
|
-
params: sanitize_hash(request_hash[:params]),
|
15
|
-
session: sanitize_hash(request_hash[:session]),
|
16
|
-
cgi_data: sanitize_hash(request_hash[:cgi_data])
|
17
|
-
})
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def sanitize_url(url)
|
23
|
-
if url
|
24
|
-
@sanitizer.filter_url(url)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def sanitize_hash(hash)
|
29
|
-
if hash
|
30
|
-
@sanitizer.filter(@sanitizer.sanitize(hash))
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|