web-console 3.7.0 → 4.1.0

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: 1e0540ac7a81a49deaad0b10cd764ca4d02ca2e9a630ef6d775051dec6e5ef55
4
- data.tar.gz: 80352b0d87ea7718cd08597c159d67edbafb2e5f9e46f674f48d1011a7118fc1
3
+ metadata.gz: 1e582f6eaaeff0b5fd7bedde53a6101c43eb8b5b86cda5f2a0e5a535b10c7bfc
4
+ data.tar.gz: 5ed7fe9a6bbb404eb7c1a9d4e594a559ca7e65f5184f342a1882cb33152aac2b
5
5
  SHA512:
6
- metadata.gz: e954cedb636a015d9cb86ddc60e4e97e44f61df6d7eaac89144c2b7b39207883117186c81420d2e90719f42d9acc6d397842f6750600b04681db47093c4e506a
7
- data.tar.gz: c091ef07d8462544f8f8367143a5b1ef8579a901cb1cfd88e463a2a37e3955f8c769f7a3206b2b4da442db27c3743a5e86ce9c69f82a6f954d1301d4e7629055
6
+ metadata.gz: 9805b430a93e04d8b1865efbb1c10824cd198f79fe8ba3bb2e4b934de2eed777f09c13200d3f07a4db82cf09285c8ea6e60b505186d86ac0d52e45ab937f3130
7
+ data.tar.gz: ac73f59d7603a019b5a0c96cb7d2583ee8280198dbd719a071c7b77af71650cfd7333c7bb481f98552ba7ed933ddbc3ee00e235292a4c337e2520d71e10975a9
@@ -2,6 +2,40 @@
2
2
 
3
3
  ## master (unreleased)
4
4
 
5
+ ## 4.1.0
6
+
7
+ * [#304](https://github.com/rails/web-console/pull/304) Add support for Rails 6.1 ([@stephannv])
8
+ * [#298](https://github.com/rails/web-console/pull/298) Prevent deprecation warnings by removing template formats ([@mikelkew])
9
+ * [#297](https://github.com/rails/web-console/pull/297) Use MutationObserver instead of Mutation Events ([@mikelkew])
10
+ * [#296](https://github.com/rails/web-console/pull/296) Add CSP nonce to injected scripts and styles ([@mikelkew])
11
+
12
+ ## 4.0.4
13
+
14
+ * [fb483743](https://github.com/rails/web-console/commit/fb483743a6a2a4168cdc0b2e03f48fc393991b73) Fix a crash on webrick with Rack 2.2.3 ([@gsamokovarov])
15
+
16
+ ## 4.0.3
17
+
18
+ * [#291](https://github.com/rails/web-console/pull/291) Deprecate config.web_console.whitelisted_ips ([@JuanitoFatas])
19
+ * [#290](https://github.com/rails/web-console/pull/290) Fix Content-Length for rack >= 2.1.0 ([@p8])
20
+
21
+ ## 4.0.2
22
+
23
+ * [#285](https://github.com/rails/web-console/pull/285) Increase timeout on paste ([@celvro])
24
+
25
+ ## 4.0.1
26
+
27
+ * [#279](https://github.com/rails/web-console/pull/279) Fix initial config.web_console.permissions value ([@patorash])
28
+
29
+ ## 4.0.0
30
+
31
+ * [61ce65b5](https://github.com/rails/web-console/commit/61ce65b599f56809de1bd8da6590a80acbd92017) Move to config.web_console.permissions ([@gsamokovarov])
32
+ * [96127ac1](https://github.com/rails/web-console/commit/96127aac143e1e653fffdc4bb65e1ce0b5ff342d) Introduce Binding#console as an alternative interface ([@gsamokovarov])
33
+ * [d4591ca5](https://github.com/rails/web-console/commit/d4591ca5396ed15a08818f3da11134852a485b27) Introduce Rails 6 support ([@gsamokovarov])
34
+ * [f97d8a88](https://github.com/rails/web-console/commit/f97d8a889a38366485e5c5e8985995c19bf61d13) Introduce Ruby 2.6 support ([@gsamokovarov])
35
+ * [d6deacd9](https://github.com/rails/web-console/commit/d6deacd9d5fcaabf3e3051d6985b53f924f86956) Drop Rails 5 support ([@gsamokovarov])
36
+ * [90fda878](https://github.com/rails/web-console/commit/90fda8789d402f05647c18f8cdf8e5c3d01692dd) Drop Ruby 2.4 support ([@gsamokovarov])
37
+ * [#265](https://github.com/rails/web-console/pull/265) Add support for nested exceptions ([@yuki24])
38
+
5
39
  ## 3.7.0
6
40
 
7
41
  * [#263](https://github.com/rails/web-console/pull/263) Show binding changes ([@causztic])
@@ -118,6 +152,8 @@ go to 3.1.0 instead.
118
152
  * [#84](https://github.com/rails/web-console/pull/84) Allow Rails 5 as dependency in gemspec ([@jonatack])
119
153
  * [#69](https://github.com/rails/web-console/pull/69) Introduce middleware for request dispatch and console rendering ([@gsamokovarov])
120
154
 
155
+ [@stephannv]: https://github.com/stephannv
156
+ [@mikelkew]: https://github.com/mikelkew
121
157
  [@jonatack]: https://github.com/jonatack
122
158
  [@ryandao]: https://github.com/ryandao
123
159
  [@jeffnv]: https://github.com/jeffnv
@@ -138,3 +174,8 @@ go to 3.1.0 instead.
138
174
  [@fl0l0u]: https://github.com/fl0l0u
139
175
  [@timomeh]: https://github.com/timomeh
140
176
  [@causztic]: https://github.com/causztic
177
+ [@yuki24]: https://github.com/yuki24
178
+ [@patorash]: https://github.com/patorash
179
+ [@celvro]: https://github.com/celvro
180
+ [@JuanitoFatas]: https://github.com/JuanitoFatas
181
+ [@p8]: https://github.com/p8
@@ -1,7 +1,8 @@
1
1
  <p align=right>
2
- Documentation for:
2
+ <strong>Current version: 4.1.0</strong> Documentation for:
3
3
  <a href=https://github.com/rails/web-console/tree/v1.0.4>v1.0.4</a>
4
4
  <a href=https://github.com/rails/web-console/tree/v2.2.1>v2.2.1</a>
5
+ <a href=https://github.com/rails/web-console/tree/v3.7.0>v3.7.0</a>
5
6
  </p>
6
7
 
7
8
  # Web Console [![Build Status](https://travis-ci.org/rails/web-console.svg?branch=master)](https://travis-ci.org/rails/web-console)
@@ -16,7 +17,7 @@ _Web Console_ is a debugging tool for your Ruby on Rails applications.
16
17
 
17
18
  ## Installation
18
19
 
19
- Add the following to your `Gemfile`.
20
+ Add the following to your `Gemfile`:
20
21
 
21
22
  ```ruby
22
23
  group :development do
@@ -27,8 +28,8 @@ end
27
28
  ## Usage
28
29
 
29
30
  The web console allows you to create an interactive Ruby session in your
30
- browser. Those sessions are launched automatically in case of an error, but
31
- they can also be launched manually in any page.
31
+ browser. Those sessions are launched automatically in case of an error and can
32
+ also be launched manually in any page.
32
33
 
33
34
  For example, calling `console` in a view will display a console in the current
34
35
  page in the context of the view binding.
@@ -56,30 +57,30 @@ have multiple ones, `WebConsole::DoubleRenderError` will be raised.
56
57
 
57
58
  ## Configuration
58
59
 
59
- _Web Console_ allows you to execute arbitrary code on the server, so you
60
- should be very careful, who you give access to.
60
+ _Web Console_ allows you to execute arbitrary code on the server. Therefore, be
61
+ very careful who you give access to.
61
62
 
62
- ### config.web_console.whitelisted_ips
63
+ ### config.web_console.permissions
63
64
 
64
65
  By default, only requests coming from IPv4 and IPv6 localhosts are allowed.
65
66
 
66
- `config.web_console.whitelisted_ips` lets you control which IP's have access to
67
+ `config.web_console.permissions` lets you control which IP's have access to
67
68
  the console.
68
69
 
69
- You can whitelist single IP's or whole networks. Say you want to share your
70
- console with `192.168.0.100`. You can do this:
70
+ You can allow single IP's or whole networks. Say you want to share your
71
+ console with `192.168.0.100`:
71
72
 
72
73
  ```ruby
73
74
  class Application < Rails::Application
74
- config.web_console.whitelisted_ips = '192.168.0.100'
75
+ config.web_console.permissions = '192.168.0.100'
75
76
  end
76
77
  ```
77
78
 
78
- If you want to whitelist the whole private network, you can do:
79
+ If you want to allow the whole private network:
79
80
 
80
81
  ```ruby
81
82
  Rails.application.configure do
82
- config.web_console.whitelisted_ips = '192.168.0.0/16'
83
+ config.web_console.permissions = '192.168.0.0/16'
83
84
  end
84
85
  ```
85
86
 
@@ -88,8 +89,8 @@ case in 2.0.
88
89
 
89
90
  ### config.web_console.whiny_requests
90
91
 
91
- When a console cannot be shown for a given IP address or content type, a
92
- messages like the following is printed in the server logs:
92
+ When a console cannot be shown for a given IP address or content type,
93
+ messages such as the following is printed in the server logs:
93
94
 
94
95
  > Cannot render console from 192.168.1.133! Allowed networks:
95
96
  > 127.0.0.0/127.255.255.255, ::1
@@ -104,7 +105,7 @@ end
104
105
 
105
106
  ### config.web_console.template_paths
106
107
 
107
- If you want to style the console yourself, you can place `style.css` at a
108
+ If you want to style the console yourself, then you can place `style.css` at a
108
109
  directory pointed by `config.web_console.template_paths`:
109
110
 
110
111
  ```ruby
@@ -119,8 +120,8 @@ may override.
119
120
  ### config.web_console.mount_point
120
121
 
121
122
  Usually the middleware of _Web Console_ is mounted at `/__web_console`.
122
- If you want to change the path for some reasons, you can specify it
123
- by `config.web_console.mount_point`:
123
+ If there is a need to change the path, then you can specify it by
124
+ `config.web_console.mount_point`:
124
125
 
125
126
  ```ruby
126
127
  Rails.application.configure do
@@ -132,7 +133,7 @@ end
132
133
 
133
134
  ### Where did /console go?
134
135
 
135
- The remote terminal emulator was extracted in its own gem that is no longer
136
+ The remote terminal emulator was extracted in its own gem which is no longer
136
137
  bundled with _Web Console_.
137
138
 
138
139
  If you miss this feature, check out [rvt].
@@ -140,11 +141,11 @@ If you miss this feature, check out [rvt].
140
141
  ### Why do I constantly get unavailable session errors?
141
142
 
142
143
  All of _Web Console_ sessions are stored in memory. If you happen to run on a
143
- multi-process server (like Unicorn) you may get unavailable session errors
144
+ multi-process server (like Unicorn), you may encounter unavailable session errors
144
145
  while the server is still running. This is because a request may hit a
145
146
  different worker (process) that doesn't have the desired session in memory.
146
147
  To avoid that, if you use such servers in development, configure them so they
147
- server requests only out of one process.
148
+ serve requests only out of one process.
148
149
 
149
150
  #### Passenger
150
151
 
@@ -11,12 +11,14 @@ module WebConsole
11
11
  autoload :ExceptionMapper
12
12
  autoload :Session
13
13
  autoload :Injector
14
+ autoload :Interceptor
14
15
  autoload :Request
15
16
  autoload :WhinyRequest
16
- autoload :Whitelist
17
+ autoload :Permissions
17
18
  autoload :Template
18
19
  autoload :Middleware
19
20
  autoload :Context
21
+ autoload :SourceLocation
20
22
 
21
23
  autoload_at "web_console/errors" do
22
24
  autoload :Error
@@ -8,9 +8,11 @@ module WebConsole
8
8
  # return a string and will format exception output.
9
9
  class Evaluator
10
10
  # Cleanses exceptions raised inside #eval.
11
- cattr_reader :cleaner
12
- @@cleaner = ActiveSupport::BacktraceCleaner.new
13
- @@cleaner.add_silencer { |line| line.start_with?(File.expand_path("..", __FILE__)) }
11
+ cattr_reader :cleaner, default: begin
12
+ cleaner = ActiveSupport::BacktraceCleaner.new
13
+ cleaner.add_silencer { |line| line.start_with?(File.expand_path("..", __FILE__)) }
14
+ cleaner
15
+ end
14
16
 
15
17
  def initialize(binding = TOPLEVEL_BINDING)
16
18
  @binding = binding
@@ -2,9 +2,28 @@
2
2
 
3
3
  module WebConsole
4
4
  class ExceptionMapper
5
+ attr_reader :exc
6
+
7
+ def self.follow(exc)
8
+ mappers = [new(exc)]
9
+
10
+ while cause = (cause || exc).cause
11
+ mappers << new(cause)
12
+ end
13
+
14
+ mappers
15
+ end
16
+
17
+ def self.find_binding(mappers, exception_object_id)
18
+ mappers.detect do |exception_mapper|
19
+ exception_mapper.exc.object_id == exception_object_id.to_i
20
+ end || mappers.first
21
+ end
22
+
5
23
  def initialize(exception)
6
24
  @backtrace = exception.backtrace
7
25
  @bindings = exception.bindings
26
+ @exc = exception
8
27
  end
9
28
 
10
29
  def first
@@ -22,13 +41,15 @@ module WebConsole
22
41
  line = line.to_i
23
42
 
24
43
  @bindings.find do |binding|
25
- binding.eval("__FILE__") == file && binding.eval("__LINE__") == line
44
+ source_location = SourceLocation.new(binding)
45
+ source_location.path == file && source_location.lineno == line
26
46
  end
27
47
  end
28
48
 
29
49
  def guess_the_first_application_binding
30
50
  @bindings.find do |binding|
31
- binding.eval("__FILE__").to_s.start_with?(Rails.root.to_s)
51
+ source_location = SourceLocation.new(binding)
52
+ source_location.path.to_s.start_with?(Rails.root.to_s)
32
53
  end
33
54
  end
34
55
  end
@@ -8,8 +8,8 @@ module Kernel
8
8
  # If +binding+ isn't explicitly given it will default to the binding of the
9
9
  # previous frame. E.g. the one that invoked +console+.
10
10
  #
11
- # Raises DoubleRenderError if a double +console+ invocation per request is
12
- # detected.
11
+ # Raises +DoubleRenderError+ if a more than one +console+ invocation per
12
+ # request is detected.
13
13
  def console(binding = Bindex.current_bindings.second)
14
14
  raise WebConsole::DoubleRenderError if Thread.current[:__web_console_binding]
15
15
 
@@ -22,26 +22,13 @@ module Kernel
22
22
  end
23
23
  end
24
24
 
25
- module ActionDispatch
26
- class DebugExceptions
27
- def render_exception_with_web_console(request, exception)
28
- render_exception_without_web_console(request, exception).tap do
29
- backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
30
- error = ExceptionWrapper.new(backtrace_cleaner, exception).exception
31
-
32
- # Get the original exception if ExceptionWrapper decides to follow it.
33
- Thread.current[:__web_console_exception] = error
34
-
35
- # ActionView::Template::Error bypass ExceptionWrapper original
36
- # exception following. The backtrace in the view is generated from
37
- # reaching out to original_exception in the view.
38
- if error.is_a?(ActionView::Template::Error)
39
- Thread.current[:__web_console_exception] = error.cause
40
- end
41
- end
42
- end
43
-
44
- alias_method :render_exception_without_web_console, :render_exception
45
- alias_method :render_exception, :render_exception_with_web_console
25
+ class Binding
26
+ # Instructs Web Console to render a console in the current binding, without
27
+ # the need to unroll the stack.
28
+ #
29
+ # Raises +DoubleRenderError+ if a more than one +console+ invocation per
30
+ # request is detected.
31
+ def console
32
+ Kernel.console(self)
46
33
  end
47
34
  end
@@ -13,9 +13,11 @@ module WebConsole
13
13
  end
14
14
 
15
15
  def inject(content)
16
- # Remove any previously set Content-Length header because we modify
17
- # the body. Otherwise the response will be truncated.
18
- @headers.delete("Content-Length")
16
+ # Set Content-Length header to the size of the current body
17
+ # + the extra content. Otherwise the response will be truncated.
18
+ if @headers["Content-Length"]
19
+ @headers["Content-Length"] = (@body.bytesize + content.bytesize).to_s
20
+ end
19
21
 
20
22
  [
21
23
  if position = @body.rindex("</body>")
@@ -0,0 +1,18 @@
1
+ module WebConsole
2
+ module Interceptor
3
+ def self.call(request, exception)
4
+ backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner")
5
+ error = ActionDispatch::ExceptionWrapper.new(backtrace_cleaner, exception).exception
6
+
7
+ # Get the original exception if ExceptionWrapper decides to follow it.
8
+ Thread.current[:__web_console_exception] = error
9
+
10
+ # ActionView::Template::Error bypass ExceptionWrapper original
11
+ # exception following. The backtrace in the view is generated from
12
+ # reaching out to original_exception in the view.
13
+ if error.is_a?(ActionView::Template::Error)
14
+ Thread.current[:__web_console_exception] = error.cause
15
+ end
16
+ end
17
+ end
18
+ end
@@ -6,11 +6,8 @@ module WebConsole
6
6
  class Middleware
7
7
  TEMPLATES_PATH = File.expand_path("../templates", __FILE__)
8
8
 
9
- cattr_accessor :mount_point
10
- @@mount_point = "/__web_console"
11
-
12
- cattr_accessor :whiny_requests
13
- @@whiny_requests = true
9
+ cattr_accessor :mount_point, default: "/__web_console"
10
+ cattr_accessor :whiny_requests, default: true
14
11
 
15
12
  def initialize(app)
16
13
  @app = app
@@ -19,7 +16,7 @@ module WebConsole
19
16
  def call(env)
20
17
  app_exception = catch :app_exception do
21
18
  request = create_regular_or_whiny_request(env)
22
- return call_app(env) unless request.from_whitelisted_ip?
19
+ return call_app(env) unless request.permitted?
23
20
 
24
21
  if id = id_for_repl_session_update(request)
25
22
  return update_repl_session(id, request)
@@ -27,6 +24,7 @@ module WebConsole
27
24
  return change_stack_trace(id, request)
28
25
  end
29
26
 
27
+
30
28
  status, headers, body = call_app(env)
31
29
 
32
30
  if (session = Session.from(Thread.current)) && acceptable_content_type?(headers)
@@ -54,7 +52,7 @@ module WebConsole
54
52
  private
55
53
 
56
54
  def acceptable_content_type?(headers)
57
- Mime::Type.parse(headers["Content-Type"].to_s).first == Mime[:html]
55
+ headers["Content-Type"].to_s.include?("html")
58
56
  end
59
57
 
60
58
  def json_response(opts = {})
@@ -66,7 +64,6 @@ module WebConsole
66
64
  end
67
65
 
68
66
  def json_response_with_session(id, request, opts = {})
69
- return respond_with_unacceptable_request unless request.acceptable?
70
67
  return respond_with_unavailable_session(id) unless session = Session.find(id)
71
68
 
72
69
  json_response(opts) { yield session }
@@ -113,7 +110,7 @@ module WebConsole
113
110
 
114
111
  def change_stack_trace(id, request)
115
112
  json_response_with_session(id, request) do |session|
116
- session.switch_binding_to(request.params[:frame_id])
113
+ session.switch_binding_to(request.params[:frame_id], request.params[:exception_object_id])
117
114
 
118
115
  { ok: true }
119
116
  end
@@ -3,20 +3,16 @@
3
3
  require "ipaddr"
4
4
 
5
5
  module WebConsole
6
- # Whitelist of allowed networks that can access Web Console.
7
- #
8
- # Networks are represented by standard IPAddr and can be either IPv4 or IPv6
9
- # networks.
10
- class Whitelist
11
- # IPv4 and IPv6 localhost should be always whitelisted.
12
- ALWAYS_WHITELISTED_NETWORKS = %w( 127.0.0.0/8 ::1 )
6
+ class Permissions
7
+ # IPv4 and IPv6 localhost should be always allowed.
8
+ ALWAYS_PERMITTED_NETWORKS = %w( 127.0.0.0/8 ::1 )
13
9
 
14
10
  def initialize(networks = nil)
15
11
  @networks = normalize_networks(networks).map(&method(:coerce_network_to_ipaddr)).uniq
16
12
  end
17
13
 
18
14
  def include?(network)
19
- @networks.any? { |whitelist| whitelist.include?(network.to_s) }
15
+ @networks.any? { |permission| permission.include?(network.to_s) }
20
16
  rescue IPAddr::InvalidAddressError
21
17
  false
22
18
  end
@@ -28,7 +24,7 @@ module WebConsole
28
24
  private
29
25
 
30
26
  def normalize_networks(networks)
31
- Array(networks).concat(ALWAYS_WHITELISTED_NETWORKS)
27
+ Array(networks).concat(ALWAYS_PERMITTED_NETWORKS)
32
28
  end
33
29
 
34
30
  def coerce_network_to_ipaddr(network)
@@ -5,11 +5,12 @@ require "rails/railtie"
5
5
  module WebConsole
6
6
  class Railtie < ::Rails::Railtie
7
7
  config.web_console = ActiveSupport::OrderedOptions.new
8
- config.web_console.whitelisted_ips = %w( 127.0.0.1 ::1 )
9
8
 
10
9
  initializer "web_console.initialize" do
11
10
  require "bindex"
12
11
  require "web_console/extensions"
12
+
13
+ ActionDispatch::DebugExceptions.register_interceptor(Interceptor)
13
14
  end
14
15
 
15
16
  initializer "web_console.development_only" do
@@ -50,9 +51,23 @@ module WebConsole
50
51
  end
51
52
  end
52
53
 
53
- initializer "web_console.whitelisted_ips" do
54
- if whitelisted_ips = config.web_console.whitelisted_ips
55
- Request.whitelisted_ips = Whitelist.new(whitelisted_ips)
54
+ initializer "web_console.permissions" do
55
+ permissions = web_console_permissions
56
+ Request.permissions = Permissions.new(permissions)
57
+ end
58
+
59
+ def web_console_permissions
60
+ case
61
+ when config.web_console.permissions
62
+ config.web_console.permissions
63
+ when config.web_console.allowed_ips
64
+ config.web_console.allowed_ips
65
+ when config.web_console.whitelisted_ips
66
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
67
+ The config.web_console.whitelisted_ips is deprecated and will be ignored in future release of web_console.
68
+ Please use config.web_console.allowed_ips instead.
69
+ MSG
70
+ config.web_console.whitelisted_ips
56
71
  end
57
72
  end
58
73
 
@@ -1,35 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebConsole
4
- # Web Console tailored request object.
5
4
  class Request < ActionDispatch::Request
6
- # Configurable set of whitelisted networks.
7
- cattr_accessor :whitelisted_ips
8
- @@whitelisted_ips = Whitelist.new
5
+ cattr_accessor :permissions, default: Permissions.new
9
6
 
10
- # Define a vendor MIME type. We can call it using Mime[:web_console_v2].
11
- Mime::Type.register "application/vnd.web-console.v2", :web_console_v2
12
-
13
- # Returns whether a request came from a whitelisted IP.
14
- #
15
- # For a request to hit Web Console features, it needs to come from a white
16
- # listed IP.
17
- def from_whitelisted_ip?
18
- whitelisted_ips.include?(strict_remote_ip)
7
+ def permitted?
8
+ permissions.include?(strict_remote_ip)
19
9
  end
20
10
 
21
- # Determines the remote IP using our much stricter whitelist.
22
11
  def strict_remote_ip
23
- GetSecureIp.new(self, whitelisted_ips).to_s
12
+ GetSecureIp.new(self, permissions).to_s
24
13
  rescue ActionDispatch::RemoteIp::IpSpoofAttackError
25
14
  "[Spoofed]"
26
15
  end
27
16
 
28
- # Returns whether the request is acceptable.
29
- def acceptable?
30
- xhr? && accepts.any? { |mime| Mime[:web_console_v2] == mime }
31
- end
32
-
33
17
  private
34
18
 
35
19
  class GetSecureIp < ActionDispatch::RemoteIp::GetIp
@@ -11,8 +11,7 @@ module WebConsole
11
11
  # error pages only, as currently, this is the only client that needs to do
12
12
  # that.
13
13
  class Session
14
- cattr_reader :inmemory_storage
15
- @@inmemory_storage = {}
14
+ cattr_reader :inmemory_storage, default: {}
16
15
 
17
16
  class << self
18
17
  # Finds a persisted session in memory by its id.
@@ -32,9 +31,9 @@ module WebConsole
32
31
  # storage.
33
32
  def from(storage)
34
33
  if exc = storage[:__web_console_exception]
35
- new(ExceptionMapper.new(exc))
34
+ new(ExceptionMapper.follow(exc))
36
35
  elsif binding = storage[:__web_console_binding]
37
- new([binding])
36
+ new([[binding]])
38
37
  end
39
38
  end
40
39
  end
@@ -42,10 +41,11 @@ module WebConsole
42
41
  # An unique identifier for every REPL.
43
42
  attr_reader :id
44
43
 
45
- def initialize(bindings)
44
+ def initialize(exception_mappers)
46
45
  @id = SecureRandom.hex(16)
47
- @bindings = bindings
48
- @evaluator = Evaluator.new(@current_binding = bindings.first)
46
+
47
+ @exception_mappers = exception_mappers
48
+ @evaluator = Evaluator.new(@current_binding = exception_mappers.first.first)
49
49
 
50
50
  store_into_memory
51
51
  end
@@ -60,8 +60,10 @@ module WebConsole
60
60
  # Switches the current binding to the one at specified +index+.
61
61
  #
62
62
  # Returns nothing.
63
- def switch_binding_to(index)
64
- @evaluator = Evaluator.new(@current_binding = @bindings[index.to_i])
63
+ def switch_binding_to(index, exception_object_id)
64
+ bindings = ExceptionMapper.find_binding(@exception_mappers, exception_object_id)
65
+
66
+ @evaluator = Evaluator.new(@current_binding = bindings[index.to_i])
65
67
  end
66
68
 
67
69
  # Returns context of the current binding
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class SourceLocation
4
+ def initialize(binding)
5
+ @binding = binding
6
+ end
7
+
8
+ if RUBY_VERSION >= "2.6"
9
+ def path() @binding.source_location.first end
10
+ def lineno() @binding.source_location.last end
11
+ else
12
+ def path() @binding.eval("__FILE__") end
13
+ def lineno() @binding.eval("__LINE__") end
14
+ end
15
+ end
@@ -7,8 +7,7 @@ module WebConsole
7
7
  # Rails error pages.
8
8
  class Template
9
9
  # Lets you customize the default templates folder location.
10
- cattr_accessor :template_paths
11
- @@template_paths = [ File.expand_path("../templates", __FILE__) ]
10
+ cattr_accessor :template_paths, default: [ File.expand_path("../templates", __FILE__) ]
12
11
 
13
12
  def initialize(env, session)
14
13
  @env = env
@@ -18,7 +17,7 @@ module WebConsole
18
17
 
19
18
  # Render a template (inferred from +template_paths+) as a plain string.
20
19
  def render(template)
21
- view = View.new(template_paths, instance_values)
20
+ view = View.with_empty_template_cache.with_view_paths(template_paths, instance_values)
22
21
  view.render(template: template, layout: false)
23
22
  end
24
23
  end
@@ -251,12 +251,14 @@ Autocomplete.prototype.removeView = function() {
251
251
  }
252
252
 
253
253
  // HTML strings for dynamic elements.
254
- var consoleInnerHtml = <%= render_inlined_string '_inner_console_markup.html' %>;
255
- var promptBoxHtml = <%= render_inlined_string '_prompt_box_markup.html' %>;
254
+ var consoleInnerHtml = <%= render_inlined_string '_inner_console_markup' %>;
255
+ var promptBoxHtml = <%= render_inlined_string '_prompt_box_markup' %>;
256
256
  // CSS
257
- var consoleStyleCss = <%= render_inlined_string 'style.css' %>;
257
+ var consoleStyleCss = <%= render_inlined_string 'style' %>;
258
258
  // Insert a style element with the unique ID
259
259
  var styleElementId = 'sr02459pvbvrmhco';
260
+ // Nonce to use for CSP
261
+ var styleElementNonce = '<%= @nonce %>';
260
262
 
261
263
  // REPLConsole Constructor
262
264
  function REPLConsole(config) {
@@ -380,8 +382,13 @@ REPLConsole.prototype.install = function(container) {
380
382
  var clientHeightStart = consoleOuter.clientHeight;
381
383
 
382
384
  var doDrag = function(e) {
383
- container.style.height = (startHeight + startY - e.clientY) + 'px';
385
+ var height = startHeight + startY - e.clientY;
384
386
  consoleOuter.scrollTop = scrollTopStart + (clientHeightStart - consoleOuter.clientHeight);
387
+ if (height > document.documentElement.clientHeight) {
388
+ container.style.height = document.documentElement.clientHeight;
389
+ } else {
390
+ container.style.height = height + 'px';
391
+ }
385
392
  shiftConsoleActions();
386
393
  };
387
394
 
@@ -411,6 +418,14 @@ REPLConsole.prototype.install = function(container) {
411
418
  }
412
419
  }
413
420
 
421
+ var observer = new MutationObserver(function(mutationsList) {
422
+ for (let mutation of mutationsList) {
423
+ if (mutation.type === 'childList' && mutation.addedNodes.length > 0) {
424
+ shiftConsoleActions();
425
+ }
426
+ }
427
+ });
428
+
414
429
  // Initialize
415
430
  this.container = container;
416
431
  this.outer = consoleOuter;
@@ -422,7 +437,7 @@ REPLConsole.prototype.install = function(container) {
422
437
 
423
438
  findChild(container, 'resizer').addEventListener('mousedown', resizeContainer);
424
439
  findChild(consoleActions, 'close-button').addEventListener('click', closeContainer);
425
- consoleOuter.addEventListener('DOMNodeInserted', shiftConsoleActions);
440
+ observer.observe(consoleOuter, { childList: true, subtree: true });
426
441
 
427
442
  REPLConsole.currentSession = this;
428
443
  };
@@ -436,6 +451,9 @@ REPLConsole.prototype.insertCss = function() {
436
451
  style.type = 'text/css';
437
452
  style.innerHTML = consoleStyleCss;
438
453
  style.id = styleElementId;
454
+ if (styleElementNonce.length > 0) {
455
+ style.nonce = styleElementNonce;
456
+ }
439
457
  document.getElementsByTagName('head')[0].appendChild(style);
440
458
  };
441
459
 
@@ -755,7 +773,7 @@ REPLConsole.prototype.onKeyDown = function(ev) {
755
773
  _this.addToInput(_this.clipboard.value);
756
774
  _this.clipboard.value = "";
757
775
  _this.clipboard.blur();
758
- }, 10);
776
+ }, 100);
759
777
  }
760
778
  }
761
779
 
@@ -871,10 +889,14 @@ REPLConsole.prototype.scrollToBottom = function() {
871
889
  };
872
890
 
873
891
  // Change the binding of the console.
874
- REPLConsole.prototype.switchBindingTo = function(frameId, callback) {
892
+ REPLConsole.prototype.switchBindingTo = function(frameId, exceptionObjectId, callback) {
875
893
  var url = this.getSessionUrl('trace');
876
894
  var params = "frame_id=" + encodeURIComponent(frameId);
877
895
 
896
+ if (exceptionObjectId) {
897
+ params = params + "&exception_object_id=" + encodeURIComponent(exceptionObjectId);
898
+ }
899
+
878
900
  var _this = this;
879
901
  postRequest(url, params, function() {
880
902
  var text = "Context has changed to: " + callback();
@@ -915,7 +937,6 @@ REPLConsole.request = function request(method, url, params, callback) {
915
937
  xhr.open(method, url, true);
916
938
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
917
939
  xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
918
- xhr.setRequestHeader("Accept", "<%= Mime[:web_console_v2] %>");
919
940
  xhr.send(params);
920
941
 
921
942
  xhr.onreadystatechange = function() {
@@ -8,9 +8,10 @@ for (var i = 0; i < traceFrames.length; i++) {
8
8
  e.preventDefault();
9
9
  var target = e.target;
10
10
  var frameId = target.dataset.frameId;
11
+ var exceptionObjectId = target.dataset.exceptionObjectId;
11
12
 
12
13
  // Change the binding of the console.
13
- changeBinding(frameId, function() {
14
+ changeBinding(frameId, exceptionObjectId, function() {
14
15
  // Rails already handles toggling the select class
15
16
  selectedFrame = target;
16
17
  return target.innerHTML;
@@ -22,8 +23,8 @@ for (var i = 0; i < traceFrames.length; i++) {
22
23
  }
23
24
 
24
25
  // Change the binding of the current session and prompt the user.
25
- function changeBinding(frameId, callback) {
26
- REPLConsole.currentSession.switchBindingTo(frameId, callback);
26
+ function changeBinding(frameId, exceptionObjectId, callback) {
27
+ REPLConsole.currentSession.switchBindingTo(frameId, exceptionObjectId, callback);
27
28
  }
28
29
 
29
30
  function changeSourceExtract(frameId) {
@@ -1,4 +1,4 @@
1
- <script type="text/javascript" data-template="<%= @template %>">
1
+ <script type="text/javascript" data-template="<%= @template %>" nonce="<%= @nonce %>">
2
2
  (function() {
3
3
  <%= yield %>
4
4
  }).call(this);
@@ -1,34 +1,182 @@
1
- .console .pos-absolute { position: absolute; }
2
- .console .pos-fixed { position: fixed; }
3
- .console .pos-right { right: 0; }
4
- .console .border-box { box-sizing: border-box; }
5
- .console .layer { width: 100%; height: 100%; }
6
- .console .layer.console-outer { z-index: 1; }
7
- .console .layer.resizer { z-index: 2; }
8
- .console { position: fixed; left: 0; bottom: 0; width: 100%; height: 148px; padding: 0; margin: 0; background: none repeat scroll 0% 0% #333; z-index: 9999; }
9
- .console .console-outer { overflow: auto; padding-top: 4px; }
10
- .console .console-inner { font-family: monospace; font-size: 11px; width: 100%; height: 100%; overflow: none; background: #333; }
11
- .console .console-prompt-box { color: #FFF; }
12
- .console .console-message { color: #1AD027; margin: 0; border: 0; white-space: pre-wrap; background-color: #333; padding: 0; }
13
- .console .console-message.error-message { color: #FC9; }
14
- .console .console-message.notification-message { color: #99F; }
15
- .console .console-message.auto-complete { word-break: break-all; }
16
- .console .console-message.auto-complete .keyword { margin-right: 11px; }
17
- .console .console-message.auto-complete .keyword.selected { background: #FFF; color: #000; }
18
- .console .console-message.auto-complete .hidden { display: none; }
19
- .console .console-message.auto-complete .trimmed { display: none; }
20
- .console .console-hint { color: #096; }
21
- .console .console-focus .console-cursor { background: #FEFEFE; color: #333; font-weight: bold; }
22
- .console .resizer { background: #333; width: 100%; height: 4px; cursor: ns-resize; }
23
- .console .console-actions { padding-right: 3px; }
24
- .console .console-actions .button { float: left; }
25
- .console .button { cursor: pointer; border-radius: 1px; font-family: monospace; font-size: 13px; width: 14px; height: 14px; line-height: 14px; text-align: center; color: #CCC; }
26
- .console .button:hover { background: #666; color: #FFF; }
27
- .console .button.close-button:hover { background: #966; }
28
- .console .clipboard { height: 0px; padding: 0px; margin: 0px; width: 0px; margin-left: -1000px; }
29
- .console .console-prompt-label { display: inline; color: #FFF; background: none repeat scroll 0% 0% #333; border: 0; padding: 0; }
30
- .console .console-prompt-display { display: inline; color: #FFF; background: none repeat scroll 0% 0% #333; border: 0; padding: 0; }
31
- .console.full-screen { height: 100%; }
32
- .console.full-screen .console-outer { padding-top: 3px; }
33
- .console.full-screen .resizer { display: none; }
34
- .console.full-screen .close-button { display: none; }
1
+ .console .pos-absolute {
2
+ position: absolute;
3
+ }
4
+
5
+ .console .pos-fixed {
6
+ position: fixed;
7
+ }
8
+
9
+ .console .pos-right {
10
+ right: 0;
11
+ }
12
+
13
+ .console .border-box {
14
+ box-sizing: border-box;
15
+ }
16
+
17
+ .console .layer {
18
+ width: 100%;
19
+ height: 100%;
20
+ }
21
+
22
+ .console .layer.console-outer {
23
+ z-index: 1;
24
+ }
25
+
26
+ .console .layer.resizer {
27
+ z-index: 2;
28
+ }
29
+
30
+ .console {
31
+ position: fixed;
32
+ left: 0;
33
+ bottom: 0;
34
+ width: 100%;
35
+ height: 148px;
36
+ padding: 0;
37
+ margin: 0;
38
+ background: none repeat scroll 0% 0% #333;
39
+ z-index: 9999;
40
+ }
41
+
42
+ .console .console-outer {
43
+ overflow: auto;
44
+ padding-top: 4px;
45
+ }
46
+
47
+ .console .console-inner {
48
+ font-family: monospace;
49
+ font-size: 11px;
50
+ width: 100%;
51
+ height: 100%;
52
+ overflow: unset;
53
+ background: #333;
54
+ }
55
+
56
+ .console .console-prompt-box {
57
+ color: #fff;
58
+ }
59
+
60
+ .console .console-message {
61
+ color: #1ad027;
62
+ margin: 0;
63
+ border: 0;
64
+ white-space: pre-wrap;
65
+ background-color: #333;
66
+ padding: 0;
67
+ }
68
+
69
+ .console .console-message.error-message {
70
+ color: #fc9;
71
+ }
72
+
73
+ .console .console-message.notification-message {
74
+ color: #99f;
75
+ }
76
+
77
+ .console .console-message.auto-complete {
78
+ word-break: break-all;
79
+ }
80
+
81
+ .console .console-message.auto-complete .keyword {
82
+ margin-right: 11px;
83
+ }
84
+
85
+ .console .console-message.auto-complete .keyword.selected {
86
+ background: #fff;
87
+ color: #000;
88
+ }
89
+
90
+ .console .console-message.auto-complete .hidden {
91
+ display: none;
92
+ }
93
+
94
+ .console .console-message.auto-complete .trimmed {
95
+ display: none;
96
+ }
97
+
98
+ .console .console-hint {
99
+ color: #096;
100
+ }
101
+
102
+ .console .console-focus .console-cursor {
103
+ background: #fefefe;
104
+ color: #333;
105
+ font-weight: bold;
106
+ }
107
+
108
+ .console .resizer {
109
+ background: #333;
110
+ width: 100%;
111
+ height: 4px;
112
+ cursor: ns-resize;
113
+ }
114
+
115
+ .console .console-actions {
116
+ padding-right: 3px;
117
+ }
118
+
119
+ .console .console-actions .button {
120
+ float: left;
121
+ }
122
+
123
+ .console .button {
124
+ cursor: pointer;
125
+ border-radius: 1px;
126
+ font-family: monospace;
127
+ font-size: 13px;
128
+ width: 14px;
129
+ height: 14px;
130
+ line-height: 14px;
131
+ text-align: center;
132
+ color: #ccc;
133
+ }
134
+
135
+ .console .button:hover {
136
+ background: #666;
137
+ color: #fff;
138
+ }
139
+
140
+ .console .button.close-button:hover {
141
+ background: #966;
142
+ }
143
+
144
+ .console .clipboard {
145
+ height: 0px;
146
+ padding: 0px;
147
+ margin: 0px;
148
+ width: 0px;
149
+ margin-left: -1000px;
150
+ }
151
+
152
+ .console .console-prompt-label {
153
+ display: inline;
154
+ color: #fff;
155
+ background: none repeat scroll 0% 0% #333;
156
+ border: 0;
157
+ padding: 0;
158
+ }
159
+
160
+ .console .console-prompt-display {
161
+ display: inline;
162
+ color: #fff;
163
+ background: none repeat scroll 0% 0% #333;
164
+ border: 0;
165
+ padding: 0;
166
+ }
167
+
168
+ .console.full-screen {
169
+ height: 100%;
170
+ }
171
+
172
+ .console.full-screen .console-outer {
173
+ padding-top: 3px;
174
+ }
175
+
176
+ .console.full-screen .resizer {
177
+ display: none;
178
+ }
179
+
180
+ .console.full-screen .close-button {
181
+ display: none;
182
+ }
@@ -3,7 +3,6 @@
3
3
  require "action_view"
4
4
  require "web_console"
5
5
  require "web_console/testing/helper"
6
- Mime = { web_console_v2: "fake" }
7
6
 
8
7
  module WebConsole
9
8
  module Testing
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module WebConsole
4
- VERSION = "3.7.0"
4
+ VERSION = "4.1.0"
5
5
  end
@@ -22,6 +22,7 @@ module WebConsole
22
22
  # leaking globals, unless you explicitly want to.
23
23
  def render_javascript(template)
24
24
  assign(template: template)
25
+ assign(nonce: @env["action_dispatch.content_security_policy_nonce"])
25
26
  render(template: template, layout: "layouts/javascript")
26
27
  end
27
28
 
@@ -3,13 +3,13 @@
3
3
  module WebConsole
4
4
  # Noisy wrapper around +Request+.
5
5
  #
6
- # If any calls to +from_whitelisted_ip?+ and +acceptable_content_type?+
6
+ # If any calls to +permitted?+ and +acceptable_content_type?+
7
7
  # return false, an info log message will be displayed in users' logs.
8
8
  class WhinyRequest < SimpleDelegator
9
- def from_whitelisted_ip?
10
- whine_unless request.from_whitelisted_ip? do
9
+ def permitted?
10
+ whine_unless request.permitted? do
11
11
  "Cannot render console from #{request.strict_remote_ip}! " \
12
- "Allowed networks: #{request.whitelisted_ips}"
12
+ "Allowed networks: #{request.permissions}"
13
13
  end
14
14
  end
15
15
 
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: web-console
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.7.0
4
+ version: 4.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Somerville
8
8
  - Genadi Samokovarov
9
9
  - Guillermo Iguaran
10
10
  - Ryan Dao
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2018-09-02 00:00:00.000000000 Z
14
+ date: 2020-11-05 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: railties
@@ -19,42 +19,42 @@ dependencies:
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: '5.0'
22
+ version: 6.0.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: '5.0'
29
+ version: 6.0.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: activemodel
32
32
  requirement: !ruby/object:Gem::Requirement
33
33
  requirements:
34
34
  - - ">="
35
35
  - !ruby/object:Gem::Version
36
- version: '5.0'
36
+ version: 6.0.0
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
- version: '5.0'
43
+ version: 6.0.0
44
44
  - !ruby/object:Gem::Dependency
45
45
  name: actionview
46
46
  requirement: !ruby/object:Gem::Requirement
47
47
  requirements:
48
48
  - - ">="
49
49
  - !ruby/object:Gem::Version
50
- version: '5.0'
50
+ version: 6.0.0
51
51
  type: :runtime
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
55
  - - ">="
56
56
  - !ruby/object:Gem::Version
57
- version: '5.0'
57
+ version: 6.0.0
58
58
  - !ruby/object:Gem::Dependency
59
59
  name: bindex
60
60
  requirement: !ruby/object:Gem::Requirement
@@ -69,7 +69,7 @@ dependencies:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
71
  version: 0.4.0
72
- description:
72
+ description:
73
73
  email:
74
74
  - charlie@charliesomerville.com
75
75
  - gsamokovarov@gmail.com
@@ -91,11 +91,14 @@ files:
91
91
  - lib/web_console/exception_mapper.rb
92
92
  - lib/web_console/extensions.rb
93
93
  - lib/web_console/injector.rb
94
+ - lib/web_console/interceptor.rb
94
95
  - lib/web_console/locales/en.yml
95
96
  - lib/web_console/middleware.rb
97
+ - lib/web_console/permissions.rb
96
98
  - lib/web_console/railtie.rb
97
99
  - lib/web_console/request.rb
98
100
  - lib/web_console/session.rb
101
+ - lib/web_console/source_location.rb
99
102
  - lib/web_console/tasks/extensions.rake
100
103
  - lib/web_console/tasks/templates.rake
101
104
  - lib/web_console/template.rb
@@ -116,12 +119,11 @@ files:
116
119
  - lib/web_console/version.rb
117
120
  - lib/web_console/view.rb
118
121
  - lib/web_console/whiny_request.rb
119
- - lib/web_console/whitelist.rb
120
122
  homepage: https://github.com/rails/web-console
121
123
  licenses:
122
124
  - MIT
123
125
  metadata: {}
124
- post_install_message:
126
+ post_install_message:
125
127
  rdoc_options: []
126
128
  require_paths:
127
129
  - lib
@@ -129,16 +131,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
129
131
  requirements:
130
132
  - - ">="
131
133
  - !ruby/object:Gem::Version
132
- version: 2.2.2
134
+ version: '2.5'
133
135
  required_rubygems_version: !ruby/object:Gem::Requirement
134
136
  requirements:
135
137
  - - ">="
136
138
  - !ruby/object:Gem::Version
137
139
  version: '0'
138
140
  requirements: []
139
- rubyforge_project:
140
- rubygems_version: 2.7.6
141
- signing_key:
141
+ rubygems_version: 3.0.3
142
+ signing_key:
142
143
  specification_version: 4
143
144
  summary: A debugging tool for your Ruby on Rails applications.
144
145
  test_files: []