better_errors 2.9.1 → 2.10.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4526a605f0982bee6fd507b813eca6e7185bad35bd14ecd289a0a269afe4ec5e
4
- data.tar.gz: 897e7c5a8fd3350b6cba2b1e46feccb872ed519d45d169dbbde9e6ab1c7387ad
3
+ metadata.gz: 2ae6237f9bcc8bc7bea85082f32a5dff2dfd4ad519f9b5cb23602801c27f3a10
4
+ data.tar.gz: e74a98ed16de6ce6d2862fe55f7094b1608250bbf51ac98b52e4f558f328dfab
5
5
  SHA512:
6
- metadata.gz: 6e9116392957f7941b7217a1e08226587081d55904c6e4722d7af28aba0e47d376f886702e958db5f7d02dfaf1480fe686af154fdf500ff817a67e46c5144a30
7
- data.tar.gz: ad5453cf355f951ad5db132454934ebe5efbdfc339f4607985d76ddb9f430a06c55e95dbffdf944ce33c63b344d4a0ef632176d4b3da00d4db4f3561c02acf39
6
+ metadata.gz: 53944fa785d9f6dd22bc07db577f6b3a4bfd3b30f4ea87eabcd492358545c629eefb401b0b86936ab87da2b39587f26e85ef99232e18fd6df54d5c6ea8e0f489
7
+ data.tar.gz: 186f51a6e6146153fbd8a9ebaa419be6db36dce42b52ecaa50ecd48525b2a4181ab0aed0f87b6608d2b9ca67d3f736c44857c6ba8c4a142ca7be022da762531e
@@ -31,16 +31,19 @@ jobs:
31
31
  - rails51
32
32
  - rails52
33
33
  - rails60
34
+ - rails61
34
35
  - rails42_haml
35
36
  - rails50_haml
36
37
  - rails51_haml
37
38
  - rails52_haml
38
39
  - rails60_haml
40
+ - rails61_haml
39
41
  - rails42_boc
40
42
  - rails50_boc
41
43
  - rails51_boc
42
44
  - rails52_boc
43
45
  - rails60_boc
46
+ - rails61_boc
44
47
  - rack
45
48
  - rack_boc
46
49
  # - pry09
@@ -50,18 +53,27 @@ jobs:
50
53
  - { ruby: 2.2, gemfile: rails60 }
51
54
  - { ruby: 2.2, gemfile: rails60_boc }
52
55
  - { ruby: 2.2, gemfile: rails60_haml }
56
+ - { ruby: 2.2, gemfile: rails61 }
57
+ - { ruby: 2.2, gemfile: rails61_boc }
58
+ - { ruby: 2.2, gemfile: rails61_haml }
53
59
  - { ruby: 2.3, gemfile: rails42 }
54
60
  - { ruby: 2.3, gemfile: rails42_boc }
55
61
  - { ruby: 2.3, gemfile: rails42_haml }
56
62
  - { ruby: 2.3, gemfile: rails60 }
57
63
  - { ruby: 2.3, gemfile: rails60_boc }
58
64
  - { ruby: 2.3, gemfile: rails60_haml }
65
+ - { ruby: 2.3, gemfile: rails61 }
66
+ - { ruby: 2.3, gemfile: rails61_boc }
67
+ - { ruby: 2.3, gemfile: rails61_haml }
59
68
  - { ruby: 2.4, gemfile: rails42 }
60
69
  - { ruby: 2.4, gemfile: rails42_boc }
61
70
  - { ruby: 2.4, gemfile: rails42_haml }
62
71
  - { ruby: 2.4, gemfile: rails60 }
63
72
  - { ruby: 2.4, gemfile: rails60_boc }
64
73
  - { ruby: 2.4, gemfile: rails60_haml }
74
+ - { ruby: 2.4, gemfile: rails61 }
75
+ - { ruby: 2.4, gemfile: rails61_boc }
76
+ - { ruby: 2.4, gemfile: rails61_haml }
65
77
  - { ruby: 2.5, gemfile: rails42 }
66
78
  - { ruby: 2.5, gemfile: rails42_boc }
67
79
  - { ruby: 2.5, gemfile: rails42_haml }
@@ -0,0 +1,8 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.1.0rc"
4
+
5
+ gem 'simplecov', require: false
6
+ gem 'simplecov-lcov', require: false
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.1.0rc"
4
+ gem "binding_of_caller"
5
+
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
8
+
9
+ gemspec path: "../"
@@ -0,0 +1,9 @@
1
+ source "https://rubygems.org"
2
+
3
+ gem "rails", "~> 6.1.0rc"
4
+ gem "haml"
5
+
6
+ gem 'simplecov', require: false
7
+ gem 'simplecov-lcov', require: false
8
+
9
+ gemspec path: "../"
@@ -84,6 +84,10 @@ module BetterErrors
84
84
  url_proc.call(file, line)
85
85
  end
86
86
 
87
+ def scheme
88
+ url('/fake', 42).sub(/:.*/, ':')
89
+ end
90
+
87
91
  private
88
92
 
89
93
  attr_reader :url_proc
@@ -5,6 +5,8 @@ require "securerandom"
5
5
  module BetterErrors
6
6
  # @private
7
7
  class ErrorPage
8
+ VariableInfo = Struct.new(:frame, :editor_url, :rails_params, :rack_session, :start_time)
9
+
8
10
  def self.template_path(template_name)
9
11
  File.expand_path("../templates/#{template_name}.erb", __FILE__)
10
12
  end
@@ -13,6 +15,15 @@ module BetterErrors
13
15
  Erubi::Engine.new(File.read(template_path(template_name)), escape: true)
14
16
  end
15
17
 
18
+ def self.render_template(template_name, locals)
19
+ locals.send(:eval, self.template(template_name).src)
20
+ rescue => e
21
+ # Fix the backtrace, which doesn't identify the template that failed (within Better Errors).
22
+ # We don't know the line number, so just injecting the template path has to be enough.
23
+ e.backtrace.unshift "#{self.template_path(template_name)}:0"
24
+ raise
25
+ end
26
+
16
27
  attr_reader :exception, :env, :repls
17
28
 
18
29
  def initialize(exception, env)
@@ -26,20 +37,21 @@ module BetterErrors
26
37
  @id ||= SecureRandom.hex(8)
27
38
  end
28
39
 
29
- def render(template_name = "main", csrf_token = nil)
30
- binding.eval(self.class.template(template_name).src)
31
- rescue => e
32
- # Fix the backtrace, which doesn't identify the template that failed (within Better Errors).
33
- # We don't know the line number, so just injecting the template path has to be enough.
34
- e.backtrace.unshift "#{self.class.template_path(template_name)}:0"
35
- raise
40
+ def render_main(csrf_token, csp_nonce)
41
+ frame = backtrace_frames[0]
42
+ first_frame_variable_info = VariableInfo.new(frame, editor_url(frame), rails_params, rack_session, Time.now.to_f)
43
+ self.class.render_template('main', binding)
44
+ end
45
+
46
+ def render_text
47
+ self.class.render_template('text', binding)
36
48
  end
37
49
 
38
50
  def do_variables(opts)
39
51
  index = opts["index"].to_i
40
- @frame = backtrace_frames[index]
41
- @var_start_time = Time.now.to_f
42
- { html: render("variable_info") }
52
+ frame = backtrace_frames[index]
53
+ variable_info = VariableInfo.new(frame, editor_url(frame), rails_params, rack_session, Time.now.to_f)
54
+ { html: self.class.render_template("variable_info", variable_info) }
43
55
  end
44
56
 
45
57
  def do_eval(opts)
@@ -113,11 +125,11 @@ module BetterErrors
113
125
  env["PATH_INFO"]
114
126
  end
115
127
 
116
- def html_formatted_code_block(frame)
128
+ def self.html_formatted_code_block(frame)
117
129
  CodeFormatter::HTML.new(frame.filename, frame.line).output
118
130
  end
119
131
 
120
- def text_formatted_code_block(frame)
132
+ def self.text_formatted_code_block(frame)
121
133
  CodeFormatter::Text.new(frame.filename, frame.line).output
122
134
  end
123
135
 
@@ -125,7 +137,7 @@ module BetterErrors
125
137
  str + "\n" + char*str.size
126
138
  end
127
139
 
128
- def inspect_value(obj)
140
+ def self.inspect_value(obj)
129
141
  if BetterErrors.ignored_classes.include? obj.class.name
130
142
  "<span class='unsupported'>(Instance of ignored class. "\
131
143
  "#{obj.class.name ? "Remove #{CGI.escapeHTML(obj.class.name)} from" : "Modify"}"\
@@ -94,12 +94,13 @@ module BetterErrors
94
94
  def show_error_page(env, exception=nil)
95
95
  request = Rack::Request.new(env)
96
96
  csrf_token = request.cookies[CSRF_TOKEN_COOKIE_NAME] || SecureRandom.uuid
97
+ csp_nonce = SecureRandom.base64(12)
97
98
 
98
99
  type, content = if @error_page
99
100
  if text?(env)
100
- [ 'plain', @error_page.render('text') ]
101
+ [ 'plain', @error_page.render_text ]
101
102
  else
102
- [ 'html', @error_page.render('main', csrf_token) ]
103
+ [ 'html', @error_page.render_main(csrf_token, csp_nonce) ]
103
104
  end
104
105
  else
105
106
  [ 'html', no_errors_page ]
@@ -110,7 +111,22 @@ module BetterErrors
110
111
  status_code = ActionDispatch::ExceptionWrapper.new(env, exception).status_code
111
112
  end
112
113
 
113
- response = Rack::Response.new(content, status_code, { "Content-Type" => "text/#{type}; charset=utf-8" })
114
+ headers = {
115
+ "Content-Type" => "text/#{type}; charset=utf-8",
116
+ "Content-Security-Policy" => [
117
+ "default-src 'none'",
118
+ # Specifying nonce makes a modern browser ignore 'unsafe-inline' which could still be set
119
+ # for older browsers without nonce support.
120
+ # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src
121
+ "script-src 'self' 'nonce-#{csp_nonce}' 'unsafe-inline'",
122
+ # Inline style is required by the syntax highlighter.
123
+ "style-src 'self' 'unsafe-inline'",
124
+ "connect-src 'self'",
125
+ "navigate-to 'self' #{BetterErrors.editor.scheme}",
126
+ ].join('; '),
127
+ }
128
+
129
+ response = Rack::Response.new(content, status_code, headers)
114
130
 
115
131
  unless request.cookies[CSRF_TOKEN_COOKIE_NAME]
116
132
  response.set_cookie(CSRF_TOKEN_COOKIE_NAME, value: csrf_token, path: "/", httponly: true, same_site: :strict)
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <title><%= exception_type %> at <%= request_path %></title>
5
5
  </head>
6
- <body>
6
+ <body class="better-errors-javascript-not-loaded">
7
7
  <%# Stylesheets are placed in the <body> for Turbolinks compatibility. %>
8
8
  <style>
9
9
  /* Basic reset */
@@ -107,6 +107,8 @@
107
107
  }
108
108
 
109
109
  .frame_info {
110
+ display: none;
111
+
110
112
  right: 0;
111
113
  left: 40%;
112
114
 
@@ -114,6 +116,9 @@
114
116
  padding-left: 10px;
115
117
  margin-left: 30px;
116
118
  }
119
+ .frame_info.current {
120
+ display: block;
121
+ }
117
122
  }
118
123
 
119
124
  nav.sidebar {
@@ -227,6 +232,10 @@
227
232
  * Navigation
228
233
  * --------------------------------------------------------------------- */
229
234
 
235
+ .better-errors-javascript-not-loaded .backtrace .tabs {
236
+ display: none;
237
+ }
238
+
230
239
  nav.tabs {
231
240
  border-bottom: solid 1px #ddd;
232
241
 
@@ -411,6 +420,18 @@
411
420
  * Display area
412
421
  * --------------------------------------------------------------------- */
413
422
 
423
+ p.no-javascript-notice {
424
+ margin-bottom: 1em;
425
+ padding: 1em;
426
+ border: 2px solid #e00;
427
+ }
428
+ .better-errors-javascript-loaded .no-javascript-notice {
429
+ display: none;
430
+ }
431
+ .no-inline-style-notice {
432
+ display: none;
433
+ }
434
+
414
435
  .trace_info {
415
436
  background: #fff;
416
437
  padding: 6px;
@@ -468,6 +489,10 @@
468
489
  font-weight: 200;
469
490
  }
470
491
 
492
+ .better-errors-javascript-not-loaded .be-repl {
493
+ display: none;
494
+ }
495
+
471
496
  .code, .be-console, .unavailable {
472
497
  background: #fff;
473
498
  padding: 5px;
@@ -598,6 +623,9 @@
598
623
  .console-has-been-used .live-console-hint {
599
624
  display: none;
600
625
  }
626
+ .better-errors-javascript-not-loaded .live-console-hint {
627
+ display: none;
628
+ }
601
629
 
602
630
  .hint:before {
603
631
  content: '\25b2';
@@ -701,7 +729,7 @@
701
729
  </style>
702
730
 
703
731
  <%# IE8 compatibility crap %>
704
- <script>
732
+ <script nonce="<%= csp_nonce %>">
705
733
  (function() {
706
734
  var elements = ["section", "nav", "header", "footer", "audio"];
707
735
  for (var i = 0; i < elements.length; i++) {
@@ -715,7 +743,7 @@
715
743
  rendered in the host app's layout. Let's empty out the styles of the
716
744
  host app.
717
745
  %>
718
- <script>
746
+ <script nonce="<%= csp_nonce %>">
719
747
  if (window.Turbolinks) {
720
748
  for(var i=0; i < document.styleSheets.length; i++) {
721
749
  if(document.styleSheets[i].href)
@@ -740,6 +768,15 @@
740
768
  }
741
769
  </script>
742
770
 
771
+ <p class='no-inline-style-notice'>
772
+ <strong>
773
+ Better Errors can't apply inline style<span class='no-javascript-notice'> (or run Javascript)</span>,
774
+ possibly because you have a Content Security Policy along with Turbolinks.
775
+ But you can
776
+ <a href='/__better_errors' target="_blank">open the interactive console in a new tab/window</a>.
777
+ </strong>
778
+ </p>
779
+
743
780
  <div class='top'>
744
781
  <header class="exception">
745
782
  <h2><strong><%= exception_type %></strong> <span>at <%= request_path %></span></h2>
@@ -786,21 +823,37 @@
786
823
  </ul>
787
824
  </nav>
788
825
 
789
- <% backtrace_frames.each_with_index do |frame, index| %>
790
- <div class="frame_info" id="frame_info_<%= index %>" style="display:none;"></div>
791
- <% end %>
826
+ <div class="frameInfos">
827
+ <div class="frame_info current" data-frame-idx="0">
828
+ <p class='no-javascript-notice'>
829
+ Better Errors can't run Javascript here<span class='no-inline-style-notice'> (or apply inline style)</span>,
830
+ possibly because you have a Content Security Policy along with Turbolinks.
831
+ But you can
832
+ <a href='/__better_errors' target="_blank">open the interactive console in a new tab/window</a>.
833
+ </p>
834
+ <!-- this is enough information to show something in case JS doesn't get to load -->
835
+ <%== ErrorPage.render_template('variable_info', first_frame_variable_info) %>
836
+ </div>
837
+ </div>
792
838
  </section>
793
839
  </body>
794
- <script>
840
+ <script nonce="<%= csp_nonce %>">
795
841
  (function() {
796
842
 
797
843
  var OID = "<%= id %>";
798
844
  var csrfToken = "<%= csrf_token %>";
799
845
 
800
846
  var previousFrame = null;
801
- var previousFrameInfo = null;
802
847
  var allFrames = document.querySelectorAll("ul.frames li");
803
- var allFrameInfos = document.querySelectorAll(".frame_info");
848
+ var frameInfos = document.querySelector(".frameInfos");
849
+
850
+ document.querySelector('body').classList.remove("better-errors-javascript-not-loaded");
851
+ document.querySelector('body').classList.add("better-errors-javascript-loaded");
852
+
853
+ var noJSNotices = document.querySelectorAll('.no-javascript-notice');
854
+ for(var i = 0; i < noJSNotices.length; i++) {
855
+ noJSNotices[i].remove();
856
+ }
804
857
 
805
858
  function apiCall(method, opts, cb) {
806
859
  var req = new XMLHttpRequest();
@@ -974,17 +1027,25 @@
974
1027
  };
975
1028
 
976
1029
  function switchTo(el) {
977
- if(previousFrameInfo) previousFrameInfo.style.display = "none";
978
- previousFrameInfo = el;
1030
+ var currentFrameInfo = document.querySelectorAll('.frame_info.current');
1031
+ for(var i = 0; i < currentFrameInfo.length; i++) {
1032
+ currentFrameInfo[i].className = "frame_info";
1033
+ }
979
1034
 
980
- el.style.display = "block";
1035
+ el.className = "frame_info current";
981
1036
 
982
1037
  var replInput = el.querySelector('.be-console input');
983
1038
  if (replInput) replInput.focus();
984
1039
  }
985
1040
 
986
1041
  function selectFrameInfo(index) {
987
- var el = allFrameInfos[index];
1042
+ var el = document.querySelector(".frame_info[data-frame-idx='" + index + "']")
1043
+ if (!el) {
1044
+ el = document.createElement("div");
1045
+ el.className = "frame_info";
1046
+ el.setAttribute('data-frame-idx', index);
1047
+ frameInfos.appendChild(el);
1048
+ }
988
1049
  if(el) {
989
1050
  if (el.loaded) {
990
1051
  return switchTo(el);
@@ -9,7 +9,7 @@
9
9
  <%== text_heading("-", "%s, line %i" % [first_frame.pretty_path, first_frame.line]) %>
10
10
 
11
11
  ``` ruby
12
- <%== text_formatted_code_block(first_frame) %>```
12
+ <%== ErrorPage.text_formatted_code_block(first_frame) %>```
13
13
 
14
14
  App backtrace
15
15
  -------------
@@ -1,20 +1,20 @@
1
1
  <header class="trace_info clearfix">
2
2
  <div class="title">
3
- <h2 class="name"><%= @frame.name %></h2>
3
+ <h2 class="name"><%= frame.name %></h2>
4
4
  <div class="location">
5
5
  <span class="filename">
6
6
  <a
7
- href="<%= editor_url(@frame) %>"
7
+ href="<%= editor_url %>"
8
8
  <%= ENV.key?('BETTER_ERRORS_INSIDE_FRAME') ? "target=_blank" : '' %>
9
- ><%= @frame.pretty_path %></a>
9
+ ><%= frame.pretty_path %></a>
10
10
  </span>
11
11
  </div>
12
12
  </div>
13
13
  <div class="code_block clearfix">
14
- <%== html_formatted_code_block @frame %>
14
+ <%== ErrorPage.html_formatted_code_block frame %>
15
15
  </div>
16
16
 
17
- <% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
17
+ <% if BetterErrors.binding_of_caller_available? && frame.frame_binding %>
18
18
  <div class="be-repl">
19
19
  <div class="be-console">
20
20
  <pre></pre>
@@ -24,7 +24,7 @@
24
24
  <% end %>
25
25
  </header>
26
26
 
27
- <% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
27
+ <% if BetterErrors.binding_of_caller_available? && frame.frame_binding %>
28
28
  <div class="hint live-console-hint">
29
29
  This is a live shell. Type in here.
30
30
  </div>
@@ -38,27 +38,28 @@
38
38
  </div>
39
39
  <% end %>
40
40
 
41
+ <%# TODO: move this outside of the frame info. It's not part of the frame. %>
41
42
  <div class="sub">
42
43
  <h3>Request info</h3>
43
44
  <div class='inset variables'>
44
45
  <table class="var_table">
45
46
  <% if rails_params %>
46
- <tr><td class="name">Request parameters</td><td><pre><%== inspect_value rails_params %></pre></td></tr>
47
+ <tr><td class="name">Request parameters</td><td><pre><%== ErrorPage.inspect_value rails_params %></pre></td></tr>
47
48
  <% end %>
48
49
  <% if rack_session %>
49
- <tr><td class="name">Rack session</td><td><pre><%== inspect_value rack_session %></pre></td></tr>
50
+ <tr><td class="name">Rack session</td><td><pre><%== ErrorPage.inspect_value rack_session %></pre></td></tr>
50
51
  <% end %>
51
52
  </table>
52
53
  </div>
53
54
  </div>
54
55
 
55
- <% if BetterErrors.binding_of_caller_available? && @frame.frame_binding %>
56
+ <% if BetterErrors.binding_of_caller_available? && frame.frame_binding %>
56
57
  <div class="sub">
57
58
  <h3>Local Variables</h3>
58
59
  <div class='inset variables'>
59
60
  <table class="var_table">
60
- <% @frame.local_variables.each do |name, value| %>
61
- <tr><td class="name"><%= name %></td><td><pre><%== inspect_value value %></pre></td></tr>
61
+ <% frame.local_variables.each do |name, value| %>
62
+ <tr><td class="name"><%= name %></td><td><pre><%== ErrorPage.inspect_value value %></pre></td></tr>
62
63
  <% end %>
63
64
  </table>
64
65
  </div>
@@ -68,12 +69,14 @@
68
69
  <h3>Instance Variables</h3>
69
70
  <div class="inset variables">
70
71
  <table class="var_table">
71
- <% @frame.instance_variables.each do |name, value| %>
72
- <tr><td class="name"><%= name %></td><td><pre><%== inspect_value value %></pre></td></tr>
72
+ <% frame.instance_variables.each do |name, value| %>
73
+ <tr><td class="name"><%= name %></td><td><pre><%== ErrorPage.inspect_value value %></pre></td></tr>
73
74
  <% end %>
74
75
  </table>
75
76
  </div>
76
77
  </div>
78
+ <% end %>
77
79
 
78
- <!-- <%= Time.now.to_f - @var_start_time %> seconds -->
80
+ <% if start_time %>
81
+ <!-- variable_info took <%= Time.now.to_f - start_time %> seconds -->
79
82
  <% end %>
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "2.9.1"
2
+ VERSION = "2.10.0.beta1"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.1
4
+ version: 2.10.0.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-11-05 00:00:00.000000000 Z
11
+ date: 2020-12-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -176,6 +176,9 @@ files:
176
176
  - gemfiles/rails60.gemfile
177
177
  - gemfiles/rails60_boc.gemfile
178
178
  - gemfiles/rails60_haml.gemfile
179
+ - gemfiles/rails61.gemfile
180
+ - gemfiles/rails61_boc.gemfile
181
+ - gemfiles/rails61_haml.gemfile
179
182
  - lib/better_errors.rb
180
183
  - lib/better_errors/code_formatter.rb
181
184
  - lib/better_errors/code_formatter/html.rb
@@ -214,9 +217,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
214
217
  version: 2.0.0
215
218
  required_rubygems_version: !ruby/object:Gem::Requirement
216
219
  requirements:
217
- - - ">="
220
+ - - ">"
218
221
  - !ruby/object:Gem::Version
219
- version: '0'
222
+ version: 1.3.1
220
223
  requirements: []
221
224
  rubygems_version: 3.1.4
222
225
  signing_key: