rollbar 2.16.2 → 2.22.1

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 (212) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +47 -0
  3. data/.travis.yml +182 -94
  4. data/Appraisals +10 -10
  5. data/Gemfile +45 -13
  6. data/README.md +20 -3
  7. data/Rakefile +0 -0
  8. data/data/rollbar.snippet.js +1 -1
  9. data/docs/configuration.md +15 -0
  10. data/gemfiles/rails30.gemfile +21 -14
  11. data/gemfiles/rails31.gemfile +21 -12
  12. data/gemfiles/rails32.gemfile +18 -8
  13. data/gemfiles/rails40.gemfile +18 -6
  14. data/gemfiles/rails41.gemfile +17 -6
  15. data/gemfiles/rails42.gemfile +24 -14
  16. data/gemfiles/rails50.gemfile +20 -11
  17. data/gemfiles/rails51.gemfile +20 -10
  18. data/gemfiles/rails52.gemfile +65 -0
  19. data/gemfiles/rails60.gemfile +67 -0
  20. data/lib/generators/rollbar/rollbar_generator.rb +1 -1
  21. data/lib/rails/rollbar_runner.rb +17 -2
  22. data/lib/rollbar.rb +2 -3
  23. data/lib/rollbar/capistrano.rb +71 -39
  24. data/lib/rollbar/capistrano3.rb +56 -1
  25. data/lib/rollbar/capistrano_tasks.rb +130 -0
  26. data/lib/rollbar/configuration.rb +95 -7
  27. data/lib/rollbar/delay/active_job.rb +17 -0
  28. data/lib/rollbar/delay/girl_friday.rb +2 -2
  29. data/lib/rollbar/delay/resque.rb +4 -6
  30. data/lib/rollbar/delay/shoryuken.rb +15 -9
  31. data/lib/rollbar/delay/sidekiq.rb +6 -8
  32. data/lib/rollbar/delay/sucker_punch.rb +17 -19
  33. data/lib/rollbar/delay/thread.rb +3 -3
  34. data/lib/rollbar/deploy.rb +90 -0
  35. data/lib/rollbar/encoding/encoder.rb +9 -9
  36. data/lib/rollbar/exception_reporter.rb +19 -5
  37. data/lib/rollbar/item.rb +62 -20
  38. data/lib/rollbar/item/backtrace.rb +4 -4
  39. data/lib/rollbar/item/frame.rb +7 -1
  40. data/lib/rollbar/item/locals.rb +56 -0
  41. data/lib/rollbar/json.rb +5 -51
  42. data/lib/rollbar/language_support.rb +4 -20
  43. data/lib/rollbar/lazy_store.rb +5 -5
  44. data/lib/rollbar/logger.rb +1 -0
  45. data/lib/rollbar/logger_proxy.rb +15 -2
  46. data/lib/rollbar/middleware/js.rb +110 -10
  47. data/lib/rollbar/middleware/js/json_value.rb +26 -0
  48. data/lib/rollbar/middleware/rack.rb +4 -1
  49. data/lib/rollbar/middleware/rails/rollbar.rb +10 -1
  50. data/lib/rollbar/notifier.rb +118 -49
  51. data/lib/rollbar/notifier/trace_with_bindings.rb +65 -0
  52. data/lib/rollbar/plugin.rb +54 -6
  53. data/lib/rollbar/plugins.rb +7 -1
  54. data/lib/rollbar/plugins/active_job.rb +5 -1
  55. data/lib/rollbar/plugins/basic_socket.rb +21 -6
  56. data/lib/rollbar/plugins/delayed_job/job_data.rb +3 -3
  57. data/lib/rollbar/plugins/delayed_job/plugin.rb +3 -3
  58. data/lib/rollbar/plugins/goalie.rb +11 -3
  59. data/lib/rollbar/plugins/rails/controller_methods.rb +17 -4
  60. data/lib/rollbar/plugins/rails/railtie_mixin.rb +7 -3
  61. data/lib/rollbar/plugins/rake.rb +2 -2
  62. data/lib/rollbar/plugins/sidekiq/plugin.rb +10 -6
  63. data/lib/rollbar/rake_tasks.rb +3 -86
  64. data/lib/rollbar/request_data_extractor.rb +35 -21
  65. data/lib/rollbar/rollbar_test.rb +147 -0
  66. data/lib/rollbar/scrubbers.rb +7 -3
  67. data/lib/rollbar/scrubbers/params.rb +38 -20
  68. data/lib/rollbar/scrubbers/url.rb +27 -13
  69. data/lib/rollbar/truncation.rb +9 -2
  70. data/lib/rollbar/truncation/min_body_strategy.rb +2 -3
  71. data/lib/rollbar/truncation/remove_any_key_strategy.rb +123 -0
  72. data/lib/rollbar/truncation/remove_extra_strategy.rb +35 -0
  73. data/lib/rollbar/truncation/remove_request_strategy.rb +21 -0
  74. data/lib/rollbar/truncation/strings_strategy.rb +3 -4
  75. data/lib/rollbar/util.rb +75 -45
  76. data/lib/rollbar/util/hash.rb +30 -6
  77. data/lib/rollbar/util/ip_anonymizer.rb +8 -7
  78. data/lib/rollbar/util/ip_obfuscator.rb +1 -1
  79. data/lib/rollbar/version.rb +1 -1
  80. data/lib/tasks/benchmark.rake +103 -0
  81. data/rollbar.gemspec +14 -8
  82. metadata +25 -277
  83. data/gemfiles/ruby_1_8_and_1_9_2.gemfile +0 -49
  84. data/lib/rollbar/json/default.rb +0 -11
  85. data/lib/rollbar/json/oj.rb +0 -16
  86. data/lib/rollbar/tasks/rollbar.cap +0 -47
  87. data/spec/cacert.pem +0 -3988
  88. data/spec/controllers/home_controller_spec.rb +0 -480
  89. data/spec/delay/sidekiq_spec.rb +0 -61
  90. data/spec/delay/sucker_punch_spec.rb +0 -25
  91. data/spec/delayed/backend/test.rb +0 -140
  92. data/spec/delayed/serialization/test.rb +0 -0
  93. data/spec/dummyapp/.gitignore +0 -73
  94. data/spec/dummyapp/Rakefile +0 -7
  95. data/spec/dummyapp/app/assets/javascripts/application.js +0 -3
  96. data/spec/dummyapp/app/assets/stylesheets/application.css.scss +0 -37
  97. data/spec/dummyapp/app/controllers/application_controller.rb +0 -3
  98. data/spec/dummyapp/app/controllers/home_controller.rb +0 -60
  99. data/spec/dummyapp/app/controllers/users_controller.rb +0 -17
  100. data/spec/dummyapp/app/helpers/.gitkeep +0 -0
  101. data/spec/dummyapp/app/mailers/.gitkeep +0 -0
  102. data/spec/dummyapp/app/models/.gitkeep +0 -0
  103. data/spec/dummyapp/app/models/book.rb +0 -5
  104. data/spec/dummyapp/app/models/post.rb +0 -9
  105. data/spec/dummyapp/app/models/user.rb +0 -9
  106. data/spec/dummyapp/app/views/devise/registrations/edit.html.erb +0 -27
  107. data/spec/dummyapp/app/views/devise/registrations/new.html.erb +0 -20
  108. data/spec/dummyapp/app/views/devise/shared/_links.html.erb +0 -25
  109. data/spec/dummyapp/app/views/home/cause_exception.html.erb +0 -1
  110. data/spec/dummyapp/app/views/home/index.html.erb +0 -4
  111. data/spec/dummyapp/app/views/home/report_exception.html.erb +0 -1
  112. data/spec/dummyapp/app/views/js/test.html.erb +0 -1
  113. data/spec/dummyapp/app/views/layouts/_messages.html.erb +0 -5
  114. data/spec/dummyapp/app/views/layouts/_navigation.html.erb +0 -21
  115. data/spec/dummyapp/app/views/layouts/application.html.erb +0 -25
  116. data/spec/dummyapp/app/views/layouts/simple.html.erb +0 -18
  117. data/spec/dummyapp/app/views/users/index.html.erb +0 -8
  118. data/spec/dummyapp/app/views/users/show.html.erb +0 -3
  119. data/spec/dummyapp/config.ru +0 -4
  120. data/spec/dummyapp/config/application.rb +0 -59
  121. data/spec/dummyapp/config/boot.rb +0 -10
  122. data/spec/dummyapp/config/database.yml +0 -25
  123. data/spec/dummyapp/config/environment.rb +0 -5
  124. data/spec/dummyapp/config/environments/development.rb +0 -37
  125. data/spec/dummyapp/config/environments/production.rb +0 -67
  126. data/spec/dummyapp/config/environments/test.rb +0 -37
  127. data/spec/dummyapp/config/initializers/backtrace_silencers.rb +0 -7
  128. data/spec/dummyapp/config/initializers/inflections.rb +0 -15
  129. data/spec/dummyapp/config/initializers/mime_types.rb +0 -5
  130. data/spec/dummyapp/config/initializers/rollbar.rb +0 -26
  131. data/spec/dummyapp/config/initializers/secret_token.rb +0 -7
  132. data/spec/dummyapp/config/initializers/session_store.rb +0 -8
  133. data/spec/dummyapp/config/initializers/wrap_parameters.rb +0 -16
  134. data/spec/dummyapp/config/locales/devise.en.yml +0 -58
  135. data/spec/dummyapp/config/locales/en.yml +0 -5
  136. data/spec/dummyapp/config/routes.rb +0 -17
  137. data/spec/dummyapp/config/secrets.yml +0 -2
  138. data/spec/dummyapp/db/migrate/20121121184652_devise_create_users.rb +0 -46
  139. data/spec/dummyapp/db/migrate/20121121184654_add_name_to_users.rb +0 -5
  140. data/spec/dummyapp/db/migrate/20161219184410_create_books.rb +0 -10
  141. data/spec/dummyapp/db/migrate/20161219185529_add_username_to_users.rb +0 -5
  142. data/spec/dummyapp/db/schema.rb +0 -41
  143. data/spec/dummyapp/db/seeds.rb +0 -12
  144. data/spec/dummyapp/lib/assets/.gitkeep +0 -0
  145. data/spec/dummyapp/public/404.html +0 -26
  146. data/spec/dummyapp/public/422.html +0 -26
  147. data/spec/dummyapp/public/500.html +0 -25
  148. data/spec/dummyapp/public/favicon.ico +0 -0
  149. data/spec/dummyapp/script/rails +0 -6
  150. data/spec/fixtures/file1 +0 -1
  151. data/spec/fixtures/file2 +0 -1
  152. data/spec/fixtures/payloads/message.json +0 -25
  153. data/spec/fixtures/payloads/sample.trace.json +0 -275
  154. data/spec/fixtures/payloads/sample.trace_chain.json +0 -530
  155. data/spec/fixtures/plugins/dummy1.rb +0 -5
  156. data/spec/fixtures/plugins/dummy2.rb +0 -5
  157. data/spec/generators/rollbar/rollbar_generator_rails30_spec.rb +0 -31
  158. data/spec/generators/rollbar/rollbar_generator_spec.rb +0 -51
  159. data/spec/requests/home_spec.rb +0 -49
  160. data/spec/rollbar/configuration_spec.rb +0 -46
  161. data/spec/rollbar/delay/delayed_job_spec.rb +0 -22
  162. data/spec/rollbar/delay/girl_friday_spec.rb +0 -41
  163. data/spec/rollbar/delay/resque_spec.rb +0 -37
  164. data/spec/rollbar/delay/thread_spec.rb +0 -27
  165. data/spec/rollbar/encoding/encoder_spec.rb +0 -63
  166. data/spec/rollbar/item/backtrace_spec.rb +0 -26
  167. data/spec/rollbar/item/frame_spec.rb +0 -267
  168. data/spec/rollbar/item_spec.rb +0 -736
  169. data/spec/rollbar/json/oj_spec.rb +0 -18
  170. data/spec/rollbar/json_spec.rb +0 -110
  171. data/spec/rollbar/lazy_store_spec.rb +0 -99
  172. data/spec/rollbar/logger_proxy_spec.rb +0 -50
  173. data/spec/rollbar/logger_spec.rb +0 -124
  174. data/spec/rollbar/middleware/js_spec.rb +0 -421
  175. data/spec/rollbar/middleware/sinatra_spec.rb +0 -197
  176. data/spec/rollbar/notifier_spec.rb +0 -56
  177. data/spec/rollbar/plugin_spec.rb +0 -209
  178. data/spec/rollbar/plugins/active_job_spec.rb +0 -38
  179. data/spec/rollbar/plugins/delayed_job/job_data_spec.rb +0 -48
  180. data/spec/rollbar/plugins/delayed_job_spec.rb +0 -129
  181. data/spec/rollbar/plugins/rack_spec.rb +0 -152
  182. data/spec/rollbar/plugins/rails_js_spec.rb +0 -19
  183. data/spec/rollbar/plugins/rake_spec.rb +0 -34
  184. data/spec/rollbar/plugins/resque/failure_spec.rb +0 -36
  185. data/spec/rollbar/plugins/sidekiq_spec.rb +0 -171
  186. data/spec/rollbar/plugins/validations_spec.rb +0 -56
  187. data/spec/rollbar/plugins_spec.rb +0 -68
  188. data/spec/rollbar/request_data_extractor_spec.rb +0 -270
  189. data/spec/rollbar/scrubbers/params_spec.rb +0 -314
  190. data/spec/rollbar/scrubbers/url_spec.rb +0 -136
  191. data/spec/rollbar/scrubbers_spec.rb +0 -31
  192. data/spec/rollbar/sidekig/clear_scope_spec.rb +0 -19
  193. data/spec/rollbar/truncation/frames_strategy_spec.rb +0 -70
  194. data/spec/rollbar/truncation/min_body_strategy_spec.rb +0 -57
  195. data/spec/rollbar/truncation/strings_strategy_spec.rb +0 -89
  196. data/spec/rollbar/truncation_spec.rb +0 -27
  197. data/spec/rollbar/util/hash_spec.rb +0 -22
  198. data/spec/rollbar/util/ip_anonymizer_spec.rb +0 -30
  199. data/spec/rollbar/util_spec.rb +0 -80
  200. data/spec/rollbar_bc_spec.rb +0 -380
  201. data/spec/rollbar_spec.rb +0 -1667
  202. data/spec/spec_helper.rb +0 -84
  203. data/spec/support/cause_exception.rb +0 -1
  204. data/spec/support/encoding_helpers.rb +0 -8
  205. data/spec/support/encodings/iso_8859_9 +0 -1
  206. data/spec/support/fixture_helpers.rb +0 -10
  207. data/spec/support/get_ip_raising.rb +0 -7
  208. data/spec/support/helpers.rb +0 -5
  209. data/spec/support/matchers.rb +0 -23
  210. data/spec/support/notifier_helpers.rb +0 -57
  211. data/spec/support/rollbar_api.rb +0 -57
  212. data/spec/support/shared_contexts.rb +0 -12
@@ -1,5 +1,6 @@
1
1
  # We want to use Gem.path
2
2
  require 'rubygems'
3
+ require 'rollbar/item/locals'
3
4
 
4
5
  module Rollbar
5
6
  class Item
@@ -47,7 +48,8 @@ module Rollbar
47
48
 
48
49
  {
49
50
  :code => code_data(file_lines, lineno),
50
- :context => context_data(file_lines, lineno)
51
+ :context => context_data(file_lines, lineno),
52
+ :locals => locals_data(filename, lineno)
51
53
  }
52
54
  end
53
55
 
@@ -94,6 +96,10 @@ module Rollbar
94
96
  }
95
97
  end
96
98
 
99
+ def locals_data(filename, lineno)
100
+ ::Rollbar::Item::Locals.locals_for_location(filename, lineno)
101
+ end
102
+
97
103
  def post_data(file_lines, lineno)
98
104
  from_line = lineno
99
105
  number_of_lines = [from_line + MAX_CONTEXT_LENGTH, file_lines.size].min - from_line
@@ -0,0 +1,56 @@
1
+ require 'rollbar/notifier'
2
+ require 'rollbar/scrubbers/params'
3
+
4
+ module Rollbar
5
+ class Item
6
+ class Locals # :nodoc:
7
+ class << self
8
+ def exception_frames
9
+ Rollbar.notifier.exception_bindings
10
+ end
11
+
12
+ def locals_for_location(filename, lineno)
13
+ if (frame = frame_for_location(filename, lineno))
14
+ scrub(locals_for(frame[:binding]))
15
+ else
16
+ {}
17
+ end
18
+ end
19
+
20
+ def frame_for_location(filename, lineno)
21
+ while (frame = exception_frames.pop)
22
+ return nil unless frame
23
+ return frame if matching_frame?(frame, filename, lineno)
24
+ end
25
+ nil
26
+ end
27
+
28
+ private
29
+
30
+ def matching_frame?(frame, filename, lineno)
31
+ frame[:path] == filename && frame[:lineno].to_i <= lineno.to_i
32
+ end
33
+
34
+ def locals_for(frame)
35
+ {}.tap do |hash|
36
+ frame.local_variables.map do |var|
37
+ hash[var] = prepare_value(frame.local_variable_get(var))
38
+ end
39
+ end
40
+ end
41
+
42
+ def prepare_value(value)
43
+ value.to_s
44
+ end
45
+
46
+ def scrub(hash)
47
+ Rollbar::Scrubbers::Params.call(
48
+ :params => hash,
49
+ :config => Rollbar.configuration.scrub_fields,
50
+ :whitelist => Rollbar.configuration.scrub_whitelist
51
+ )
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
data/lib/rollbar/json.rb CHANGED
@@ -1,65 +1,19 @@
1
- require 'multi_json'
2
- require 'rollbar/json/oj'
3
- require 'rollbar/json/default'
4
1
  require 'rollbar/language_support'
5
2
 
6
- begin
7
- require 'oj'
8
- rescue LoadError
9
- end
10
-
11
3
  module Rollbar
12
- module JSON
4
+ module JSON # :nodoc:
13
5
  extend self
14
6
 
15
7
  attr_writer :options_module
16
8
 
17
9
  def dump(object)
18
- with_adapter { MultiJson.dump(object, adapter_options) }
19
- end
20
-
21
- def load(string)
22
- with_adapter { MultiJson.load(string, adapter_options) }
23
- end
24
-
25
- def with_adapter(&block)
26
- MultiJson.with_adapter(detect_multi_json_adapter, &block)
27
- end
28
-
29
- def detect_multi_json_adapter
30
- options = {}
31
- options[:adapter] = :oj if defined?(::Oj)
32
-
33
- MultiJson.current_adapter(options)
34
- end
35
-
36
- def adapter_options
37
- options_module.options
38
- end
39
-
40
- def options_module
41
- @options_module ||= find_options_module
42
- end
43
-
44
- def find_options_module
45
- module_name = multi_json_adapter_module_name
46
-
47
- if LanguageSupport.const_defined?(Rollbar::JSON, module_name, false)
48
- LanguageSupport.const_get(Rollbar::JSON, module_name, false)
49
- else
50
- Default
10
+ Rollbar.plugins.get('basic_socket').load_scoped!(true) do
11
+ ::JSON.generate(object)
51
12
  end
52
13
  end
53
14
 
54
- # MultiJson adapters have this name structure:
55
- # "MultiJson::Adapters::{AdapterModule}"
56
- #
57
- # Ex: MultiJson::Adapters::Oj
58
- # Ex: MultiJson::Adapters::JsonGem
59
- #
60
- # In this method we just get the last module name.
61
- def multi_json_adapter_module_name
62
- detect_multi_json_adapter.name[/^MultiJson::Adapters::(.*)$/, 1]
15
+ def load(string)
16
+ ::JSON.parse(string)
63
17
  end
64
18
  end
65
19
  end
@@ -1,29 +1,13 @@
1
1
  module Rollbar
2
2
  module LanguageSupport
3
- extend self
3
+ module_function
4
4
 
5
5
  def const_defined?(mod, target, inherit = true)
6
- if ruby_18?
7
- mod.const_defined?(target)
8
- else
9
- mod.const_defined?(target, inherit)
10
- end
6
+ mod.const_defined?(target, inherit)
11
7
  end
12
8
 
13
9
  def const_get(mod, target, inherit = true)
14
- if ruby_18?
15
- mod.const_get(target)
16
- else
17
- mod.const_get(target, inherit)
18
- end
19
- end
20
-
21
- def can_scrub_url?
22
- !version?('1.8')
23
- end
24
-
25
- def ruby_18?
26
- version?('1.8')
10
+ mod.const_get(target, inherit)
27
11
  end
28
12
 
29
13
  def ruby_19?
@@ -37,7 +21,7 @@ module Rollbar
37
21
  end
38
22
 
39
23
  def timeout_exceptions
40
- return [] if ruby_18? || ruby_19?
24
+ return [] if ruby_19?
41
25
 
42
26
  [Net::ReadTimeout, Net::OpenTimeout]
43
27
  end
@@ -21,11 +21,11 @@ module Rollbar
21
21
  end
22
22
 
23
23
  def ==(other)
24
- if other.is_a?(self.class)
25
- raw == other.raw
26
- else
27
- raw == other
28
- end
24
+ raw == if other.is_a?(self.class)
25
+ other.raw
26
+ else
27
+ other
28
+ end
29
29
  end
30
30
 
31
31
  # With this version of clone we ensure that the loaded_data is empty
@@ -67,6 +67,7 @@ module Rollbar
67
67
 
68
68
  def blank?(message)
69
69
  return message.blank? if message.respond_to?(:blank?)
70
+
70
71
  message.respond_to?(:empty?) ? !!message.empty? : !message
71
72
  end
72
73
 
@@ -23,12 +23,25 @@ module Rollbar
23
23
  end
24
24
 
25
25
  def log(level, message)
26
- return unless Rollbar.configuration.enabled
26
+ return unless Rollbar.configuration.enabled && acceptable_levels.include?(level.to_sym)
27
27
 
28
28
  @object.send(level, message)
29
- rescue
29
+ rescue StandardError
30
30
  puts "[Rollbar] Error logging #{level}:"
31
31
  puts "[Rollbar] #{message}"
32
32
  end
33
+
34
+ protected
35
+
36
+ def acceptable_levels
37
+ @acceptable_levels ||= begin
38
+ levels = [:debug, :info, :warn, :error]
39
+ if Rollbar.configuration.logger_level
40
+ levels[levels.find_index(Rollbar.configuration.logger_level)..-1]
41
+ else
42
+ []
43
+ end
44
+ end
45
+ end
33
46
  end
34
47
  end
@@ -13,7 +13,7 @@ module Rollbar
13
13
  attr_reader :app
14
14
  attr_reader :config
15
15
 
16
- JS_IS_INJECTED_KEY = 'rollbar.js_is_injected'
16
+ JS_IS_INJECTED_KEY = 'rollbar.js_is_injected'.freeze
17
17
  SNIPPET = File.read(File.expand_path('../../../../data/rollbar.snippet.js', __FILE__))
18
18
 
19
19
  def initialize(app, config)
@@ -29,13 +29,15 @@ module Rollbar
29
29
 
30
30
  response_string = add_js(env, app_result[2])
31
31
  build_response(env, app_result, response_string)
32
- rescue => e
32
+ rescue StandardError => e
33
33
  Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
34
34
 
35
35
  app_result
36
36
  end
37
37
  end
38
38
 
39
+ private
40
+
39
41
  def enabled?
40
42
  !!config[:enabled]
41
43
  end
@@ -69,7 +71,7 @@ module Rollbar
69
71
  return nil unless insert_after_idx
70
72
 
71
73
  build_body_with_js(env, body, insert_after_idx)
72
- rescue => e
74
+ rescue StandardError => e
73
75
  Rollbar.log_error("[Rollbar] Rollbar.js could not be added because #{e} exception")
74
76
  nil
75
77
  end
@@ -118,7 +120,11 @@ module Rollbar
118
120
 
119
121
  add_person_data(js_config, env)
120
122
 
121
- script_tag("var _rollbarConfig = #{js_config.to_json};", env)
123
+ # MUST use the Ruby JSON encoder (JSON#generate).
124
+ # See lib/rollbar/middleware/js/json_value
125
+ json = ::JSON.generate(js_config)
126
+
127
+ script_tag("var _rollbarConfig = #{json};", env)
122
128
  end
123
129
 
124
130
  def add_person_data(js_config, env)
@@ -139,7 +145,9 @@ module Rollbar
139
145
  end
140
146
 
141
147
  def script_tag(content, env)
142
- if append_nonce?
148
+ if (nonce = rails5_nonce(env))
149
+ script_tag_content = "\n<script type=\"text/javascript\" nonce=\"#{nonce}\">#{content}</script>"
150
+ elsif secure_headers_nonce?
143
151
  nonce = ::SecureHeaders.content_security_policy_script_nonce(::Rack::Request.new(env))
144
152
  script_tag_content = "\n<script type=\"text/javascript\" nonce=\"#{nonce}\">#{content}</script>"
145
153
  else
@@ -154,11 +162,103 @@ module Rollbar
154
162
  string
155
163
  end
156
164
 
157
- def append_nonce?
158
- defined?(::SecureHeaders) && ::SecureHeaders.respond_to?(:content_security_policy_script_nonce) &&
159
- defined?(::SecureHeaders::Configuration) &&
160
- !::SecureHeaders::Configuration.get.csp.opt_out? &&
161
- !::SecureHeaders::Configuration.get.current_csp[:script_src].to_a.include?("'unsafe-inline'")
165
+ # Rails 5.2 Secure Content Policy
166
+ def rails5_nonce(env)
167
+ # The nonce is the preferred method, however 'unsafe-inline' is also possible.
168
+ # The app gets to decide, so we handle both. If the script_src key is missing,
169
+ # Rails will not add the nonce to the headers, so we should not add it either.
170
+ # If the 'unsafe-inline' value is present, the app should not add a nonce and
171
+ # we should ignore it if they do.
172
+ req = ::ActionDispatch::Request.new env
173
+ req.respond_to?(:content_security_policy) &&
174
+ req.content_security_policy &&
175
+ req.content_security_policy.directives['script-src'] &&
176
+ !req.content_security_policy.directives['script-src'].include?("'unsafe-inline'") &&
177
+ req.content_security_policy_nonce
178
+ end
179
+
180
+ # Secure Headers gem
181
+ def secure_headers_nonce?
182
+ secure_headers.append_nonce?
183
+ end
184
+
185
+ def secure_headers
186
+ return SecureHeadersFalse.new unless defined?(::SecureHeaders::Configuration)
187
+
188
+ config = ::SecureHeaders::Configuration
189
+
190
+ secure_headers_cls = nil
191
+
192
+ secure_headers_cls = if !::SecureHeaders.respond_to?(:content_security_policy_script_nonce)
193
+ SecureHeadersFalse
194
+ elsif config.respond_to?(:get)
195
+ SecureHeaders3To5
196
+ elsif config.dup.respond_to?(:csp)
197
+ SecureHeaders6
198
+ else
199
+ SecureHeadersFalse
200
+ end
201
+
202
+ secure_headers_cls.new
203
+ end
204
+
205
+ class SecureHeadersResolver
206
+ def append_nonce?
207
+ csp_needs_nonce?(find_csp)
208
+ end
209
+
210
+ private
211
+
212
+ def find_csp
213
+ raise NotImplementedError
214
+ end
215
+
216
+ def csp_needs_nonce?(csp)
217
+ !opt_out?(csp) && !unsafe_inline?(csp)
218
+ end
219
+
220
+ def opt_out?(_csp)
221
+ raise NotImplementedError
222
+ end
223
+
224
+ def unsafe_inline?(csp)
225
+ csp[:script_src].to_a.include?("'unsafe-inline'")
226
+ end
227
+ end
228
+
229
+ class SecureHeadersFalse < SecureHeadersResolver
230
+ def append_nonce?
231
+ false
232
+ end
233
+ end
234
+
235
+ class SecureHeaders3To5 < SecureHeadersResolver
236
+ private
237
+
238
+ def find_csp
239
+ ::SecureHeaders::Configuration.get.csp
240
+ end
241
+
242
+ def opt_out?(csp)
243
+ if csp.respond_to?(:opt_out?) && csp.opt_out?
244
+ csp.opt_out?
245
+ # secure_headers csp 3.0.x-3.4.x doesn't respond to 'opt_out?'
246
+ elsif defined?(::SecureHeaders::OPT_OUT) && ::SecureHeaders::OPT_OUT.is_a?(Symbol)
247
+ csp == ::SecureHeaders::OPT_OUT
248
+ end
249
+ end
250
+ end
251
+
252
+ class SecureHeaders6 < SecureHeadersResolver
253
+ private
254
+
255
+ def find_csp
256
+ ::SecureHeaders::Configuration.dup.csp
257
+ end
258
+
259
+ def opt_out?(csp)
260
+ csp.opt_out?
261
+ end
162
262
  end
163
263
  end
164
264
  end
@@ -0,0 +1,26 @@
1
+ # Allows a Ruby String to be used to create native Javascript objects
2
+ # when calling JSON#generate.
3
+ #
4
+ # Example:
5
+ # JSON.generate({ foo: Rollbar::JSON::Value.new('function(){ alert("bar") }') })
6
+ # => '{"foo":function(){ alert(\"bar\") }}'
7
+ #
8
+ # MUST use the Ruby JSON encoder, as in the example. The ActiveSupport encoder,
9
+ # which is installed with Rails, is invoked when calling Hash#to_json and #as_json,
10
+ # and will not work.
11
+ #
12
+ module Rollbar
13
+ module JSON
14
+ class Value # :nodoc:
15
+ attr_accessor :value
16
+
17
+ def initialize(value)
18
+ @value = value
19
+ end
20
+
21
+ def to_json(*_args)
22
+ value
23
+ end
24
+ end
25
+ end
26
+ end