web-console 1.0.4 → 2.0.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 +4 -4
- data/README.markdown +26 -247
- data/lib/action_dispatch/debug_exceptions.rb +115 -0
- data/lib/action_dispatch/exception_wrapper.rb +15 -0
- data/lib/action_dispatch/templates/rescues/_request_and_response.html.erb +34 -0
- data/lib/action_dispatch/templates/rescues/_request_and_response.text.erb +23 -0
- data/lib/action_dispatch/templates/rescues/_source.erb +27 -0
- data/lib/action_dispatch/templates/rescues/_trace.html.erb +76 -0
- data/lib/action_dispatch/templates/rescues/_trace.text.erb +15 -0
- data/lib/action_dispatch/templates/rescues/_web_console.html.erb +382 -0
- data/lib/action_dispatch/templates/rescues/diagnostics.html.erb +18 -0
- data/lib/action_dispatch/templates/rescues/diagnostics.text.erb +9 -0
- data/lib/action_dispatch/templates/rescues/layout.erb +162 -0
- data/lib/action_dispatch/templates/rescues/missing_template.html.erb +7 -0
- data/lib/action_dispatch/templates/rescues/missing_template.text.erb +3 -0
- data/lib/action_dispatch/templates/rescues/routing_error.html.erb +30 -0
- data/lib/action_dispatch/templates/rescues/routing_error.text.erb +11 -0
- data/lib/action_dispatch/templates/rescues/template_error.html.erb +22 -0
- data/lib/action_dispatch/templates/rescues/template_error.text.erb +8 -0
- data/lib/action_dispatch/templates/rescues/unknown_action.html.erb +6 -0
- data/lib/action_dispatch/templates/rescues/unknown_action.text.erb +3 -0
- data/lib/web_console.rb +17 -7
- data/lib/web_console/exception_extension.rb +22 -0
- data/lib/web_console/railtie.rb +15 -0
- data/lib/web_console/repl.rb +24 -0
- data/lib/web_console/repl_session.rb +90 -0
- data/lib/web_console/version.rb +1 -1
- data/lib/web_console/view_helpers.rb +21 -0
- data/test/action_pack/exception_wrapper_test.rb +26 -0
- data/test/dummy/app/controllers/exception_test_controller.rb +11 -0
- data/test/dummy/app/controllers/helper_test_controller.rb +5 -0
- data/test/dummy/app/views/helper_test/index.html.erb +220 -0
- data/test/dummy/app/views/layouts/application.html.erb +2 -0
- data/test/dummy/config/application.rb +0 -34
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/db/development.sqlite3 +0 -0
- data/test/dummy/log/development.log +61270 -0
- data/test/dummy/log/test.log +3917 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/038461854af2e8bccdb29768efd4768f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/0ec396634a5f6808b026257fd107c355 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/127a54171eea8d294e4673599861787d +0 -0
- data/{app/assets/stylesheets/web_console/application.css → test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705} +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/17c571144b4e44da39bddb2d2c412414 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/1cb77d8cf661ccbc9de08f347c89b9f1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/204edd12a29660722d4e0d8de9bd6652 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2b96b037f3dfeccfe27113eb95b06ea1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2c853768baf811357d81d41bdfd05dcf +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/314d48e543146f617c4d3439a4d8d40d +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/34f21019a876722b8c24a6da4f0ef50b +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
- data/{vendor/assets/javascripts/term.js → test/dummy/tmp/cache/assets/development/sprockets/36341e42f23669574fa1027d0958ff3e} +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/44117154e909436e7eeaf10cdb18d2b4 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/496864a905d53afd8e176f29500f96a8 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/55b7b76605fdffe31d737d4ac1f1ef7b +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/5ac98782fe3dfd0a766f75ce1801f0a0 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6088d6f344b38303cc8028057d69e0f9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/676dcf9b2d01b9dc7bd3183d8da88463 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/680381170dc160e358fc28076ea6886c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6ad7acc9a22fe2a67ec24a1fc866c20e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6bdb0d0c602e0e1bc304dc697e2cc6de +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6dc8d7aa69668fce85683aaad6615432 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/6e4d5b32cc444226f6597198994ccd5e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/74db0ca5cb8c8c347c9131a3ff516748 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/7999e525c88173c1beb785f002effc1d +0 -0
- data/{lib/assets/javascripts/web_console.js → test/dummy/tmp/cache/assets/development/sprockets/7a50a9e605754e99783de95715b976b0} +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/806b0e33a2fe8e1245534345fa27c30a +0 -0
- data/{app/assets/javascripts/web_console/console_sessions.js → test/dummy/tmp/cache/assets/development/sprockets/8aa4c7aabff23c8089d41e9e54193483} +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/90396626cba6cbec37e32038e6c54e76 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/976b28910aa72c90a3b30c6e940f51df +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/99e1bd7cbc437505bc8f07bc528c721c +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/aaccf2c9ae2add0863c9a49e0042a097 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ae4677d24a79d9411f2fced5011d5807 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/b2401118729720034b6f3eda0b4c5025 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/c649837df826fc310cb80f1adafd6b8d +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cac185d59612fae451a12df3fc21bb51 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cb0065359d3b5b296f71d673f4b276e9 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cee8c6b09c33d2b276753e959712724e +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d1f6e06bc2f112c4ec3a4c3f68351878 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d20d83fd7ffa378b1b2b901786d640f3 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d38c7c3aa1e72b55769ccb3607641ef4 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d6b85d8b0b5c569388b89e56e9f6fed7 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/d982412def520c434e2240eae6d29cf2 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/df048a8b0897b9c04acdf59c8f95b18f +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/df600f50f002512c95d93bcfbab891ed +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/e6d6b8bde546349764be7b44ffcf5807 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/eb25265794d2f7afd1684779d84efdac +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ee8826b12b7d9bfd717df950b58f82ab +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/ef9824789c6ed3483590e0564a12e1d1 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
- data/test/dummy/tmp/cache/assets/development/sprockets/fc7201c6cbef32453aa4175c520c8eae +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/17c571144b4e44da39bddb2d2c412414 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/36341e42f23669574fa1027d0958ff3e +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/55b7b76605fdffe31d737d4ac1f1ef7b +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/5ac98782fe3dfd0a766f75ce1801f0a0 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/680381170dc160e358fc28076ea6886c +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/6ad7acc9a22fe2a67ec24a1fc866c20e +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/6e4d5b32cc444226f6597198994ccd5e +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/7a50a9e605754e99783de95715b976b0 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/8aa4c7aabff23c8089d41e9e54193483 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/b2401118729720034b6f3eda0b4c5025 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/cb0065359d3b5b296f71d673f4b276e9 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d1f6e06bc2f112c4ec3a4c3f68351878 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d6b85d8b0b5c569388b89e56e9f6fed7 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/d982412def520c434e2240eae6d29cf2 +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/df048a8b0897b9c04acdf59c8f95b18f +0 -0
- data/test/dummy/tmp/cache/assets/test/sprockets/e6d6b8bde546349764be7b44ffcf5807 +0 -0
- data/test/web_console/exception_extention_test.rb +16 -0
- data/test/web_console/repl_session_test.rb +32 -0
- data/test/web_console/repl_test.rb +26 -0
- metadata +191 -58
- data/app/assets/javascripts/web_console/application.js +0 -1
- data/app/assets/stylesheets/web_console/console_sessions.css.erb +0 -6
- data/app/controllers/web_console/application_controller.rb +0 -13
- data/app/controllers/web_console/console_sessions_controller.rb +0 -43
- data/app/helpers/web_console/application_helper.rb +0 -4
- data/app/helpers/web_console/console_session_helper.rb +0 -4
- data/app/models/web_console/console_session.rb +0 -96
- data/app/views/layouts/web_console/application.html.erb +0 -14
- data/app/views/web_console/console_sessions/index.html.erb +0 -15
- data/config/routes.rb +0 -11
- data/lib/assets/javascripts/web-console.js +0 -1
- data/lib/web_console/colors.rb +0 -87
- data/lib/web_console/colors/light.rb +0 -24
- data/lib/web_console/colors/monokai.rb +0 -24
- data/lib/web_console/colors/solarized.rb +0 -47
- data/lib/web_console/colors/tango.rb +0 -24
- data/lib/web_console/colors/xterm.rb +0 -24
- data/lib/web_console/engine.rb +0 -77
- data/lib/web_console/slave.rb +0 -139
- data/test/controllers/web_console/console_sessions_controller_test.rb +0 -95
- data/test/helpers/web_console/console_session_helper_test.rb +0 -6
- data/test/models/console_session_test.rb +0 -58
- data/test/web_console/colors_test.rb +0 -58
- data/test/web_console/engine_test.rb +0 -136
- data/test/web_console/slave_test.rb +0 -71
data/lib/web_console/engine.rb
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
require 'ipaddr'
|
|
2
|
-
require 'active_support/core_ext/numeric/time'
|
|
3
|
-
require 'rails/engine'
|
|
4
|
-
|
|
5
|
-
require 'active_model'
|
|
6
|
-
require 'sprockets/rails'
|
|
7
|
-
|
|
8
|
-
module WebConsole
|
|
9
|
-
class Engine < ::Rails::Engine
|
|
10
|
-
isolate_namespace WebConsole
|
|
11
|
-
|
|
12
|
-
config.web_console = ActiveSupport::OrderedOptions.new.tap do |c|
|
|
13
|
-
c.automount = true
|
|
14
|
-
c.command = nil
|
|
15
|
-
c.default_mount_path = '/console'
|
|
16
|
-
c.timeout = 0.seconds
|
|
17
|
-
c.term = 'xterm-color'
|
|
18
|
-
c.whitelisted_ips = '127.0.0.1'
|
|
19
|
-
|
|
20
|
-
c.style = ActiveSupport::OrderedOptions.new.tap do |s|
|
|
21
|
-
s.colors = 'light'
|
|
22
|
-
s.font = 'large DejaVu Sans Mono, Liberation Mono, monospace'
|
|
23
|
-
end
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
initializer 'web_console.add_default_route' do |app|
|
|
27
|
-
# While we don't need the route in the test environment, we define it
|
|
28
|
-
# there as well, so we can easily test it.
|
|
29
|
-
if config.web_console.automount && (Rails.env.development? || Rails.env.test?)
|
|
30
|
-
app.routes.append do
|
|
31
|
-
mount WebConsole::Engine => app.config.web_console.default_mount_path
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
initializer 'web_console.process_whitelisted_ips' do
|
|
37
|
-
config.web_console.tap do |c|
|
|
38
|
-
# Ensure that it is an array of IPAddr instances and it is defaulted to
|
|
39
|
-
# 127.0.0.1 if not precent. Only unique entries are left in the end.
|
|
40
|
-
c.whitelisted_ips = Array(c.whitelisted_ips).map do |ip|
|
|
41
|
-
ip.is_a?(IPAddr) ? ip : IPAddr.new(ip.presence || '127.0.0.1')
|
|
42
|
-
end.uniq
|
|
43
|
-
|
|
44
|
-
# IPAddr instances can cover whole networks, so simplify the #include?
|
|
45
|
-
# check for the most common case.
|
|
46
|
-
def (c.whitelisted_ips).include?(ip)
|
|
47
|
-
ip.is_a?(IPAddr) ? super : any? { |net| net.include?(ip.to_s) }
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
initializer 'web_console.process_command' do
|
|
53
|
-
config.web_console.tap do |c|
|
|
54
|
-
# +Rails.root+ is not available while we set the default values of the
|
|
55
|
-
# other options. Default it during initialization.
|
|
56
|
-
|
|
57
|
-
# Not all people created their Rails 4 applications with the Rails 4
|
|
58
|
-
# generator, so bin/rails may not be available.
|
|
59
|
-
if c.command.blank?
|
|
60
|
-
local_rails = Rails.root.join('bin/rails')
|
|
61
|
-
c.command = "#{local_rails.executable? ? local_rails : 'rails'} console"
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
initializer 'web_console.process_colors' do
|
|
67
|
-
config.web_console.style.tap do |c|
|
|
68
|
-
case colors = c.colors
|
|
69
|
-
when Symbol, String
|
|
70
|
-
c.colors = Colors[colors] || Colors.default
|
|
71
|
-
else
|
|
72
|
-
c.colors = Colors.new(colors)
|
|
73
|
-
end
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
end
|
data/lib/web_console/slave.rb
DELETED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
require 'pty'
|
|
2
|
-
require 'io/console'
|
|
3
|
-
|
|
4
|
-
module WebConsole
|
|
5
|
-
# = Slave\ Process\ Wrapper
|
|
6
|
-
#
|
|
7
|
-
# Creates and communicates with slave processses.
|
|
8
|
-
#
|
|
9
|
-
# The communication happens through an input with attached psuedo-terminal.
|
|
10
|
-
# All of the communication is done in asynchrouns way, meaning that when you
|
|
11
|
-
# send input to the process, you have get the output by polling for it.
|
|
12
|
-
class Slave
|
|
13
|
-
# Different OS' and platforms raises different errors when trying to read
|
|
14
|
-
# on output end of a closed process.
|
|
15
|
-
READING_ON_CLOSED_END_ERRORS = [ Errno::EIO, EOFError ]
|
|
16
|
-
|
|
17
|
-
# Raised when trying to read from a closed (exited) process.
|
|
18
|
-
Closed = Class.new(IOError)
|
|
19
|
-
|
|
20
|
-
# The slave process id.
|
|
21
|
-
attr_reader :pid
|
|
22
|
-
|
|
23
|
-
def initialize(command = WebConsole.config.command, options = {})
|
|
24
|
-
using_term(options[:term] || WebConsole.config.term) do
|
|
25
|
-
@output, @input, @pid = PTY.spawn(command.to_s)
|
|
26
|
-
end
|
|
27
|
-
configure(options)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# Configure the psuedo terminal properties.
|
|
31
|
-
#
|
|
32
|
-
# Options:
|
|
33
|
-
# :width The width of the terminal in number of columns.
|
|
34
|
-
# :height The height of the terminal in number of rows.
|
|
35
|
-
#
|
|
36
|
-
# If any of the width or height is missing (or zero), the termininal size
|
|
37
|
-
# won't be set.
|
|
38
|
-
def configure(options = {})
|
|
39
|
-
dimentions = options.values_at(:height, :width).collect(&:to_i)
|
|
40
|
-
@input.winsize = dimentions unless dimentions.any?(&:zero?)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Sends input to the slave process STDIN.
|
|
44
|
-
#
|
|
45
|
-
# Returns immediately.
|
|
46
|
-
def send_input(input)
|
|
47
|
-
raise ArgumentError if input.nil? or input.try(:empty?)
|
|
48
|
-
input.each_char { |char| @input.putc(char) }
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
# Returns whether the slave process has any pending output in +wait+
|
|
52
|
-
# seconds.
|
|
53
|
-
#
|
|
54
|
-
# By default, the +timeout+ follows +config.web_console.timeout+. Usually,
|
|
55
|
-
# it is zero, making the response immediate.
|
|
56
|
-
def pending_output?(timeout = WebConsole.config.timeout)
|
|
57
|
-
# JRuby's select won't automatically coerce ActiveSupport::Duration.
|
|
58
|
-
!!IO.select([@output], [], [], timeout.to_i)
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# Gets the pending output of the process.
|
|
62
|
-
#
|
|
63
|
-
# The pending output is read in an non blocking way by chunks, in the size
|
|
64
|
-
# of +chunk_len+. By default, +chunk_len+ is 49152 bytes.
|
|
65
|
-
#
|
|
66
|
-
# Returns +nil+, if there is no pending output at the moment. Otherwise,
|
|
67
|
-
# returns the output that hasn't been read since the last invocation.
|
|
68
|
-
#
|
|
69
|
-
# Raises Errno:EIO on closed output stream. This can happen if the
|
|
70
|
-
# underlying process exits.
|
|
71
|
-
def pending_output(chunk_len = 49152)
|
|
72
|
-
# Returns nil if there is no pending output.
|
|
73
|
-
return unless pending_output?
|
|
74
|
-
|
|
75
|
-
pending = String.new
|
|
76
|
-
while chunk = @output.read_nonblock(chunk_len)
|
|
77
|
-
pending << chunk
|
|
78
|
-
end
|
|
79
|
-
pending.force_encoding('UTF-8')
|
|
80
|
-
rescue IO::WaitReadable
|
|
81
|
-
pending.force_encoding('UTF-8')
|
|
82
|
-
rescue
|
|
83
|
-
raise Closed if READING_ON_CLOSED_END_ERRORS.any? { |exc| $!.is_a?(exc) }
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
# Dispose the underlying process, sending +SIGTERM+.
|
|
87
|
-
#
|
|
88
|
-
# After the process is disposed, it is detached from the parent to prevent
|
|
89
|
-
# zombies.
|
|
90
|
-
#
|
|
91
|
-
# If the process is already disposed an Errno::ESRCH will be raised and
|
|
92
|
-
# handled internally. If you want to handle Errno::ESRCH yourself, pass
|
|
93
|
-
# +{raise: true}+ as options.
|
|
94
|
-
#
|
|
95
|
-
# Returns a thread, which can be used to wait for the process termination.
|
|
96
|
-
def dispose(options = {})
|
|
97
|
-
dispose_with(:SIGTERM, options)
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
# Dispose the underlying process, sending +SIGKILL+.
|
|
101
|
-
#
|
|
102
|
-
# After the process is disposed, it is detached from the parent to prevent
|
|
103
|
-
# zombies.
|
|
104
|
-
#
|
|
105
|
-
# If the process is already disposed an Errno::ESRCH will be raised and
|
|
106
|
-
# handled internally. If you want to handle Errno::ESRCH yourself, pass
|
|
107
|
-
# +{raise: true}+ as options.
|
|
108
|
-
#
|
|
109
|
-
# Returns a thread, which can be used to wait for the process termination.
|
|
110
|
-
def dispose!(options = {})
|
|
111
|
-
dispose_with(:SIGKILL, options)
|
|
112
|
-
end
|
|
113
|
-
|
|
114
|
-
private
|
|
115
|
-
|
|
116
|
-
LOCK = Mutex.new
|
|
117
|
-
|
|
118
|
-
def using_term(term)
|
|
119
|
-
if term.nil?
|
|
120
|
-
yield
|
|
121
|
-
else
|
|
122
|
-
LOCK.synchronize do
|
|
123
|
-
begin
|
|
124
|
-
(previous_term, ENV['TERM'] = ENV['TERM'], term) and yield
|
|
125
|
-
ensure
|
|
126
|
-
ENV['TERM'] = previous_term
|
|
127
|
-
end
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|
|
131
|
-
|
|
132
|
-
def dispose_with(signal, options = {})
|
|
133
|
-
Process.kill(signal, @pid)
|
|
134
|
-
Process.detach(@pid)
|
|
135
|
-
rescue Errno::ESRCH
|
|
136
|
-
raise if options[:raise]
|
|
137
|
-
end
|
|
138
|
-
end
|
|
139
|
-
end
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
module WebConsole
|
|
4
|
-
class ConsoleSessionsControllerTest < ActionController::TestCase
|
|
5
|
-
setup do
|
|
6
|
-
PTY.stubs(:spawn).returns([StringIO.new, StringIO.new, Random.rand(20000)])
|
|
7
|
-
@request.stubs(:remote_ip).returns('127.0.0.1')
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
test 'index is successful' do
|
|
11
|
-
get :index, use_route: 'web_console'
|
|
12
|
-
assert_response :success
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
test 'GET index creates new console session' do
|
|
16
|
-
assert_difference 'ConsoleSession::INMEMORY_STORAGE.size' do
|
|
17
|
-
get :index, use_route: 'web_console'
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
test 'PUT input validates for missing input' do
|
|
22
|
-
get :index, use_route: 'web_console'
|
|
23
|
-
|
|
24
|
-
assert_not_nil console_session = assigns(:console_session)
|
|
25
|
-
|
|
26
|
-
console_session.instance_variable_get(:@slave).stubs(:send_input).raises(ArgumentError)
|
|
27
|
-
put :input, id: console_session.pid, use_route: 'web_console'
|
|
28
|
-
|
|
29
|
-
assert_response :unprocessable_entity
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
test 'PUT input sends input to the slave' do
|
|
33
|
-
get :index, use_route: 'web_console'
|
|
34
|
-
|
|
35
|
-
assert_not_nil console_session = assigns(:console_session)
|
|
36
|
-
|
|
37
|
-
console_session.expects(:send_input)
|
|
38
|
-
put :input, input: ' ', id: console_session.pid, use_route: 'web_console'
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
test 'GET pending_output gives the slave pending output' do
|
|
42
|
-
get :index, use_route: 'web_console'
|
|
43
|
-
|
|
44
|
-
assert_not_nil console_session = assigns(:console_session)
|
|
45
|
-
console_session.expects(:pending_output)
|
|
46
|
-
|
|
47
|
-
get :pending_output, id: console_session.pid, use_route: 'web_console'
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
test 'GET pending_output raises 410 on exitted slave processes' do
|
|
51
|
-
get :index, use_route: 'web_console'
|
|
52
|
-
|
|
53
|
-
assert_not_nil console_session = assigns(:console_session)
|
|
54
|
-
console_session.stubs(:pending_output).raises(ConsoleSession::Unavailable)
|
|
55
|
-
|
|
56
|
-
get :pending_output, id: console_session.pid, use_route: 'web_console'
|
|
57
|
-
assert_response :gone
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
test 'PUT configuration adjust the terminal size' do
|
|
61
|
-
get :index, use_route: 'web_console'
|
|
62
|
-
|
|
63
|
-
assert_not_nil console_session = assigns(:console_session)
|
|
64
|
-
console_session.expects(:configure).with('id' => console_session.pid.to_s, 'width' => '80', 'height' => '24')
|
|
65
|
-
|
|
66
|
-
put :configuration, id: console_session.pid, width: 80, height: 24, use_route: 'web_console'
|
|
67
|
-
assert_response :success
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
test 'blocks requests from non-whitelisted ips' do
|
|
71
|
-
@request.stubs(:remote_ip).returns('128.0.0.1')
|
|
72
|
-
get :index, use_route: 'web_console'
|
|
73
|
-
assert_response :unauthorized
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
test 'allows requests from whitelisted ips' do
|
|
77
|
-
@request.stubs(:remote_ip).returns('127.0.0.1')
|
|
78
|
-
get :index, use_route: 'web_console'
|
|
79
|
-
assert_response :success
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
test 'index generated path' do
|
|
83
|
-
assert_generates mount_path, {
|
|
84
|
-
use_route: 'web_console',
|
|
85
|
-
controller: 'console_sessions'
|
|
86
|
-
}, {}, {controller: 'console_sessions'}
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
private
|
|
90
|
-
|
|
91
|
-
def mount_path
|
|
92
|
-
WebConsole::Engine.config.web_console.default_mount_path
|
|
93
|
-
end
|
|
94
|
-
end
|
|
95
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
module WebConsole
|
|
4
|
-
class ConsoleSessionTest < ActionView::TestCase
|
|
5
|
-
include ActiveModel::Lint::Tests
|
|
6
|
-
|
|
7
|
-
setup do
|
|
8
|
-
PTY.stubs(:spawn).returns([StringIO.new, StringIO.new, Random.rand(20000)])
|
|
9
|
-
ConsoleSession::INMEMORY_STORAGE.clear
|
|
10
|
-
@model1 = @model = ConsoleSession.new
|
|
11
|
-
@model2 = ConsoleSession.new
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
test 'raises ConsoleSession::Unavailable on not found sessions' do
|
|
15
|
-
assert_raises(ConsoleSession::Unavailable) { ConsoleSession.find(-1) }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
test 'find coerces ids' do
|
|
19
|
-
assert_equal @model.persist, ConsoleSession.find("#{@model.pid}")
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
test 'not found exceptions are json serializable' do
|
|
23
|
-
exception = assert_raises(ConsoleSession::Unavailable) { ConsoleSession.find(-1) }
|
|
24
|
-
assert_equal '{"error":"Session unavailable"}', exception.to_json
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
test 'can be used as slave as the methods are delegated' do
|
|
28
|
-
slave_methods = Slave.instance_methods - @model.methods
|
|
29
|
-
slave_methods.each { |method| assert @model.respond_to?(method) }
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
test 'slave methods are cached on the singleton' do
|
|
33
|
-
assert_not @model.singleton_methods.include?(:pending_output?)
|
|
34
|
-
@model.pending_output? rescue nil
|
|
35
|
-
assert @model.singleton_methods.include?(:pending_output?)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
test 'persisted models knows that they are in memory' do
|
|
39
|
-
assert_not @model.persisted?
|
|
40
|
-
@model.persist
|
|
41
|
-
assert @model.persisted?
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
test 'persisted models knows about their keys' do
|
|
45
|
-
assert_nil @model.to_key
|
|
46
|
-
@model.persist
|
|
47
|
-
assert_not_nil @model.to_key
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
test 'create gives already persisted models' do
|
|
51
|
-
assert ConsoleSession.create.persisted?
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
test 'no gives not persisted models' do
|
|
55
|
-
assert_not ConsoleSession.new.persisted?
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
module WebConsole
|
|
4
|
-
class ColorsTest < ActiveSupport::TestCase
|
|
5
|
-
setup do
|
|
6
|
-
@colors = Colors.new %w( #7f7f7f #ff0000 #00ff00 #ffff00 #5c5cff #ff00ff #00ffff #ffffff )
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
test '.[] is an alias for .themes#[]' do
|
|
10
|
-
@colors.class.themes.expects(:[]).with(:light).once
|
|
11
|
-
@colors.class[:light]
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
test '.register_theme creates Colors instance for the block' do
|
|
15
|
-
@colors.class.register_theme(:test) { |c| assert c.is_a?(Colors) }
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
test '#background is the first color if not specified' do
|
|
19
|
-
assert_equal '#7f7f7f', @colors.background
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
test '#background can be explicitly specified' do
|
|
23
|
-
@colors.background '#00ff00'
|
|
24
|
-
assert_equal '#00ff00', @colors.background
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
test '#background= is an alias of #background' do
|
|
28
|
-
@colors.background = '#00ff00'
|
|
29
|
-
assert_equal '#00ff00', @colors.background
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
test '#foreground is the last color if not specified' do
|
|
33
|
-
assert_equal '#ffffff', @colors.foreground
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
test '#foreground can be explicitly specified' do
|
|
37
|
-
@colors.foreground '#f0f0f0'
|
|
38
|
-
assert_equal '#f0f0f0', @colors.foreground
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
test '#foreground= is an alias of #foreground' do
|
|
42
|
-
@colors.foreground = '#f0f0f0'
|
|
43
|
-
assert_equal '#f0f0f0', @colors.foreground
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
test '#to_json includes the background and the foreground' do
|
|
47
|
-
@colors.background = '#00ff00'
|
|
48
|
-
@colors.foreground = '#f0f0f0'
|
|
49
|
-
|
|
50
|
-
expected_json = '["#7f7f7f","#ff0000","#00ff00","#ffff00","#5c5cff","#ff00ff","#00ffff","#ffffff","#00ff00","#f0f0f0"]'
|
|
51
|
-
assert_equal expected_json, @colors.to_json
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
test '#default is :light' do
|
|
55
|
-
assert_equal @colors.class.default, @colors.class.themes[:light]
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
require 'test_helper'
|
|
2
|
-
|
|
3
|
-
module WebConsole
|
|
4
|
-
class EngineTest < ActiveSupport::TestCase
|
|
5
|
-
test 'custom default_mount_path' do
|
|
6
|
-
new_uninitialized_app do |app|
|
|
7
|
-
app.config.web_console.default_mount_path = '/shell'
|
|
8
|
-
app.initialize!
|
|
9
|
-
|
|
10
|
-
assert app.routes.named_routes['web_console'].path.match('/shell')
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
test 'disabling automounting' do
|
|
15
|
-
new_uninitialized_app do |app|
|
|
16
|
-
app.config.web_console.automount = false
|
|
17
|
-
app.initialize!
|
|
18
|
-
|
|
19
|
-
assert_not app.routes.named_routes['web_console']
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
test 'blank commands are expanded to the rails console' do
|
|
24
|
-
new_uninitialized_app do |app|
|
|
25
|
-
app.config.web_console.command = ' '
|
|
26
|
-
app.initialize!
|
|
27
|
-
|
|
28
|
-
expected_path = Rails.root.join('bin/rails console').to_s
|
|
29
|
-
assert_equal expected_path, app.config.web_console.command
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
test 'present commands are not processed' do
|
|
34
|
-
new_uninitialized_app do |app|
|
|
35
|
-
app.config.web_console.command = '/bin/login'
|
|
36
|
-
app.initialize!
|
|
37
|
-
|
|
38
|
-
assert_equal '/bin/login', app.config.web_console.command
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
test 'whitelisted ips are courced to IPAddr' do
|
|
43
|
-
new_uninitialized_app do |app|
|
|
44
|
-
app.config.web_console.whitelisted_ips = '127.0.0.1'
|
|
45
|
-
app.initialize!
|
|
46
|
-
|
|
47
|
-
assert_equal [ IPAddr.new('127.0.0.1') ], app.config.web_console.whitelisted_ips
|
|
48
|
-
end
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
test 'whitelisted ips are normalized and unique IPAddr' do
|
|
52
|
-
new_uninitialized_app do |app|
|
|
53
|
-
app.config.web_console.whitelisted_ips = [ '127.0.0.1', '127.0.0.1', nil, '', ' ' ]
|
|
54
|
-
app.initialize!
|
|
55
|
-
|
|
56
|
-
assert_equal [ IPAddr.new('127.0.0.1') ], app.config.web_console.whitelisted_ips
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
test 'whitelisted_ips.include? coerces to IPAddr' do
|
|
61
|
-
new_uninitialized_app do |app|
|
|
62
|
-
app.config.web_console.whitelisted_ips = '127.0.0.1'
|
|
63
|
-
app.initialize!
|
|
64
|
-
|
|
65
|
-
assert app.config.web_console.whitelisted_ips.include?('127.0.0.1')
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
test 'whitelisted_ips.include? works with IPAddr' do
|
|
70
|
-
new_uninitialized_app do |app|
|
|
71
|
-
app.config.web_console.whitelisted_ips = '127.0.0.1'
|
|
72
|
-
app.initialize!
|
|
73
|
-
|
|
74
|
-
assert app.config.web_console.whitelisted_ips.include?(IPAddr.new('127.0.0.1'))
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
test 'whitelist whole networks' do
|
|
79
|
-
new_uninitialized_app do |app|
|
|
80
|
-
app.config.web_console.whitelisted_ips = '172.16.0.0/12'
|
|
81
|
-
app.initialize!
|
|
82
|
-
|
|
83
|
-
1.upto(255).each do |n|
|
|
84
|
-
assert_includes app.config.web_console.whitelisted_ips, "172.16.0.#{n}"
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
test 'whitelist multiple networks' do
|
|
90
|
-
new_uninitialized_app do |app|
|
|
91
|
-
app.config.web_console.whitelisted_ips = %w( 172.16.0.0/12 192.168.0.0/16 )
|
|
92
|
-
app.initialize!
|
|
93
|
-
|
|
94
|
-
1.upto(255).each do |n|
|
|
95
|
-
assert_includes app.config.web_console.whitelisted_ips, "172.16.0.#{n}"
|
|
96
|
-
assert_includes app.config.web_console.whitelisted_ips, "192.168.0.#{n}"
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
private
|
|
102
|
-
|
|
103
|
-
def new_uninitialized_app(root = File.expand_path('../../dummy', __FILE__))
|
|
104
|
-
skip if Rails::VERSION::MAJOR == 3
|
|
105
|
-
|
|
106
|
-
old_app = Rails.application
|
|
107
|
-
|
|
108
|
-
FileUtils.mkdir_p(root)
|
|
109
|
-
Dir.chdir(root) do
|
|
110
|
-
Rails.application = nil
|
|
111
|
-
|
|
112
|
-
app = Class.new(Rails::Application)
|
|
113
|
-
app.config.eager_load = false
|
|
114
|
-
app.config.time_zone = 'UTC'
|
|
115
|
-
app.config.middleware ||= Rails::Configuration::MiddlewareStackProxy.new
|
|
116
|
-
app.config.active_support.deprecation = :notify
|
|
117
|
-
|
|
118
|
-
yield app
|
|
119
|
-
end
|
|
120
|
-
ensure
|
|
121
|
-
Rails.application = old_app
|
|
122
|
-
end
|
|
123
|
-
|
|
124
|
-
def teardown_fixtures(*)
|
|
125
|
-
super
|
|
126
|
-
rescue
|
|
127
|
-
# This is nasty hack to prevent a connection to the database in JRuby's
|
|
128
|
-
# activerecord-jdbcsqlite3-adapter. We don't really require a database
|
|
129
|
-
# connection, for the tests to run.
|
|
130
|
-
#
|
|
131
|
-
# The sad thing is that I couldn't figure out why does it only happens
|
|
132
|
-
# on activerecord-jdbcsqlite3-adapter and how to actually prevent it,
|
|
133
|
-
# rather than work-around it.
|
|
134
|
-
end
|
|
135
|
-
end
|
|
136
|
-
end
|