better_errors 2.9.1 → 2.10.0.beta1

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 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: