better_errors 2.9.1 → 2.10.0
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/.github/release-drafter.yml +46 -0
- data/.github/workflows/ci.yml +12 -0
- data/.github/workflows/draft_release_update.yml +22 -0
- data/.github/workflows/pull_request.yml +20 -0
- data/.github/workflows/release.yml +5 -1
- data/.gitignore +4 -0
- data/LICENSE.txt +1 -1
- data/README.md +2 -2
- data/better_errors.gemspec +7 -6
- data/gemfiles/rails61.gemfile +8 -0
- data/gemfiles/rails61_boc.gemfile +9 -0
- data/gemfiles/rails61_haml.gemfile +9 -0
- data/lib/better_errors/code_formatter/html.rb +15 -1
- data/lib/better_errors/code_formatter.rb +16 -27
- data/lib/better_errors/editor.rb +4 -0
- data/lib/better_errors/error_page.rb +28 -14
- data/lib/better_errors/error_page_style.rb +30 -0
- data/lib/better_errors/middleware.rb +19 -3
- data/lib/better_errors/templates/main.css +1 -0
- data/lib/better_errors/templates/main.erb +49 -708
- data/lib/better_errors/templates/text.erb +1 -1
- data/lib/better_errors/templates/variable_info.erb +17 -14
- data/lib/better_errors/version.rb +2 -1
- data/lib/better_errors.rb +0 -1
- metadata +28 -6
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 63e5bb97d23bd3c7afee4c068d074160eca36a9215fb17239a28e807b4ba5b31
|
|
4
|
+
data.tar.gz: cd08b12eaa698201185e457f6d0eb1f4e330de23fd230b7329e32f636665d350
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8ee33a489d6117bb2446ccbd3a41893639df2af5bcb00996ca893b7acf33e6c0310e81124b978f4c991354eef9ca4459288db838d8ed4ea1a622911f96b14c9b
|
|
7
|
+
data.tar.gz: 46d7e1c8fd6738280b5e0c1d23c85c8a7c6c4bce531ad174fbb729a78dea0a0e5870161d6c36fd4fa348da38549f03079e3e46506f8a095f6dfc4247aba390e9
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
---
|
|
2
|
+
name-template: 'v$RESOLVED_VERSION'
|
|
3
|
+
tag-template: 'v$RESOLVED_VERSION'
|
|
4
|
+
autolabeler:
|
|
5
|
+
- label: breaking change
|
|
6
|
+
title:
|
|
7
|
+
- '/(?<!non[- ]?)breaking/i'
|
|
8
|
+
- label: feature
|
|
9
|
+
branch:
|
|
10
|
+
- '/^feature/'
|
|
11
|
+
- label: patch fix
|
|
12
|
+
branch:
|
|
13
|
+
- '/^fix/'
|
|
14
|
+
- label: chore
|
|
15
|
+
branch:
|
|
16
|
+
- '/^chore/'
|
|
17
|
+
categories:
|
|
18
|
+
- title: ⚠ Breaking Changes
|
|
19
|
+
labels:
|
|
20
|
+
- breaking change
|
|
21
|
+
- title: Feature Changes
|
|
22
|
+
labels:
|
|
23
|
+
- feature
|
|
24
|
+
- title: Fixes
|
|
25
|
+
labels:
|
|
26
|
+
- patch fix
|
|
27
|
+
- title: Maintenance
|
|
28
|
+
labels:
|
|
29
|
+
- chore
|
|
30
|
+
exclude-labels:
|
|
31
|
+
- skip-changelog
|
|
32
|
+
change-template: '- $TITLE (@$AUTHOR) #$NUMBER'
|
|
33
|
+
template: '$CHANGES'
|
|
34
|
+
no-changes-template: '_No changes yet._'
|
|
35
|
+
version-resolver:
|
|
36
|
+
major:
|
|
37
|
+
labels:
|
|
38
|
+
- breaking change
|
|
39
|
+
minor:
|
|
40
|
+
labels:
|
|
41
|
+
- minor
|
|
42
|
+
patch:
|
|
43
|
+
labels:
|
|
44
|
+
- patch fix
|
|
45
|
+
- chore
|
|
46
|
+
default: minor
|
data/.github/workflows/ci.yml
CHANGED
|
@@ -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,22 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
name: Draft Release
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
push:
|
|
7
|
+
# Run on change of the main branch, which covers merged pull requests
|
|
8
|
+
branches:
|
|
9
|
+
- main
|
|
10
|
+
- master
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
update:
|
|
14
|
+
name: "Update"
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: release-drafter/release-drafter@v5
|
|
18
|
+
with:
|
|
19
|
+
# Not sure what autolabeler would do in the main branch, but it wouldn't make sense.
|
|
20
|
+
disable-autolabeler: true
|
|
21
|
+
env:
|
|
22
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
|
|
3
|
+
name: Pull Request
|
|
4
|
+
|
|
5
|
+
on:
|
|
6
|
+
pull_request:
|
|
7
|
+
# Run on new/reopened/renamed pull requests so that autolabeling happens
|
|
8
|
+
types: [opened, reopened, edited]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
label:
|
|
12
|
+
name: "Label"
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- uses: release-drafter/release-drafter@v5
|
|
16
|
+
with:
|
|
17
|
+
# Don't run the releaser from the PR, because that will create a draft PR containing the current PR even though it's not merged.
|
|
18
|
+
disable-releaser: true
|
|
19
|
+
env:
|
|
20
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -48,10 +48,14 @@ jobs:
|
|
|
48
48
|
run: |
|
|
49
49
|
bundle exec gem bump better_errors --version ${{ steps.get_version.outputs.version }} --no-commit
|
|
50
50
|
|
|
51
|
+
- name: Compile CSS
|
|
52
|
+
run: |
|
|
53
|
+
bundle exec rake style:build
|
|
54
|
+
|
|
51
55
|
- name: Build gem
|
|
52
56
|
run: gem build better_errors.gemspec
|
|
53
57
|
|
|
54
|
-
- name:
|
|
58
|
+
- name: Add gem to GitHub Release
|
|
55
59
|
uses: actions/upload-release-asset@v1
|
|
56
60
|
env:
|
|
57
61
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
data/.gitignore
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
|
@@ -120,8 +120,8 @@ BetterErrors.maximum_variable_inspect_size = 100_000
|
|
|
120
120
|
```ruby
|
|
121
121
|
# e.g. in config/initializers/better_errors.rb
|
|
122
122
|
# This will stop BetterErrors from trying to inspect objects of these classes, which can cause
|
|
123
|
-
# slow loading times and
|
|
124
|
-
# strings not
|
|
123
|
+
# slow loading times and unnecessary database queries. Does not check inheritance chain, use
|
|
124
|
+
# strings not constants.
|
|
125
125
|
# default value: ['ActionDispatch::Request', 'ActionDispatch::Response']
|
|
126
126
|
BetterErrors.ignored_classes = ['ActionDispatch::Request', 'ActionDispatch::Response']
|
|
127
127
|
```
|
data/better_errors.gemspec
CHANGED
|
@@ -5,16 +5,16 @@ require 'better_errors/version'
|
|
|
5
5
|
Gem::Specification.new do |s|
|
|
6
6
|
s.name = "better_errors"
|
|
7
7
|
s.version = BetterErrors::VERSION
|
|
8
|
-
s.authors = ["
|
|
9
|
-
s.email = ["
|
|
8
|
+
s.authors = ["Hailey Somerville"]
|
|
9
|
+
s.email = ["hailey@hailey.lol"]
|
|
10
10
|
s.description = %q{Provides a better error page for Rails and other Rack apps. Includes source code inspection, a live REPL and local/instance variable inspection for all stack frames.}
|
|
11
11
|
s.summary = %q{Better error page for Rails and other Rack apps}
|
|
12
12
|
s.homepage = "https://github.com/BetterErrors/better_errors"
|
|
13
13
|
s.license = "MIT"
|
|
14
14
|
|
|
15
|
-
s.files = `git ls-files -z`.split("\x0").reject
|
|
16
|
-
f.match(%r{^((test|spec|features|feature-screenshots)/|Rakefile)})
|
|
17
|
-
|
|
15
|
+
s.files = `git ls-files -z`.split("\x0").reject { |f|
|
|
16
|
+
f.match(%r{^((test|spec|features|feature-screenshots)/|Rakefile)|\.scss$})
|
|
17
|
+
} + %w[lib/better_errors/templates/main.css]
|
|
18
18
|
|
|
19
19
|
s.require_paths = ["lib"]
|
|
20
20
|
|
|
@@ -25,12 +25,13 @@ Gem::Specification.new do |s|
|
|
|
25
25
|
s.add_development_dependency "rspec-html-matchers"
|
|
26
26
|
s.add_development_dependency "rspec-its"
|
|
27
27
|
s.add_development_dependency "yard"
|
|
28
|
+
s.add_development_dependency "sassc"
|
|
28
29
|
# kramdown 2.1 requires Ruby 2.3+
|
|
29
30
|
s.add_development_dependency "kramdown", (RUBY_VERSION < '2.3' ? '< 2.0.0' : '> 2.0.0')
|
|
30
31
|
# simplecov and coveralls must not be included here. See the Gemfiles instead.
|
|
31
32
|
|
|
32
33
|
s.add_dependency "erubi", ">= 1.0.0"
|
|
33
|
-
s.add_dependency "
|
|
34
|
+
s.add_dependency "rouge", ">= 1.0.0"
|
|
34
35
|
s.add_dependency "rack", ">= 0.9.0"
|
|
35
36
|
|
|
36
37
|
# optional dependencies:
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
require "rouge"
|
|
2
|
+
|
|
1
3
|
module BetterErrors
|
|
2
4
|
# @private
|
|
3
5
|
class CodeFormatter::HTML < CodeFormatter
|
|
@@ -20,7 +22,19 @@ module BetterErrors
|
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
def formatted_code
|
|
23
|
-
%{
|
|
25
|
+
%{
|
|
26
|
+
<div class="code_linenums">#{formatted_nums.join}</div>
|
|
27
|
+
<div class="code"><div class='code-wrapper'>#{super}</div></div>
|
|
28
|
+
}
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def rouge_lexer
|
|
32
|
+
Rouge::Lexer.guess(filename: filename, source: source) { Rouge::Lexers::Ruby }
|
|
24
33
|
end
|
|
34
|
+
|
|
35
|
+
def highlighted_lines
|
|
36
|
+
Rouge::Formatters::HTML.new.format(rouge_lexer.lex(context_lines.join)).lines
|
|
37
|
+
end
|
|
38
|
+
|
|
25
39
|
end
|
|
26
40
|
end
|
|
@@ -4,14 +4,6 @@ module BetterErrors
|
|
|
4
4
|
require "better_errors/code_formatter/html"
|
|
5
5
|
require "better_errors/code_formatter/text"
|
|
6
6
|
|
|
7
|
-
FILE_TYPES = {
|
|
8
|
-
".rb" => :ruby,
|
|
9
|
-
"" => :ruby,
|
|
10
|
-
".html" => :html,
|
|
11
|
-
".erb" => :erb,
|
|
12
|
-
".haml" => :haml
|
|
13
|
-
}
|
|
14
|
-
|
|
15
7
|
attr_reader :filename, :line, :context
|
|
16
8
|
|
|
17
9
|
def initialize(filename, line, context = 5)
|
|
@@ -26,13 +18,21 @@ module BetterErrors
|
|
|
26
18
|
source_unavailable
|
|
27
19
|
end
|
|
28
20
|
|
|
29
|
-
def
|
|
30
|
-
|
|
21
|
+
def line_range
|
|
22
|
+
min = [line - context, 1].max
|
|
23
|
+
max = [line + context, source_lines.count].min
|
|
24
|
+
min..max
|
|
31
25
|
end
|
|
32
26
|
|
|
33
|
-
def
|
|
34
|
-
|
|
35
|
-
|
|
27
|
+
def context_lines
|
|
28
|
+
range = line_range
|
|
29
|
+
source_lines[(range.begin - 1)..(range.end - 1)] or raise Errno::EINVAL
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def formatted_code
|
|
35
|
+
formatted_lines.join
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def each_line_of(lines, &blk)
|
|
@@ -41,23 +41,12 @@ module BetterErrors
|
|
|
41
41
|
}
|
|
42
42
|
end
|
|
43
43
|
|
|
44
|
-
def
|
|
45
|
-
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
def context_lines
|
|
49
|
-
range = line_range
|
|
50
|
-
source_lines[(range.begin - 1)..(range.end - 1)] or raise Errno::EINVAL
|
|
44
|
+
def source
|
|
45
|
+
@source ||= File.read(filename)
|
|
51
46
|
end
|
|
52
47
|
|
|
53
48
|
def source_lines
|
|
54
|
-
@source_lines ||=
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def line_range
|
|
58
|
-
min = [line - context, 1].max
|
|
59
|
-
max = [line + context, source_lines.count].min
|
|
60
|
-
min..max
|
|
49
|
+
@source_lines ||= source.lines
|
|
61
50
|
end
|
|
62
51
|
end
|
|
63
52
|
end
|
data/lib/better_errors/editor.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
require "cgi"
|
|
2
2
|
require "json"
|
|
3
3
|
require "securerandom"
|
|
4
|
+
require "rouge"
|
|
5
|
+
require "better_errors/error_page_style"
|
|
4
6
|
|
|
5
7
|
module BetterErrors
|
|
6
8
|
# @private
|
|
7
9
|
class ErrorPage
|
|
10
|
+
VariableInfo = Struct.new(:frame, :editor_url, :rails_params, :rack_session, :start_time)
|
|
11
|
+
|
|
8
12
|
def self.template_path(template_name)
|
|
9
13
|
File.expand_path("../templates/#{template_name}.erb", __FILE__)
|
|
10
14
|
end
|
|
@@ -13,6 +17,15 @@ module BetterErrors
|
|
|
13
17
|
Erubi::Engine.new(File.read(template_path(template_name)), escape: true)
|
|
14
18
|
end
|
|
15
19
|
|
|
20
|
+
def self.render_template(template_name, locals)
|
|
21
|
+
locals.send(:eval, self.template(template_name).src)
|
|
22
|
+
rescue => e
|
|
23
|
+
# Fix the backtrace, which doesn't identify the template that failed (within Better Errors).
|
|
24
|
+
# We don't know the line number, so just injecting the template path has to be enough.
|
|
25
|
+
e.backtrace.unshift "#{self.template_path(template_name)}:0"
|
|
26
|
+
raise
|
|
27
|
+
end
|
|
28
|
+
|
|
16
29
|
attr_reader :exception, :env, :repls
|
|
17
30
|
|
|
18
31
|
def initialize(exception, env)
|
|
@@ -26,20 +39,21 @@ module BetterErrors
|
|
|
26
39
|
@id ||= SecureRandom.hex(8)
|
|
27
40
|
end
|
|
28
41
|
|
|
29
|
-
def
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
def render_main(csrf_token, csp_nonce)
|
|
43
|
+
frame = backtrace_frames[0]
|
|
44
|
+
first_frame_variable_info = VariableInfo.new(frame, editor_url(frame), rails_params, rack_session, Time.now.to_f)
|
|
45
|
+
self.class.render_template('main', binding)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def render_text
|
|
49
|
+
self.class.render_template('text', binding)
|
|
36
50
|
end
|
|
37
51
|
|
|
38
52
|
def do_variables(opts)
|
|
39
53
|
index = opts["index"].to_i
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
{ html:
|
|
54
|
+
frame = backtrace_frames[index]
|
|
55
|
+
variable_info = VariableInfo.new(frame, editor_url(frame), rails_params, rack_session, Time.now.to_f)
|
|
56
|
+
{ html: self.class.render_template("variable_info", variable_info) }
|
|
43
57
|
end
|
|
44
58
|
|
|
45
59
|
def do_eval(opts)
|
|
@@ -113,11 +127,11 @@ module BetterErrors
|
|
|
113
127
|
env["PATH_INFO"]
|
|
114
128
|
end
|
|
115
129
|
|
|
116
|
-
def html_formatted_code_block(frame)
|
|
130
|
+
def self.html_formatted_code_block(frame)
|
|
117
131
|
CodeFormatter::HTML.new(frame.filename, frame.line).output
|
|
118
132
|
end
|
|
119
133
|
|
|
120
|
-
def text_formatted_code_block(frame)
|
|
134
|
+
def self.text_formatted_code_block(frame)
|
|
121
135
|
CodeFormatter::Text.new(frame.filename, frame.line).output
|
|
122
136
|
end
|
|
123
137
|
|
|
@@ -125,7 +139,7 @@ module BetterErrors
|
|
|
125
139
|
str + "\n" + char*str.size
|
|
126
140
|
end
|
|
127
141
|
|
|
128
|
-
def inspect_value(obj)
|
|
142
|
+
def self.inspect_value(obj)
|
|
129
143
|
if BetterErrors.ignored_classes.include? obj.class.name
|
|
130
144
|
"<span class='unsupported'>(Instance of ignored class. "\
|
|
131
145
|
"#{obj.class.name ? "Remove #{CGI.escapeHTML(obj.class.name)} from" : "Modify"}"\
|
|
@@ -145,7 +159,7 @@ module BetterErrors
|
|
|
145
159
|
result, prompt, prefilled_input = @repls[index].send_input(code)
|
|
146
160
|
|
|
147
161
|
{
|
|
148
|
-
highlighted_input:
|
|
162
|
+
highlighted_input: Rouge::Formatters::HTML.new.format(Rouge::Lexers::Ruby.lex(code)),
|
|
149
163
|
prefilled_input: prefilled_input,
|
|
150
164
|
prompt: prompt,
|
|
151
165
|
result: result
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require "sassc"
|
|
2
|
+
|
|
3
|
+
module BetterErrors
|
|
4
|
+
# @private
|
|
5
|
+
module ErrorPageStyle
|
|
6
|
+
def self.compiled_css(for_deployment = false)
|
|
7
|
+
style_dir = File.expand_path("style", File.dirname(__FILE__))
|
|
8
|
+
style_file = "#{style_dir}/main.scss"
|
|
9
|
+
|
|
10
|
+
engine = SassC::Engine.new(
|
|
11
|
+
File.read(style_file),
|
|
12
|
+
filename: style_file,
|
|
13
|
+
style: for_deployment ? :compressed : :expanded,
|
|
14
|
+
line_comments: !for_deployment,
|
|
15
|
+
load_paths: [style_dir],
|
|
16
|
+
)
|
|
17
|
+
engine.render
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def self.style_tag(csp_nonce)
|
|
21
|
+
style_file = File.expand_path("templates/main.css", File.dirname(__FILE__))
|
|
22
|
+
css = if File.exist?(style_file)
|
|
23
|
+
File.open(style_file).read
|
|
24
|
+
else
|
|
25
|
+
compiled_css(false)
|
|
26
|
+
end
|
|
27
|
+
"<style type='text/css' nonce='#{csp_nonce}'>\n#{css}\n</style>"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -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.
|
|
101
|
+
[ 'plain', @error_page.render_text ]
|
|
101
102
|
else
|
|
102
|
-
[ 'html', @error_page.
|
|
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
|
-
|
|
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
|
+
"style-src 'self' 'nonce-#{csp_nonce}' 'unsafe-inline'",
|
|
123
|
+
"img-src data:",
|
|
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)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
*{margin:0;padding:0}table{width:100%;border-collapse:collapse}th,td{vertical-align:top;text-align:left}textarea{resize:none}body{font-size:10pt}body,td,input,textarea{font-family:helvetica neue, lucida grande, sans-serif;line-height:1.5;color:#333;text-shadow:0 1px 0 rgba(255,255,255,0.6)}html{background:#f0f0f5}.clearfix::after{clear:both;content:".";display:block;height:0;visibility:hidden}@media screen and (max-width: 1100px){html{overflow-y:scroll}body{margin:0 20px}header.exception{margin:0 -20px}nav.sidebar{padding:0;margin:20px 0}ul.frames{max-height:200px;overflow:auto}}@media screen and (min-width: 1100px){header.exception{position:fixed;top:0;left:0;right:0}nav.sidebar,.frame_info{position:fixed;top:102px;bottom:0;box-sizing:border-box;overflow-y:auto;overflow-x:hidden}nav.sidebar{width:40%;left:20px;top:122px;bottom:20px}.frame_info{display:none;right:0;left:40%;padding:20px;padding-left:10px;margin-left:30px}.frame_info.current{display:block}}nav.sidebar{background:#d3d3da;border-top:solid 3px #a33;border-bottom:solid 3px #a33;border-radius:4px;box-shadow:0 0 6px rgba(0,0,0,0.2),inset 0 0 0 1px rgba(0,0,0,0.1)}header.exception{padding:18px 20px;height:66px;min-height:59px;overflow:hidden;background-color:#20202a;color:#aaa;text-shadow:0 1px 0 rgba(0,0,0,0.3);font-weight:200;box-shadow:inset 0 -5px 3px -3px rgba(0,0,0,0.05),inset 0 -1px 0 rgba(0,0,0,0.05);-webkit-text-smoothing:antialiased}header.exception .fix-actions{margin-top:.5em}header.exception .fix-actions input[type=submit]{font-weight:bold}header.exception h2{font-weight:200;font-size:11pt}header.exception h2,header.exception p{line-height:1.5em;overflow:hidden;white-space:pre;text-overflow:ellipsis}header.exception h2 strong{font-weight:700;color:#d55}header.exception p{font-weight:200;font-size:17pt;color:white}header.exception:hover{height:auto;z-index:2}header.exception:hover h2,header.exception:hover p{padding-right:20px;overflow-y:auto;word-wrap:break-word;white-space:pre-wrap;height:auto;max-height:7.5em}@media screen and (max-width: 1100px){header.exception{height:auto}header.exception h2,header.exception p{padding-right:20px;overflow-y:auto;word-wrap:break-word;height:auto;max-height:7em}}.better-errors-javascript-not-loaded .backtrace .tabs{display:none}nav.tabs{border-bottom:solid 1px #ddd;background-color:#eee;text-align:center;padding:6px;box-shadow:inset 0 1px 0 rgba(255,255,255,0.1)}nav.tabs a{display:inline-block;height:22px;line-height:22px;padding:0 10px;text-decoration:none;font-size:8pt;font-weight:bold;color:#999;text-shadow:0 1px 0 rgba(255,255,255,0.6)}nav.tabs a.selected{color:white;background:rgba(0,0,0,0.5);border-radius:16px;box-shadow:1px 1px 0 rgba(255,255,255,0.1);text-shadow:0 0 4px rgba(0,0,0,0.4),0 1px 0 rgba(0,0,0,0.4)}nav.tabs a.disabled{text-decoration:line-through;text-shadow:none;cursor:default}ul.frames{box-shadow:0 0 10px rgba(0,0,0,0.1)}ul.frames li{background-color:#f8f8f8;background:-webkit-linear-gradient(top, #f8f8f8 80%, #f0f0f0);background:-moz-linear-gradient(top, #f8f8f8 80%, #f0f0f0);background:linear-gradient(top, #f8f8f8 80%, #f0f0f0);box-shadow:inset 0 -1px 0 #e2e2e2;padding:7px 20px;cursor:pointer;overflow:hidden}ul.frames .name,ul.frames .location{overflow:hidden;height:1.5em;white-space:nowrap;word-wrap:none;text-overflow:ellipsis}ul.frames .method{color:#966}ul.frames .location{font-size:0.85em;font-weight:400;color:#999}ul.frames .line{font-weight:bold}ul.frames li.selected{background:#38a;box-shadow:inset 0 1px 0 rgba(0,0,0,0.1),inset 0 2px 0 rgba(255,255,255,0.01),inset 0 -1px 0 rgba(0,0,0,0.1)}ul.frames li.selected .name,ul.frames li.selected .method,ul.frames li.selected .location{color:white;text-shadow:0 1px 0 rgba(0,0,0,0.2)}ul.frames li.selected .location{opacity:0.6}ul.frames li{padding-left:60px;position:relative}ul.frames li .icon{display:block;width:20px;height:20px;line-height:20px;border-radius:15px;text-align:center;background:white;border:solid 2px #ccc;font-size:9pt;font-weight:200;font-style:normal;position:absolute;top:14px;left:20px}ul.frames .icon.application{background:#808090;border-color:#555}ul.frames .icon.application:before{content:'A';color:white;text-shadow:0 0 3px rgba(0,0,0,0.2)}@media screen and (max-width: 1100px){ul.frames li{padding-top:6px;padding-bottom:6px;padding-left:36px;line-height:1.3}ul.frames li .icon{width:11px;height:11px;line-height:11px;top:7px;left:10px;font-size:5pt}ul.frames .name,ul.frames .location{display:inline-block;line-height:1.3;height:1.3em}ul.frames .name{margin-right:10px}}pre,code,.be-repl input,.be-repl .command-line span,textarea,.code_linenums{font-family:menlo, lucida console, monospace;font-size:8pt}p.no-javascript-notice{margin-bottom:1em;padding:1em;border:2px solid #e00}.better-errors-javascript-loaded .no-javascript-notice{display:none}.no-inline-style-notice{display:none}.trace_info{background:#fff;padding:6px;border-radius:3px;margin-bottom:2px;box-shadow:0 0 10px rgba(0,0,0,0.03),1px 1px 0 rgba(0,0,0,0.05),-1px 1px 0 rgba(0,0,0,0.05),0 0 0 4px rgba(0,0,0,0.04)}.code_block{background:#f1f1f1;border-left:1px solid #ccc}.trace_info .title{background:#f1f1f1;box-shadow:inset 0 1px 0 rgba(255,255,255,0.3);overflow:hidden;padding:6px 10px;border:solid 1px #ccc;border-bottom:0;border-top-left-radius:2px;border-top-right-radius:2px}.trace_info .title .name,.trace_info .title .location{font-size:9pt;line-height:26px;height:26px;overflow:hidden}.trace_info .title .location{float:left;font-weight:bold;font-size:10pt}.trace_info .title .location a{color:inherit;text-decoration:none;border-bottom:1px solid #aaaaaa}.trace_info .title .location a:hover{border-color:#666666}.trace_info .title .name{float:right;font-weight:200}.better-errors-javascript-not-loaded .be-repl{display:none}.code,.be-console,.unavailable{padding:5px;box-shadow:inset 3px 3px 3px rgba(0,0,0,0.1),inset 0 0 0 1px rgba(0,0,0,0.1)}.code,.unavailable{text-shadow:none}.code_linenums{background:#f1f1f1;padding-top:10px;padding-bottom:9px;float:left}.code_linenums span{display:block;padding:0 12px}.code,.be-console .syntax-highlighted{text-shadow:none}.code,.be-console .syntax-highlighted{background-color:#fdf6e3;color:#586e75}.code .c,.be-console .syntax-highlighted .c{color:#93a1a1}.code .err,.be-console .syntax-highlighted .err{color:#586e75}.code .g,.be-console .syntax-highlighted .g{color:#586e75}.code .k,.be-console .syntax-highlighted .k{color:#859900}.code .l,.be-console .syntax-highlighted .l{color:#586e75}.code .n,.be-console .syntax-highlighted .n{color:#586e75}.code .o,.be-console .syntax-highlighted .o{color:#859900}.code .x,.be-console .syntax-highlighted .x{color:#cb4b16}.code .p,.be-console .syntax-highlighted .p{color:#586e75}.code .cm,.be-console .syntax-highlighted .cm{color:#93a1a1}.code .cp,.be-console .syntax-highlighted .cp{color:#859900}.code .c1,.be-console .syntax-highlighted .c1{color:#93a1a1}.code .cs,.be-console .syntax-highlighted .cs{color:#859900}.code .gd,.be-console .syntax-highlighted .gd{color:#2aa198}.code .ge,.be-console .syntax-highlighted .ge{color:#586e75;font-style:italic}.code .gr,.be-console .syntax-highlighted .gr{color:#dc322f}.code .gh,.be-console .syntax-highlighted .gh{color:#cb4b16}.code .gi,.be-console .syntax-highlighted .gi{color:#859900}.code .go,.be-console .syntax-highlighted .go{color:#586e75}.code .gp,.be-console .syntax-highlighted .gp{color:#586e75}.code .gs,.be-console .syntax-highlighted .gs{color:#586e75;font-weight:bold}.code .gu,.be-console .syntax-highlighted .gu{color:#cb4b16}.code .gt,.be-console .syntax-highlighted .gt{color:#586e75}.code .kc,.be-console .syntax-highlighted .kc{color:#cb4b16}.code .kd,.be-console .syntax-highlighted .kd{color:#268bd2}.code .kn,.be-console .syntax-highlighted .kn{color:#859900}.code .kp,.be-console .syntax-highlighted .kp{color:#859900}.code .kr,.be-console .syntax-highlighted .kr{color:#268bd2}.code .kt,.be-console .syntax-highlighted .kt{color:#dc322f}.code .ld,.be-console .syntax-highlighted .ld{color:#586e75}.code .m,.be-console .syntax-highlighted .m{color:#2aa198}.code .s,.be-console .syntax-highlighted .s{color:#2aa198}.code .na,.be-console .syntax-highlighted .na{color:#586e75}.code .nb,.be-console .syntax-highlighted .nb{color:#B58900}.code .nc,.be-console .syntax-highlighted .nc{color:#268bd2}.code .no,.be-console .syntax-highlighted .no{color:#cb4b16}.code .nd,.be-console .syntax-highlighted .nd{color:#268bd2}.code .ni,.be-console .syntax-highlighted .ni{color:#cb4b16}.code .ne,.be-console .syntax-highlighted .ne{color:#cb4b16}.code .nf,.be-console .syntax-highlighted .nf{color:#268bd2}.code .nl,.be-console .syntax-highlighted .nl{color:#586e75}.code .nn,.be-console .syntax-highlighted .nn{color:#586e75}.code .nx,.be-console .syntax-highlighted .nx{color:#586e75}.code .py,.be-console .syntax-highlighted .py{color:#586e75}.code .nt,.be-console .syntax-highlighted .nt{color:#268bd2}.code .nv,.be-console .syntax-highlighted .nv{color:#268bd2}.code .ow,.be-console .syntax-highlighted .ow{color:#859900}.code .w,.be-console .syntax-highlighted .w{color:#586e75}.code .mf,.be-console .syntax-highlighted .mf{color:#2aa198}.code .mh,.be-console .syntax-highlighted .mh{color:#2aa198}.code .mi,.be-console .syntax-highlighted .mi{color:#2aa198}.code .mo,.be-console .syntax-highlighted .mo{color:#2aa198}.code .sb,.be-console .syntax-highlighted .sb{color:#93a1a1}.code .sc,.be-console .syntax-highlighted .sc{color:#2aa198}.code .sd,.be-console .syntax-highlighted .sd{color:#586e75}.code .s2,.be-console .syntax-highlighted .s2{color:#2aa198}.code .se,.be-console .syntax-highlighted .se{color:#cb4b16}.code .sh,.be-console .syntax-highlighted .sh{color:#586e75}.code .si,.be-console .syntax-highlighted .si{color:#2aa198}.code .sx,.be-console .syntax-highlighted .sx{color:#2aa198}.code .sr,.be-console .syntax-highlighted .sr{color:#dc322f}.code .s1,.be-console .syntax-highlighted .s1{color:#2aa198}.code .ss,.be-console .syntax-highlighted .ss{color:#2aa198}.code .bp,.be-console .syntax-highlighted .bp{color:#268bd2}.code .vc,.be-console .syntax-highlighted .vc{color:#268bd2}.code .vg,.be-console .syntax-highlighted .vg{color:#268bd2}.code .vi,.be-console .syntax-highlighted .vi{color:#268bd2}.code .il,.be-console .syntax-highlighted .il{color:#2aa198}@media (prefers-color-scheme: dark){.code{background-color:#002b36;color:#93a1a1}.code .c{color:#586e75;background-color:transparent;font-style:inherit}.code .err{color:#93a1a1;background-color:transparent;font-style:inherit}.code .g{color:#93a1a1;background-color:transparent;font-style:inherit}.code .k{color:#859900;background-color:transparent;font-style:inherit}.code .l{color:#93a1a1;background-color:transparent;font-style:inherit}.code .n{color:#93a1a1;background-color:transparent;font-style:inherit}.code .o{color:#859900;background-color:transparent;font-style:inherit}.code .x{color:#cb4b16;background-color:transparent;font-style:inherit}.code .p{color:#93a1a1;background-color:transparent;font-style:inherit}.code .cm{color:#586e75;background-color:transparent;font-style:inherit}.code .cp{color:#859900;background-color:transparent;font-style:inherit}.code .c1{color:#586e75;background-color:transparent;font-style:inherit}.code .cs{color:#859900;background-color:transparent;font-style:inherit}.code .gd{color:#2aa198;background-color:transparent;font-style:inherit}.code .ge{color:#93a1a1;background-color:transparent;font-style:italic}.code .gr{color:#dc322f;background-color:transparent;font-style:inherit}.code .gh{color:#cb4b16;background-color:transparent;font-style:inherit}.code .gi{color:#859900;background-color:transparent;font-style:inherit}.code .go{color:#93a1a1;background-color:transparent;font-style:inherit}.code .gp{color:#93a1a1;background-color:transparent;font-style:inherit}.code .gs{color:#93a1a1;background-color:transparent;font-weight:bold}.code .gu{color:#cb4b16;background-color:transparent;font-style:inherit}.code .gt{color:#93a1a1;background-color:transparent;font-style:inherit}.code .kc{color:#cb4b16;background-color:transparent;font-style:inherit}.code .kd{color:#268bd2;background-color:transparent;font-style:inherit}.code .kn{color:#859900;background-color:transparent;font-style:inherit}.code .kp{color:#859900;background-color:transparent;font-style:inherit}.code .kr{color:#268bd2;background-color:transparent;font-style:inherit}.code .kt{color:#dc322f;background-color:transparent;font-style:inherit}.code .ld{color:#93a1a1;background-color:transparent;font-style:inherit}.code .m{color:#2aa198;background-color:transparent;font-style:inherit}.code .s{color:#2aa198;background-color:transparent;font-style:inherit}.code .na{color:#93a1a1;background-color:transparent;font-style:inherit}.code .nb{color:#B58900;background-color:transparent;font-style:inherit}.code .nc{color:#268bd2;background-color:transparent;font-style:inherit}.code .no{color:#cb4b16;background-color:transparent;font-style:inherit}.code .nd{color:#268bd2;background-color:transparent;font-style:inherit}.code .ni{color:#cb4b16;background-color:transparent;font-style:inherit}.code .ne{color:#cb4b16;background-color:transparent;font-style:inherit}.code .nf{color:#268bd2;background-color:transparent;font-style:inherit}.code .nl{color:#93a1a1;background-color:transparent;font-style:inherit}.code .nn{color:#93a1a1;background-color:transparent;font-style:inherit}.code .nx{color:#93a1a1;background-color:transparent;font-style:inherit}.code .py{color:#93a1a1;background-color:transparent;font-style:inherit}.code .nt{color:#268bd2;background-color:transparent;font-style:inherit}.code .nv{color:#268bd2;background-color:transparent;font-style:inherit}.code .ow{color:#859900;background-color:transparent;font-style:inherit}.code .w{color:#93a1a1;background-color:transparent;font-style:inherit}.code .mf{color:#2aa198;background-color:transparent;font-style:inherit}.code .mh{color:#2aa198;background-color:transparent;font-style:inherit}.code .mi{color:#2aa198;background-color:transparent;font-style:inherit}.code .mo{color:#2aa198;background-color:transparent;font-style:inherit}.code .sb{color:#586e75;background-color:transparent;font-style:inherit}.code .sc{color:#2aa198;background-color:transparent;font-style:inherit}.code .sd{color:#93a1a1;background-color:transparent;font-style:inherit}.code .s2{color:#2aa198;background-color:transparent;font-style:inherit}.code .se{color:#cb4b16;background-color:transparent;font-style:inherit}.code .sh{color:#93a1a1;background-color:transparent;font-style:inherit}.code .si{color:#2aa198;background-color:transparent;font-style:inherit}.code .sx{color:#2aa198;background-color:transparent;font-style:inherit}.code .sr{color:#dc322f;background-color:transparent;font-style:inherit}.code .s1{color:#2aa198;background-color:transparent;font-style:inherit}.code .ss{color:#2aa198;background-color:transparent;font-style:inherit}.code .bp{color:#268bd2;background-color:transparent;font-style:inherit}.code .vc{color:#268bd2;background-color:transparent;font-style:inherit}.code .vg{color:#268bd2;background-color:transparent;font-style:inherit}.code .vi{color:#268bd2;background-color:transparent;font-style:inherit}.code .il{color:#2aa198;background-color:transparent;font-style:inherit}}.code{margin-bottom:-1px;border-top-left-radius:2px;padding:10px 0;overflow:auto}.code .code-wrapper{display:inline-block;min-width:100%}.code pre{padding-left:12px;min-height:16px}p.unavailable{padding:20px 0 40px 0;text-align:center;color:#b99;font-weight:bold}p.unavailable:before{content:'\00d7';display:block;color:#daa;text-align:center;font-size:40pt;font-weight:normal;margin-bottom:-10px}@-webkit-keyframes highlight{0%{background:rgba(51,136,170,0.45)}100%{background:rgba(51,136,170,0.15)}}@-moz-keyframes highlight{0%{background:rgba(51,136,170,0.45)}100%{background:rgba(51,136,170,0.15)}}@keyframes highlight{0%{background:rgba(51,136,170,0.45)}100%{background:rgba(51,136,170,0.15)}}.code .highlight,.code_linenums .highlight{background:rgba(51,136,170,0.15);-webkit-animation:highlight 400ms linear 1;-moz-animation:highlight 400ms linear 1;animation:highlight 400ms linear 1}.be-console{background:#fff;padding:0 1px 10px 1px;border-bottom-left-radius:2px;border-bottom-right-radius:2px}.be-console pre{padding:10px 10px 0 10px;max-height:400px;overflow-x:none;overflow-y:auto;margin-bottom:-3px;word-wrap:break-word;white-space:pre-wrap}.be-console .command-line{display:table;width:100%}.be-console .command-line span,.be-console .command-line input{display:table-cell}.be-console .command-line span{width:1%;padding-right:5px;padding-left:10px;white-space:pre}.be-console .command-line input{width:99%}.be-console input,.be-console input:focus{outline:0;border:0;padding:0;background:transparent;margin:0}.hint{margin:15px 0 20px 0;font-size:8pt;color:#8080a0;padding-left:20px}.console-has-been-used .live-console-hint{display:none}.better-errors-javascript-not-loaded .live-console-hint{display:none}.hint:before{content:'\25b2';margin-right:5px;opacity:0.5}.sub{padding:10px 0;margin:10px 0}.sub h3{color:#39a;font-size:1.1em;margin:10px 0;text-shadow:0 1px 0 rgba(255,255,255,0.6);-webkit-font-smoothing:antialiased}.sub .inset{overflow-y:auto}.sub table{table-layout:fixed}.sub table td{border-top:dotted 1px #ddd;padding:7px 1px}.sub table td.name{width:150px;font-weight:bold;font-size:0.8em;padding-right:20px;word-wrap:break-word}.sub table td pre{max-height:15em;overflow-y:auto}.sub table td pre{width:100%;word-wrap:break-word;white-space:normal}.sub .unsupported{font-family:sans-serif;color:#777}nav.sidebar::-webkit-scrollbar,.inset pre::-webkit-scrollbar,.be-console pre::-webkit-scrollbar,.code::-webkit-scrollbar{width:10px;height:10px}.inset pre::-webkit-scrollbar-thumb,.be-console pre::-webkit-scrollbar-thumb,.code::-webkit-scrollbar-thumb{background:#ccc;border-radius:5px}nav.sidebar::-webkit-scrollbar-thumb{background:rgba(0,0,0,0);border-radius:5px}nav.sidebar:hover::-webkit-scrollbar-thumb{background-color:#999;background:-webkit-linear-gradient(left, #aaa, #999)}.be-console pre:hover::-webkit-scrollbar-thumb,.inset pre:hover::-webkit-scrollbar-thumb,.code:hover::-webkit-scrollbar-thumb{background:#888}
|