honeybadger 5.0.2 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (115) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +713 -701
  3. data/LICENSE +19 -19
  4. data/README.md +57 -57
  5. data/TROUBLESHOOTING.md +3 -3
  6. data/bin/honeybadger +5 -5
  7. data/lib/honeybadger/agent.rb +488 -488
  8. data/lib/honeybadger/backend/base.rb +116 -116
  9. data/lib/honeybadger/backend/debug.rb +22 -22
  10. data/lib/honeybadger/backend/null.rb +29 -29
  11. data/lib/honeybadger/backend/server.rb +62 -62
  12. data/lib/honeybadger/backend/test.rb +46 -46
  13. data/lib/honeybadger/backend.rb +27 -27
  14. data/lib/honeybadger/backtrace.rb +181 -181
  15. data/lib/honeybadger/breadcrumbs/active_support.rb +119 -119
  16. data/lib/honeybadger/breadcrumbs/breadcrumb.rb +53 -53
  17. data/lib/honeybadger/breadcrumbs/collector.rb +82 -82
  18. data/lib/honeybadger/breadcrumbs/logging.rb +51 -51
  19. data/lib/honeybadger/breadcrumbs/ring_buffer.rb +44 -44
  20. data/lib/honeybadger/breadcrumbs.rb +8 -8
  21. data/lib/honeybadger/cli/deploy.rb +43 -43
  22. data/lib/honeybadger/cli/exec.rb +143 -143
  23. data/lib/honeybadger/cli/helpers.rb +28 -28
  24. data/lib/honeybadger/cli/heroku.rb +129 -129
  25. data/lib/honeybadger/cli/install.rb +101 -101
  26. data/lib/honeybadger/cli/main.rb +237 -237
  27. data/lib/honeybadger/cli/notify.rb +67 -67
  28. data/lib/honeybadger/cli/test.rb +267 -267
  29. data/lib/honeybadger/cli.rb +14 -14
  30. data/lib/honeybadger/config/defaults.rb +336 -333
  31. data/lib/honeybadger/config/env.rb +42 -42
  32. data/lib/honeybadger/config/ruby.rb +146 -146
  33. data/lib/honeybadger/config/yaml.rb +76 -76
  34. data/lib/honeybadger/config.rb +413 -413
  35. data/lib/honeybadger/const.rb +20 -20
  36. data/lib/honeybadger/context_manager.rb +55 -55
  37. data/lib/honeybadger/conversions.rb +16 -16
  38. data/lib/honeybadger/init/rails.rb +38 -38
  39. data/lib/honeybadger/init/rake.rb +66 -66
  40. data/lib/honeybadger/init/ruby.rb +11 -11
  41. data/lib/honeybadger/init/sinatra.rb +51 -51
  42. data/lib/honeybadger/logging.rb +177 -177
  43. data/lib/honeybadger/notice.rb +579 -568
  44. data/lib/honeybadger/plugin.rb +210 -210
  45. data/lib/honeybadger/plugins/breadcrumbs.rb +111 -111
  46. data/lib/honeybadger/plugins/delayed_job/plugin.rb +56 -56
  47. data/lib/honeybadger/plugins/delayed_job.rb +22 -22
  48. data/lib/honeybadger/plugins/faktory.rb +52 -52
  49. data/lib/honeybadger/plugins/lambda.rb +71 -71
  50. data/lib/honeybadger/plugins/local_variables.rb +44 -44
  51. data/lib/honeybadger/plugins/passenger.rb +23 -23
  52. data/lib/honeybadger/plugins/rails.rb +72 -63
  53. data/lib/honeybadger/plugins/resque.rb +72 -72
  54. data/lib/honeybadger/plugins/shoryuken.rb +52 -52
  55. data/lib/honeybadger/plugins/sidekiq.rb +71 -62
  56. data/lib/honeybadger/plugins/sucker_punch.rb +18 -18
  57. data/lib/honeybadger/plugins/thor.rb +32 -32
  58. data/lib/honeybadger/plugins/warden.rb +19 -19
  59. data/lib/honeybadger/rack/error_notifier.rb +92 -92
  60. data/lib/honeybadger/rack/user_feedback.rb +88 -88
  61. data/lib/honeybadger/rack/user_informer.rb +45 -45
  62. data/lib/honeybadger/ruby.rb +2 -2
  63. data/lib/honeybadger/singleton.rb +103 -103
  64. data/lib/honeybadger/tasks.rb +22 -22
  65. data/lib/honeybadger/templates/feedback_form.erb +84 -84
  66. data/lib/honeybadger/util/http.rb +92 -92
  67. data/lib/honeybadger/util/lambda.rb +32 -32
  68. data/lib/honeybadger/util/request_hash.rb +73 -73
  69. data/lib/honeybadger/util/request_payload.rb +41 -41
  70. data/lib/honeybadger/util/revision.rb +39 -39
  71. data/lib/honeybadger/util/sanitizer.rb +214 -214
  72. data/lib/honeybadger/util/sql.rb +34 -34
  73. data/lib/honeybadger/util/stats.rb +50 -50
  74. data/lib/honeybadger/version.rb +4 -4
  75. data/lib/honeybadger/worker.rb +253 -253
  76. data/lib/honeybadger.rb +11 -11
  77. data/resources/ca-bundle.crt +3376 -3376
  78. data/vendor/capistrano-honeybadger/lib/capistrano/honeybadger.rb +5 -5
  79. data/vendor/capistrano-honeybadger/lib/capistrano/tasks/deploy.cap +89 -89
  80. data/vendor/capistrano-honeybadger/lib/honeybadger/capistrano/legacy.rb +47 -47
  81. data/vendor/capistrano-honeybadger/lib/honeybadger/capistrano.rb +2 -2
  82. data/vendor/cli/inifile.rb +628 -628
  83. data/vendor/cli/thor/actions/create_file.rb +103 -103
  84. data/vendor/cli/thor/actions/create_link.rb +59 -59
  85. data/vendor/cli/thor/actions/directory.rb +118 -118
  86. data/vendor/cli/thor/actions/empty_directory.rb +135 -135
  87. data/vendor/cli/thor/actions/file_manipulation.rb +316 -316
  88. data/vendor/cli/thor/actions/inject_into_file.rb +107 -107
  89. data/vendor/cli/thor/actions.rb +319 -319
  90. data/vendor/cli/thor/base.rb +656 -656
  91. data/vendor/cli/thor/command.rb +133 -133
  92. data/vendor/cli/thor/core_ext/hash_with_indifferent_access.rb +77 -77
  93. data/vendor/cli/thor/core_ext/io_binary_read.rb +10 -10
  94. data/vendor/cli/thor/core_ext/ordered_hash.rb +98 -98
  95. data/vendor/cli/thor/error.rb +32 -32
  96. data/vendor/cli/thor/group.rb +281 -281
  97. data/vendor/cli/thor/invocation.rb +178 -178
  98. data/vendor/cli/thor/line_editor/basic.rb +35 -35
  99. data/vendor/cli/thor/line_editor/readline.rb +88 -88
  100. data/vendor/cli/thor/line_editor.rb +17 -17
  101. data/vendor/cli/thor/parser/argument.rb +73 -73
  102. data/vendor/cli/thor/parser/arguments.rb +175 -175
  103. data/vendor/cli/thor/parser/option.rb +125 -125
  104. data/vendor/cli/thor/parser/options.rb +218 -218
  105. data/vendor/cli/thor/parser.rb +4 -4
  106. data/vendor/cli/thor/rake_compat.rb +71 -71
  107. data/vendor/cli/thor/runner.rb +322 -322
  108. data/vendor/cli/thor/shell/basic.rb +421 -421
  109. data/vendor/cli/thor/shell/color.rb +149 -149
  110. data/vendor/cli/thor/shell/html.rb +126 -126
  111. data/vendor/cli/thor/shell.rb +81 -81
  112. data/vendor/cli/thor/util.rb +267 -267
  113. data/vendor/cli/thor/version.rb +3 -3
  114. data/vendor/cli/thor.rb +484 -484
  115. metadata +10 -5
@@ -1,41 +1,41 @@
1
- require 'honeybadger/util/sanitizer'
2
-
3
- module Honeybadger
4
- module Util
5
- # Constructs/sanitizes request data for notices
6
- module RequestPayload
7
- # Default values to use for request data.
8
- DEFAULTS = {
9
- url: nil,
10
- component: nil,
11
- action: nil,
12
- params: {}.freeze,
13
- session: {}.freeze,
14
- cgi_data: {}.freeze
15
- }.freeze
16
-
17
- # Allowed keys.
18
- KEYS = DEFAULTS.keys.freeze
19
-
20
- # The cgi_data key where the raw Cookie header is stored.
21
- HTTP_COOKIE_KEY = 'HTTP_COOKIE'.freeze
22
-
23
- def self.build(opts = {})
24
- sanitizer = opts.fetch(:sanitizer) { Sanitizer.new }
25
-
26
- payload = DEFAULTS.dup
27
- KEYS.each do |key|
28
- next unless opts[key]
29
- payload[key] = sanitizer.sanitize(opts[key])
30
- end
31
-
32
- payload[:url] = sanitizer.filter_url(payload[:url]) if payload[:url]
33
- if payload[:cgi_data][HTTP_COOKIE_KEY]
34
- payload[:cgi_data][HTTP_COOKIE_KEY] = sanitizer.filter_cookies(payload[:cgi_data][HTTP_COOKIE_KEY])
35
- end
36
-
37
- payload
38
- end
39
- end
40
- end
41
- end
1
+ require 'honeybadger/util/sanitizer'
2
+
3
+ module Honeybadger
4
+ module Util
5
+ # Constructs/sanitizes request data for notices
6
+ module RequestPayload
7
+ # Default values to use for request data.
8
+ DEFAULTS = {
9
+ url: nil,
10
+ component: nil,
11
+ action: nil,
12
+ params: {}.freeze,
13
+ session: {}.freeze,
14
+ cgi_data: {}.freeze
15
+ }.freeze
16
+
17
+ # Allowed keys.
18
+ KEYS = DEFAULTS.keys.freeze
19
+
20
+ # The cgi_data key where the raw Cookie header is stored.
21
+ HTTP_COOKIE_KEY = 'HTTP_COOKIE'.freeze
22
+
23
+ def self.build(opts = {})
24
+ sanitizer = opts.fetch(:sanitizer) { Sanitizer.new }
25
+
26
+ payload = DEFAULTS.dup
27
+ KEYS.each do |key|
28
+ next unless opts[key]
29
+ payload[key] = sanitizer.sanitize(opts[key])
30
+ end
31
+
32
+ payload[:url] = sanitizer.filter_url(payload[:url]) if payload[:url]
33
+ if payload[:cgi_data][HTTP_COOKIE_KEY]
34
+ payload[:cgi_data][HTTP_COOKIE_KEY] = sanitizer.filter_cookies(payload[:cgi_data][HTTP_COOKIE_KEY])
35
+ end
36
+
37
+ payload
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,39 +1,39 @@
1
- module Honeybadger
2
- module Util
3
- class Revision
4
- class << self
5
- def detect(root = Dir.pwd)
6
- revision = from_heroku ||
7
- from_capistrano(root) ||
8
- from_git
9
-
10
- revision = revision.to_s.strip
11
- return unless revision =~ /\S/
12
-
13
- revision
14
- end
15
-
16
- private
17
-
18
- # Requires (currently) alpha platform feature `heroku labs:enable
19
- # runtime-dyno-metadata`
20
- #
21
- # See https://devcenter.heroku.com/articles/dyno-metadata
22
- def from_heroku
23
- ENV['HEROKU_SLUG_COMMIT']
24
- end
25
-
26
- def from_capistrano(root)
27
- file = File.join(root, 'REVISION')
28
- return nil unless File.file?(file)
29
- File.read(file) rescue nil
30
- end
31
-
32
- def from_git
33
- return nil unless File.directory?('.git')
34
- `git rev-parse HEAD 2> #{File::NULL}` rescue nil
35
- end
36
- end
37
- end
38
- end
39
- end
1
+ module Honeybadger
2
+ module Util
3
+ class Revision
4
+ class << self
5
+ def detect(root = Dir.pwd)
6
+ revision = from_heroku ||
7
+ from_capistrano(root) ||
8
+ from_git
9
+
10
+ revision = revision.to_s.strip
11
+ return unless revision =~ /\S/
12
+
13
+ revision
14
+ end
15
+
16
+ private
17
+
18
+ # Requires (currently) alpha platform feature `heroku labs:enable
19
+ # runtime-dyno-metadata`
20
+ #
21
+ # See https://devcenter.heroku.com/articles/dyno-metadata
22
+ def from_heroku
23
+ ENV['HEROKU_SLUG_COMMIT']
24
+ end
25
+
26
+ def from_capistrano(root)
27
+ file = File.join(root, 'REVISION')
28
+ return nil unless File.file?(file)
29
+ File.read(file) rescue nil
30
+ end
31
+
32
+ def from_git
33
+ return nil unless File.directory?('.git')
34
+ `git rev-parse HEAD 2> #{File::NULL}` rescue nil
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -1,214 +1,214 @@
1
- require 'bigdecimal'
2
- require 'set'
3
-
4
- require 'honeybadger/conversions'
5
-
6
- module Honeybadger
7
- module Util
8
- # Sanitizer sanitizes data for sending to Honeybadger's API. The filters
9
- # are based on Rails' HTTP parameter filter.
10
- class Sanitizer
11
- COOKIE_PAIRS = /[;,]\s?/
12
- COOKIE_SEP = '='.freeze
13
- COOKIE_PAIR_SEP = '; '.freeze
14
-
15
- ENCODE_OPTS = { invalid: :replace, undef: :replace, replace: '?'.freeze }.freeze
16
-
17
- BASIC_OBJECT = '#<BasicObject>'.freeze
18
- DEPTH = '[DEPTH]'.freeze
19
- FILTERED = '[FILTERED]'.freeze
20
- RAISED = '[RAISED]'.freeze
21
- RECURSION = '[RECURSION]'.freeze
22
- TRUNCATED = '[TRUNCATED]'.freeze
23
-
24
- IMMUTABLE = [NilClass, FalseClass, TrueClass, Symbol, Numeric, BigDecimal, Method].freeze
25
-
26
- MAX_STRING_SIZE = 65536
27
-
28
- VALID_ENCODINGS = [Encoding::UTF_8, Encoding::ISO_8859_1].freeze
29
-
30
- def self.sanitize(data)
31
- @sanitizer ||= new
32
- @sanitizer.sanitize(data)
33
- end
34
-
35
- def initialize(max_depth: 20, filters: [])
36
- @filters = !filters.empty?
37
- @max_depth = max_depth
38
-
39
- strings, @regexps, @blocks = [], [], []
40
-
41
- filters.each do |item|
42
- case item
43
- when Proc
44
- @blocks << item
45
- when Regexp
46
- @regexps << item
47
- else
48
- strings << Regexp.escape(item.to_s)
49
- end
50
- end
51
-
52
- @deep_regexps, @regexps = @regexps.partition { |r| r.to_s.include?('\\.'.freeze) }
53
- deep_strings, @strings = strings.partition { |s| s.include?('\\.'.freeze) }
54
-
55
- @regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
56
- @deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
57
- end
58
-
59
- def sanitize(data, depth = 0, stack = nil, parents = [])
60
- return BASIC_OBJECT if basic_object?(data)
61
-
62
- if recursive?(data)
63
- return RECURSION if stack && stack.include?(data.object_id)
64
-
65
- stack = stack ? stack.dup : Set.new
66
- stack << data.object_id
67
- end
68
-
69
- case data
70
- when Hash
71
- return DEPTH if depth >= max_depth
72
-
73
- hash = data.to_hash
74
- new_hash = {}
75
-
76
- hash.each_pair do |key, value|
77
- parents.push(key) if deep_regexps
78
- key = key.kind_of?(Symbol) ? key : sanitize(key, depth+1, stack, parents)
79
-
80
- if filter_key?(key, parents)
81
- new_hash[key] = FILTERED
82
- else
83
- value = sanitize(value, depth+1, stack, parents)
84
-
85
- if blocks.any? && !recursive?(value)
86
- key = key.dup if can_dup?(key)
87
- value = value.dup if can_dup?(value)
88
- blocks.each { |b| b.call(key, value) }
89
- end
90
-
91
- new_hash[key] = value
92
- end
93
-
94
- parents.pop if deep_regexps
95
- end
96
-
97
- new_hash
98
- when Array, Set
99
- return DEPTH if depth >= max_depth
100
-
101
- data.to_a.map do |value|
102
- sanitize(value, depth+1, stack, parents)
103
- end
104
- when Numeric, TrueClass, FalseClass, NilClass
105
- data
106
- when String
107
- sanitize_string(data)
108
- when -> (d) { d.respond_to?(:to_honeybadger) }
109
- return DEPTH if depth >= max_depth
110
-
111
- begin
112
- data = data.to_honeybadger
113
- rescue
114
- return RAISED
115
- end
116
-
117
- sanitize(data, depth+1, stack, parents)
118
- else # all other objects
119
- klass = data.class
120
-
121
- begin
122
- data = String(data)
123
- rescue
124
- return RAISED
125
- end
126
-
127
- return "#<#{klass.name}>" if inspected?(data)
128
-
129
- sanitize_string(data)
130
- end
131
- end
132
-
133
- def filter_cookies(raw_cookies)
134
- return raw_cookies unless filters?
135
-
136
- cookies = []
137
-
138
- raw_cookies.to_s.split(COOKIE_PAIRS).each do |pair|
139
- name, values = pair.split(COOKIE_SEP, 2)
140
- values = FILTERED if filter_key?(name)
141
- cookies << "#{name}=#{values}"
142
- end
143
-
144
- cookies.join(COOKIE_PAIR_SEP)
145
- end
146
-
147
- def filter_url(url)
148
- return url unless filters?
149
-
150
- filtered_url = url.to_s.dup
151
-
152
- filtered_url.scan(/(?:^|&|\?)([^=?&]+)=([^&]+)/).each do |m|
153
- next unless filter_key?(m[0])
154
- filtered_url.gsub!(/#{Regexp.escape(m[1])}/, FILTERED)
155
- end
156
-
157
- filtered_url
158
- end
159
-
160
- private
161
-
162
- attr_reader :max_depth, :regexps, :deep_regexps, :blocks
163
-
164
- def filters?
165
- !!@filters
166
- end
167
-
168
- def filter_key?(key, parents = nil)
169
- return false unless filters?
170
- return true if regexps.any? { |r| key =~ r }
171
- return true if deep_regexps && parents && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
172
- false
173
- end
174
-
175
- def sanitize_string(string)
176
- string = valid_encoding(string)
177
- return string unless string.respond_to?(:size) && string.size > MAX_STRING_SIZE
178
- string[0...MAX_STRING_SIZE] + TRUNCATED
179
- end
180
-
181
- def valid_encoding?(string)
182
- string.valid_encoding? && (
183
- VALID_ENCODINGS.include?(string.encoding) ||
184
- VALID_ENCODINGS.include?(Encoding.compatible?(''.freeze, string))
185
- )
186
- end
187
-
188
- def valid_encoding(string)
189
- return string if valid_encoding?(string)
190
- string.encode(Encoding::UTF_8, **ENCODE_OPTS)
191
- end
192
-
193
- def recursive?(data)
194
- data.is_a?(Hash) || data.is_a?(Array) || data.is_a?(Set) || data.respond_to?(:to_honeybadger)
195
- end
196
-
197
- def basic_object?(object)
198
- object.respond_to?(:to_s)
199
- false
200
- rescue
201
- # BasicObject doesn't respond to `#respond_to?`.
202
- true
203
- end
204
-
205
- def can_dup?(obj)
206
- !IMMUTABLE.any? {|k| obj.kind_of?(k) }
207
- end
208
-
209
- def inspected?(string)
210
- String(string) =~ /#<.*>/
211
- end
212
- end
213
- end
214
- end
1
+ require 'bigdecimal'
2
+ require 'set'
3
+
4
+ require 'honeybadger/conversions'
5
+
6
+ module Honeybadger
7
+ module Util
8
+ # Sanitizer sanitizes data for sending to Honeybadger's API. The filters
9
+ # are based on Rails' HTTP parameter filter.
10
+ class Sanitizer
11
+ COOKIE_PAIRS = /[;,]\s?/
12
+ COOKIE_SEP = '='.freeze
13
+ COOKIE_PAIR_SEP = '; '.freeze
14
+
15
+ ENCODE_OPTS = { invalid: :replace, undef: :replace, replace: '?'.freeze }.freeze
16
+
17
+ BASIC_OBJECT = '#<BasicObject>'.freeze
18
+ DEPTH = '[DEPTH]'.freeze
19
+ FILTERED = '[FILTERED]'.freeze
20
+ RAISED = '[RAISED]'.freeze
21
+ RECURSION = '[RECURSION]'.freeze
22
+ TRUNCATED = '[TRUNCATED]'.freeze
23
+
24
+ IMMUTABLE = [NilClass, FalseClass, TrueClass, Symbol, Numeric, BigDecimal, Method].freeze
25
+
26
+ MAX_STRING_SIZE = 65536
27
+
28
+ VALID_ENCODINGS = [Encoding::UTF_8, Encoding::ISO_8859_1].freeze
29
+
30
+ def self.sanitize(data)
31
+ @sanitizer ||= new
32
+ @sanitizer.sanitize(data)
33
+ end
34
+
35
+ def initialize(max_depth: 20, filters: [])
36
+ @filters = !filters.empty?
37
+ @max_depth = max_depth
38
+
39
+ strings, @regexps, @blocks = [], [], []
40
+
41
+ filters.each do |item|
42
+ case item
43
+ when Proc
44
+ @blocks << item
45
+ when Regexp
46
+ @regexps << item
47
+ else
48
+ strings << Regexp.escape(item.to_s)
49
+ end
50
+ end
51
+
52
+ @deep_regexps, @regexps = @regexps.partition { |r| r.to_s.include?('\\.'.freeze) }
53
+ deep_strings, @strings = strings.partition { |s| s.include?('\\.'.freeze) }
54
+
55
+ @regexps << Regexp.new(strings.join('|'.freeze), true) unless strings.empty?
56
+ @deep_regexps << Regexp.new(deep_strings.join('|'.freeze), true) unless deep_strings.empty?
57
+ end
58
+
59
+ def sanitize(data, depth = 0, stack = nil, parents = [])
60
+ return BASIC_OBJECT if basic_object?(data)
61
+
62
+ if recursive?(data)
63
+ return RECURSION if stack && stack.include?(data.object_id)
64
+
65
+ stack = stack ? stack.dup : Set.new
66
+ stack << data.object_id
67
+ end
68
+
69
+ case data
70
+ when Hash
71
+ return DEPTH if depth >= max_depth
72
+
73
+ hash = data.to_hash
74
+ new_hash = {}
75
+
76
+ hash.each_pair do |key, value|
77
+ parents.push(key) if deep_regexps
78
+ key = key.kind_of?(Symbol) ? key : sanitize(key, depth+1, stack, parents)
79
+
80
+ if filter_key?(key, parents)
81
+ new_hash[key] = FILTERED
82
+ else
83
+ value = sanitize(value, depth+1, stack, parents)
84
+
85
+ if blocks.any? && !recursive?(value)
86
+ key = key.dup if can_dup?(key)
87
+ value = value.dup if can_dup?(value)
88
+ blocks.each { |b| b.call(key, value) }
89
+ end
90
+
91
+ new_hash[key] = value
92
+ end
93
+
94
+ parents.pop if deep_regexps
95
+ end
96
+
97
+ new_hash
98
+ when Array, Set
99
+ return DEPTH if depth >= max_depth
100
+
101
+ data.to_a.map do |value|
102
+ sanitize(value, depth+1, stack, parents)
103
+ end
104
+ when Numeric, TrueClass, FalseClass, NilClass
105
+ data
106
+ when String
107
+ sanitize_string(data)
108
+ when -> (d) { d.respond_to?(:to_honeybadger) }
109
+ return DEPTH if depth >= max_depth
110
+
111
+ begin
112
+ data = data.to_honeybadger
113
+ rescue
114
+ return RAISED
115
+ end
116
+
117
+ sanitize(data, depth+1, stack, parents)
118
+ else # all other objects
119
+ klass = data.class
120
+
121
+ begin
122
+ data = String(data)
123
+ rescue
124
+ return RAISED
125
+ end
126
+
127
+ return "#<#{klass.name}>" if inspected?(data)
128
+
129
+ sanitize_string(data)
130
+ end
131
+ end
132
+
133
+ def filter_cookies(raw_cookies)
134
+ return raw_cookies unless filters?
135
+
136
+ cookies = []
137
+
138
+ raw_cookies.to_s.split(COOKIE_PAIRS).each do |pair|
139
+ name, values = pair.split(COOKIE_SEP, 2)
140
+ values = FILTERED if filter_key?(name)
141
+ cookies << "#{name}=#{values}"
142
+ end
143
+
144
+ cookies.join(COOKIE_PAIR_SEP)
145
+ end
146
+
147
+ def filter_url(url)
148
+ return url unless filters?
149
+
150
+ filtered_url = url.to_s.dup
151
+
152
+ filtered_url.scan(/(?:^|&|\?)([^=?&]+)=([^&]+)/).each do |m|
153
+ next unless filter_key?(m[0])
154
+ filtered_url.gsub!(/#{Regexp.escape(m[1])}/, FILTERED)
155
+ end
156
+
157
+ filtered_url
158
+ end
159
+
160
+ private
161
+
162
+ attr_reader :max_depth, :regexps, :deep_regexps, :blocks
163
+
164
+ def filters?
165
+ !!@filters
166
+ end
167
+
168
+ def filter_key?(key, parents = nil)
169
+ return false unless filters?
170
+ return true if regexps.any? { |r| key =~ r }
171
+ return true if deep_regexps && parents && (joined = parents.join(".")) && deep_regexps.any? { |r| joined =~ r }
172
+ false
173
+ end
174
+
175
+ def sanitize_string(string)
176
+ string = valid_encoding(string)
177
+ return string unless string.respond_to?(:size) && string.size > MAX_STRING_SIZE
178
+ string[0...MAX_STRING_SIZE] + TRUNCATED
179
+ end
180
+
181
+ def valid_encoding?(string)
182
+ string.valid_encoding? && (
183
+ VALID_ENCODINGS.include?(string.encoding) ||
184
+ VALID_ENCODINGS.include?(Encoding.compatible?(''.freeze, string))
185
+ )
186
+ end
187
+
188
+ def valid_encoding(string)
189
+ return string if valid_encoding?(string)
190
+ string.encode(Encoding::UTF_8, **ENCODE_OPTS)
191
+ end
192
+
193
+ def recursive?(data)
194
+ data.is_a?(Hash) || data.is_a?(Array) || data.is_a?(Set) || data.respond_to?(:to_honeybadger)
195
+ end
196
+
197
+ def basic_object?(object)
198
+ object.respond_to?(:to_s)
199
+ false
200
+ rescue
201
+ # BasicObject doesn't respond to `#respond_to?`.
202
+ true
203
+ end
204
+
205
+ def can_dup?(obj)
206
+ !IMMUTABLE.any? {|k| obj.kind_of?(k) }
207
+ end
208
+
209
+ def inspected?(string)
210
+ String(string) =~ /#<.*>/
211
+ end
212
+ end
213
+ end
214
+ end
@@ -1,34 +1,34 @@
1
- module Honeybadger
2
- module Util
3
- class SQL
4
- EscapedQuotes = /(\\"|\\')/.freeze
5
- SQuotedData = /'(?:[^']|'')*'/.freeze
6
- DQuotedData = /"(?:[^"]|"")*"/.freeze
7
- NumericData = /\b\d+\b/.freeze
8
- Newline = /\n/.freeze
9
- Replacement = "?".freeze
10
- EmptyReplacement = "".freeze
11
- DoubleQuoters = /(postgres|sqlite|postgis)/.freeze
12
-
13
- def self.obfuscate(sql, adapter)
14
- force_utf_8(sql.dup).tap do |s|
15
- s.gsub!(EscapedQuotes, EmptyReplacement)
16
- s.gsub!(SQuotedData, Replacement)
17
- s.gsub!(DQuotedData, Replacement) if adapter =~ DoubleQuoters
18
- s.gsub!(NumericData, Replacement)
19
- s.gsub!(Newline, EmptyReplacement)
20
- s.squeeze!(' ')
21
- end
22
- end
23
-
24
- def self.force_utf_8(string)
25
- string.encode(
26
- Encoding.find('UTF-8'),
27
- invalid: :replace,
28
- undef: :replace,
29
- replace: ''
30
- )
31
- end
32
- end
33
- end
34
- end
1
+ module Honeybadger
2
+ module Util
3
+ class SQL
4
+ EscapedQuotes = /(\\"|\\')/.freeze
5
+ SQuotedData = /'(?:[^']|'')*'/.freeze
6
+ DQuotedData = /"(?:[^"]|"")*"/.freeze
7
+ NumericData = /\b\d+\b/.freeze
8
+ Newline = /\n/.freeze
9
+ Replacement = "?".freeze
10
+ EmptyReplacement = "".freeze
11
+ DoubleQuoters = /(postgres|sqlite|postgis)/.freeze
12
+
13
+ def self.obfuscate(sql, adapter)
14
+ force_utf_8(sql.dup).tap do |s|
15
+ s.gsub!(EscapedQuotes, EmptyReplacement)
16
+ s.gsub!(SQuotedData, Replacement)
17
+ s.gsub!(DQuotedData, Replacement) if adapter =~ DoubleQuoters
18
+ s.gsub!(NumericData, Replacement)
19
+ s.gsub!(Newline, EmptyReplacement)
20
+ s.squeeze!(' ')
21
+ end
22
+ end
23
+
24
+ def self.force_utf_8(string)
25
+ string.encode(
26
+ Encoding.find('UTF-8'),
27
+ invalid: :replace,
28
+ undef: :replace,
29
+ replace: ''
30
+ )
31
+ end
32
+ end
33
+ end
34
+ end