Class: Rack::Webconsole::Repl
- Inherits:
-
Object
- Object
- Rack::Webconsole::Repl
- Defined in:
- lib/rack/webconsole/repl.rb
Overview
Repl is a Rack middleware acting as a Ruby evaluator application.
In a nutshell, it evaluates a string in a Sandbox instance stored in an evil global variable. Then, to keep the state, it inspects the local variables and stores them in an instance variable for further retrieval.
Constant Summary collapse
- @@request =
nil
- @@tokens =
{}
Class Method Summary collapse
- .clear_tokens ⇒ Object
-
.request ⇒ Rack::Request
Returns the original request for inspection purposes.
-
.request=(request) ⇒ Object
Sets the original request for inspection purposes.
-
.reset_token(app, env) ⇒ Object
Regenerates the token.
-
.token_valid?(token) ⇒ String
Returns the autogenerated security token.
Instance Method Summary collapse
-
#call(env) ⇒ Array
Evaluates a string as Ruby code and returns the evaluated result as JSON.
-
#initialize(app) ⇒ Repl
constructor
Honor the Rack contract by saving the passed Rack application in an ivar.
Constructor Details
#initialize(app) ⇒ Repl
Honor the Rack contract by saving the passed Rack application in an ivar.
61 62 63 64 |
# File 'lib/rack/webconsole/repl.rb', line 61 def initialize(app) @app = app end |
Class Method Details
.clear_tokens ⇒ Object
19 20 21 22 23 |
# File 'lib/rack/webconsole/repl.rb', line 19 def clear_tokens @@tokens.each_pair do |k, v| @@tokens.delete(k) if v <= Time.now end end |
.request ⇒ Rack::Request
Returns the original request for inspection purposes.
44 45 46 |
# File 'lib/rack/webconsole/repl.rb', line 44 def request @@request end |
.request=(request) ⇒ Object
Sets the original request for inspection purposes.
51 52 53 |
# File 'lib/rack/webconsole/repl.rb', line 51 def request=(request) @@request = request end |
.reset_token(app, env) ⇒ Object
Regenerates the token.
34 35 36 37 38 39 |
# File 'lib/rack/webconsole/repl.rb', line 34 def reset_token(app, env) clear_tokens token = Digest::SHA1.hexdigest("#{rand(36**8)}#{Time.now}")[4..20] @@tokens[token] = Time.now + 30 * 60 token end |
.token_valid?(token) ⇒ String
Returns the autogenerated security token
28 29 30 31 |
# File 'lib/rack/webconsole/repl.rb', line 28 def token_valid? token clear_tokens @@tokens.keys.include?(token) end |
Instance Method Details
#call(env) ⇒ Array
Evaluates a string as Ruby code and returns the evaluated result as JSON.
It also stores the Sandbox state in a ‘$sandbox` global variable, with its local variables.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/rack/webconsole/repl.rb', line 75 def call(env) status, headers, response = @app.call(env) req = Rack::Request.new(env) params = req.params return [status, headers, response] unless check_legitimate(req) hash = {} $pry_output ||= StringIO.new("") $pry_output.string = "" if $pry.nil? Pry.pager = false $pry = Pry.new(:output => $pry_output, :pager => false) Pry.initial_session_setup end pry = $pry # repl loop if pry.binding_stack.last target = Pry.binding_for(pry.binding_stack.last) else target = Pry.binding_for(TOPLEVEL_BINDING) end pry.repl_prologue(target) unless pry.binding_stack.last == target pry.inject_sticky_locals(target) code = params['query'] hash[:prompt] = pry.select_prompt("", target) + Pry::Code.new(code).to_s got_output = false begin read_pipe, write_pipe = IO.pipe end_line = "~~~~~ rack-webconsole end output ~~~~~\n" thr = Thread.new do while true new_line = read_pipe.readline break if new_line == end_line $pry_output << new_line end end old_stdout = STDOUT.dup old_stderr = STDERR.dup STDOUT.reopen(write_pipe) STDERR.reopen(write_pipe) if !pry.process_command(code, "", target) result = target.eval(code, Pry.eval_path, Pry.current_line) got_output = true end rescue StandardError => e error_out = "Error: " + e. ensure write_pipe << end_line thr.join read_pipe.close write_pipe.close STDOUT.reopen(old_stdout) STDERR.reopen(old_stderr) end if got_output pry.set_last_result(result, target, code) Pry.print.call($pry_output, result) if pry.should_print? # the below line doesn't work well with custom printers # (like awesome_print) for some reason #pry.show_result(result) if pry.should_print? end $pry_output.write(error_out) if error_out # cleanup (supposed to call when $pry is destroyed) # pry.repl_epilogue(target) hash[:result] = $pry_output.string response_body = MultiJson.encode(hash) headers = {} headers['Content-Type'] = 'application/json' headers['Content-Length'] = response_body.bytesize.to_s [200, headers, [response_body]] end |