better_errors 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of better_errors might be problematic. Click here for more details.

@@ -0,0 +1,3 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0-rc2
data/README.md CHANGED
@@ -21,8 +21,6 @@ group :development do
21
21
  end
22
22
  ```
23
23
 
24
- **NOTE:** It is *critical* you put better\_errors in the **development** section. **Do NOT run better_errors in production, or on Internet facing hosts.**
25
-
26
24
  If you would like to use Better Errors' **advanced features** (REPL, local/instance variable inspection, pretty stack frame names), you need to add the [`binding_of_caller`](https://github.com/banister/binding_of_caller) gem by [@banisterfiend](http://twitter.com/banisterfiend) to your Gemfile:
27
25
 
28
26
  ```ruby
@@ -31,6 +29,28 @@ gem "binding_of_caller"
31
29
 
32
30
  This is an optional dependency however, and Better Errors will work without it.
33
31
 
32
+ ## Security
33
+
34
+ **NOTE:** It is *critical* you put better\_errors in the **development** section. **Do NOT run better_errors in production, or on Internet facing hosts.**
35
+
36
+ You will notice that the only machine that gets the Better Errors page is localhost, which means you get the default error page if you are developing on a remote host (or a virtually remote host, such as a Vagrant box). Obviously, the REPL is not something you want to expose to the public, but there may also be other pieces of sensitive information available in the backtrace.
37
+
38
+ To poke selective holes in this security mechanism, you can add a line like this to your startup (for example, on Rails it would be `config/environments/development.rb`)
39
+
40
+ ```ruby
41
+ BetterErrors::Middleware.allow_ip! ENV['TRUSTED_IP'] if ENV['TRUSTED_IP']
42
+ ```
43
+
44
+ Then run Rails like this:
45
+
46
+ ```shell
47
+ TRUSTED_IP=66.68.96.220 rails s
48
+ ```
49
+
50
+ Note that the `allow_ip!` is actually backed by a `Set`, so you can add more than one IP address or subnet.
51
+
52
+ **Tip:** You can find your apparent IP by hitting the old error page's "Show env dump" and looking at "REMOTE_ADDR".
53
+
34
54
  ## Usage
35
55
 
36
56
  If you're using Rails, there's nothing else you need to do.
data/Rakefile CHANGED
@@ -1 +1,4 @@
1
1
  require "bundler/gem_tasks"
2
+ task :default => :spec
3
+ task :test => :spec
4
+ task :spec do sh 'bundle exec rspec' end
@@ -17,6 +17,8 @@ Gem::Specification.new do |s|
17
17
  s.test_files = s.files.grep(%r{^(test|spec|features)/})
18
18
  s.require_paths = ["lib"]
19
19
 
20
+ s.required_ruby_version = ">= 1.9.2"
21
+
20
22
  s.add_development_dependency "rake"
21
23
  s.add_development_dependency "rspec", "~> 2.12.0"
22
24
  s.add_development_dependency "binding_of_caller"
@@ -91,6 +91,8 @@ module BetterErrors
91
91
  self.editor = "subl://open?url=file://%{file}&line=%{line}"
92
92
  when :macvim, :mvim
93
93
  self.editor = proc { |file, line| "mvim://open?url=file://#{file}&line=#{line}" }
94
+ when :emacs
95
+ self.editor = "emacs://open?url=file://%{file}&line=%{line}"
94
96
  when String
95
97
  self.editor = proc { |file, line| editor % { file: URI.encode_www_form_component(file), line: line } }
96
98
  else
@@ -1,17 +1,18 @@
1
1
  require "json"
2
2
  require "ipaddr"
3
+ require "set"
3
4
 
4
5
  module BetterErrors
5
6
  # Better Errors' error handling middleware. Including this in your middleware
6
7
  # stack will show a Better Errors error page for exceptions raised below this
7
8
  # middleware.
8
- #
9
- # If you are using Ruby on Rails, you do not need to manually insert this
9
+ #
10
+ # If you are using Ruby on Rails, you do not need to manually insert this
10
11
  # middleware into your middleware stack.
11
- #
12
+ #
12
13
  # @example Sinatra
13
14
  # require "better_errors"
14
- #
15
+ #
15
16
  # if development?
16
17
  # use BetterErrors::Middleware
17
18
  # end
@@ -21,39 +22,51 @@ module BetterErrors
21
22
  # if ENV["RACK_ENV"] == "development"
22
23
  # use BetterErrors::Middleware
23
24
  # end
24
- #
25
+ #
25
26
  class Middleware
27
+ # The set of IP addresses that are allowed to access Better Errors.
28
+ #
29
+ # Set to `{ "127.0.0.1/8", "::1/128" }` by default.
30
+ ALLOWED_IPS = Set.new
31
+
32
+ # Adds an address to the set of IP addresses allowed to access Better
33
+ # Errors.
34
+ def self.allow_ip!(addr)
35
+ ALLOWED_IPS << IPAddr.new(addr)
36
+ end
37
+
38
+ allow_ip! "127.0.0.0/8"
39
+ allow_ip! "::1/128"
40
+
26
41
  # A new instance of BetterErrors::Middleware
27
- #
42
+ #
28
43
  # @param app The Rack app/middleware to wrap with Better Errors
29
44
  # @param handler The error handler to use.
30
45
  def initialize(app, handler = ErrorPage)
31
46
  @app = app
32
47
  @handler = handler
33
48
  end
34
-
49
+
35
50
  # Calls the Better Errors middleware
36
- #
51
+ #
37
52
  # @param [Hash] env
38
53
  # @return [Array]
39
54
  def call(env)
40
- if local_request? env
55
+ if allow_ip? env
41
56
  better_errors_call env
42
57
  else
43
58
  @app.call env
44
59
  end
45
60
  end
46
-
61
+
47
62
  private
48
- IPV4_LOCAL = IPAddr.new("127.0.0.0/8")
49
- IPV6_LOCAL = IPAddr.new("::1/128")
50
63
 
51
- def local_request?(env)
64
+ def allow_ip?(env)
52
65
  # REMOTE_ADDR is not in the rack spec, so some application servers do
53
66
  # not provide it.
54
67
  return true unless env["REMOTE_ADDR"]
55
68
  ip = IPAddr.new env["REMOTE_ADDR"]
56
- IPV4_LOCAL.include? ip or IPV6_LOCAL.include? ip
69
+ ALLOWED_IPS.any? { |subnet| subnet.include? ip }
57
70
  end
58
71
 
59
72
  def better_errors_call(env)
@@ -93,18 +106,18 @@ module BetterErrors
93
106
  env["HTTP_X_REQUESTED_WITH"] == "XMLHttpRequest" ||
94
107
  !env["HTTP_ACCEPT"].to_s.include?('html')
95
108
  end
96
-
109
+
97
110
  def log_exception
98
111
  return unless BetterErrors.logger
99
-
112
+
100
113
  message = "\n#{@error_page.exception.class} - #{@error_page.exception.message}:\n"
101
114
  @error_page.backtrace_frames.each do |frame|
102
115
  message << " #{frame}\n"
103
116
  end
104
-
117
+
105
118
  BetterErrors.logger.fatal message
106
119
  end
107
-
120
+
108
121
  def internal_call(env, opts)
109
122
  if opts[:oid].to_i != @error_page.object_id
110
123
  return [200, { "Content-Type" => "text/plain; charset=utf-8" }, [JSON.dump(error: "Session expired")]]
@@ -1,3 +1,3 @@
1
1
  module BetterErrors
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -23,48 +23,54 @@ module BetterErrors
23
23
  app.call("REMOTE_ADDR" => "1.2.3.4")
24
24
  end
25
25
 
26
+ it "should show to a whitelisted IP" do
27
+ BetterErrors::Middleware.allow_ip! '77.55.33.11'
28
+ app.should_receive :better_errors_call
29
+ app.call("REMOTE_ADDR" => "77.55.33.11")
30
+ end
31
+
26
32
  context "when requesting the /__better_errors manually" do
27
33
  let(:app) { Middleware.new(->env { ":)" }) }
28
-
34
+
29
35
  it "should show that no errors have been recorded" do
30
36
  status, headers, body = app.call("PATH_INFO" => "/__better_errors")
31
37
  body.join.should match /No errors have been recorded yet./
32
38
  end
33
39
  end
34
-
40
+
35
41
  context "when handling an error" do
36
42
  let(:app) { Middleware.new(->env { raise "oh no :(" }) }
37
-
43
+
38
44
  it "should return status 500" do
39
45
  status, headers, body = app.call({})
40
-
46
+
41
47
  status.should == 500
42
48
  end
43
-
49
+
44
50
  it "should return UTF-8 error pages" do
45
51
  status, headers, body = app.call({})
46
-
52
+
47
53
  headers["Content-Type"].should match /charset=utf-8/
48
54
  end
49
55
 
50
56
  it "should return text pages by default" do
51
57
  status, headers, body = app.call({})
52
-
58
+
53
59
  headers["Content-Type"].should match /text\/plain/
54
60
  end
55
-
61
+
56
62
  it "should return HTML pages by default" do
57
63
  # Chrome's 'Accept' header looks similar this.
58
64
  status, headers, body = app.call("HTTP_ACCEPT" => "text/html,application/xhtml+xml;q=0.9,*/*")
59
-
65
+
60
66
  headers["Content-Type"].should match /text\/html/
61
67
  end
62
-
68
+
63
69
  it "should log the exception" do
64
70
  logger = Object.new
65
71
  logger.should_receive :fatal
66
72
  BetterErrors.stub!(:logger).and_return(logger)
67
-
73
+
68
74
  app.call({})
69
75
  end
70
76
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: better_errors
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-14 00:00:00.000000000 Z
12
+ date: 2013-02-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -165,6 +165,7 @@ extensions: []
165
165
  extra_rdoc_files: []
166
166
  files:
167
167
  - .gitignore
168
+ - .travis.yml
168
169
  - .yardopts
169
170
  - CONTRIBUTING.md
170
171
  - Gemfile
@@ -211,13 +212,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
211
212
  requirements:
212
213
  - - '>='
213
214
  - !ruby/object:Gem::Version
214
- version: '0'
215
+ version: 1.9.2
215
216
  required_rubygems_version: !ruby/object:Gem::Requirement
216
217
  none: false
217
218
  requirements:
218
219
  - - '>='
219
220
  - !ruby/object:Gem::Version
220
221
  version: '0'
222
+ segments:
223
+ - 0
224
+ hash: -156735969867517913
221
225
  requirements: []
222
226
  rubyforge_project:
223
227
  rubygems_version: 1.8.25
@@ -235,3 +239,4 @@ test_files:
235
239
  - spec/better_errors/support/my_source.rb
236
240
  - spec/better_errors_spec.rb
237
241
  - spec/spec_helper.rb
242
+ has_rdoc: