tobias-rack-webconsole 0.1.4
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +9 -0
- data/.rvmrc +1 -0
- data/.travis.yml +9 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +40 -0
- data/History +27 -0
- data/Rakefile +23 -0
- data/Readme.md +125 -0
- data/lib/rack-webconsole.rb +3 -0
- data/lib/rack/webconsole.rb +83 -0
- data/lib/rack/webconsole/asset_helpers.rb +73 -0
- data/lib/rack/webconsole/assets.rb +75 -0
- data/lib/rack/webconsole/railtie.rb +14 -0
- data/lib/rack/webconsole/repl.rb +86 -0
- data/lib/rack/webconsole/sandbox.rb +33 -0
- data/lib/rack/webconsole/shell.rb +74 -0
- data/lib/rack/webconsole/version.rb +7 -0
- data/public/jquery.html +1 -0
- data/public/webconsole.css +86 -0
- data/public/webconsole.html +15 -0
- data/public/webconsole.js +92 -0
- data/rack-webconsole.gemspec +36 -0
- data/spec/rack/webconsole/asset_helpers_spec.rb +56 -0
- data/spec/rack/webconsole/assets_spec.rb +101 -0
- data/spec/rack/webconsole/repl_spec.rb +106 -0
- data/spec/rack/webconsole/sandbox_spec.rb +50 -0
- data/spec/rack/webconsole/shell_spec.rb +73 -0
- data/spec/rack/webconsole_spec.rb +56 -0
- data/spec/spec_helper.rb +10 -0
- metadata +190 -0
data/.gitignore
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create use ruby-1.9.3@rack-webconsole
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
rack-webconsole (0.1.3)
|
5
|
+
multi_json (~> 1.0.3)
|
6
|
+
rack
|
7
|
+
ripl (~> 0.5.1)
|
8
|
+
ripl-multi_line (~> 0.3.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: http://rubygems.org/
|
12
|
+
specs:
|
13
|
+
bluecloth (2.2.0)
|
14
|
+
bond (0.4.1)
|
15
|
+
metaclass (0.0.1)
|
16
|
+
minitest (2.11.4)
|
17
|
+
mocha (0.10.5)
|
18
|
+
metaclass (~> 0.0.1)
|
19
|
+
multi_json (1.0.4)
|
20
|
+
purdytest (1.0.0)
|
21
|
+
minitest (~> 2.2)
|
22
|
+
rack (1.4.1)
|
23
|
+
rake (0.9.2.2)
|
24
|
+
ripl (0.5.1)
|
25
|
+
bond (~> 0.4.0)
|
26
|
+
ripl-multi_line (0.3.0)
|
27
|
+
ripl (>= 0.3.6)
|
28
|
+
yard (0.7.5)
|
29
|
+
|
30
|
+
PLATFORMS
|
31
|
+
ruby
|
32
|
+
|
33
|
+
DEPENDENCIES
|
34
|
+
bluecloth
|
35
|
+
minitest
|
36
|
+
mocha
|
37
|
+
purdytest
|
38
|
+
rack-webconsole!
|
39
|
+
rake
|
40
|
+
yard
|
data/History
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
=== 0.1.3 / 2012-03-22
|
2
|
+
|
3
|
+
+ Make keycode configurable (Roger Leite)
|
4
|
+
+ Switch to multi_json (Josh Buddy)
|
5
|
+
! Fix markup to make it work in more browsers
|
6
|
+
|
7
|
+
=== 0.1.2 / 2011-08-01
|
8
|
+
|
9
|
+
+ Change field name to avoid conflicts with other forms (Chris Apolzon)
|
10
|
+
+ Prevent visual flash of unstyled content (Rob Cameron)
|
11
|
+
+ Fix minor styling issues (Jeff Kreeftmeijer)
|
12
|
+
+ Avoid conflicts with libraries other than JQuery (Jo Liss)
|
13
|
+
|
14
|
+
=== 0.1.1 / 2011-07-27
|
15
|
+
|
16
|
+
! Fix bug with Content-Length not being calculated appropriately. (Corin Langosch)
|
17
|
+
+ Refactor JavaScript to avoid messing with prototypes (Corin Langosch)
|
18
|
+
|
19
|
+
=== 0.1.0 / 2011-07-27
|
20
|
+
|
21
|
+
+ The request object is now exposed in the console through #request method
|
22
|
+
+ Various UI enhancements
|
23
|
+
! Fix bug where Sandbox locals were much more than those defined by the user.
|
24
|
+
|
25
|
+
=== 0.0.5 / 2011-07-26
|
26
|
+
|
27
|
+
! Protection against CSRF attacks.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rake/testtask'
|
5
|
+
desc "Run rack-webconsole specs"
|
6
|
+
Rake::TestTask.new do |t|
|
7
|
+
t.libs << "spec"
|
8
|
+
t.test_files = FileList['spec/**/*_spec.rb']
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
|
12
|
+
require 'yard'
|
13
|
+
YARD::Rake::YardocTask.new(:docs) do |t|
|
14
|
+
t.files = ['lib/**/*.rb']
|
15
|
+
t.options = ['-m', 'markdown', '--no-private', '-r', 'Readme.md', '--title', 'rack-webconsole documentation']
|
16
|
+
end
|
17
|
+
task :doc => [:docs]
|
18
|
+
|
19
|
+
desc "Generate and open class diagram (needs Graphviz installed)"
|
20
|
+
task :graph do |t|
|
21
|
+
`bundle exec yard graph -d --full --no-private | dot -Tpng -o graph.png && open graph.png`
|
22
|
+
end
|
23
|
+
task :default => [:test]
|
data/Readme.md
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
#rack-webconsole [![Build Status](http://travis-ci.org/codegram/rack-webconsole.png)](http://travis-ci.org/codegram/rack-webconsole.png)
|
2
|
+
|
3
|
+
Rack-webconsole is a Rack-based interactive console (à la Rails console) in
|
4
|
+
your web application's frontend. That means you can interact with your
|
5
|
+
application's backend from within the browser itself!
|
6
|
+
|
7
|
+
To get a clearer idea, you can check out this video showing a live example :)
|
8
|
+
|
9
|
+
[![YouTube video](http://img.youtube.com/vi/yKK5J01Dqts/0.jpg)](http://youtu.be/yKK5J01Dqts?hd=1)
|
10
|
+
|
11
|
+
Rack-webconsole is a Rack middleware designed to be unobtrusive. With Rails 3,
|
12
|
+
for example, you only have to include the gem in your Gemfile and it already
|
13
|
+
works. Without any configuration.
|
14
|
+
|
15
|
+
Tested with MRI versions 1.8.7, 1.9.2, ruby-head, and JRuby 1.6.3.
|
16
|
+
|
17
|
+
**SECURITY NOTE**: From version v0.0.5 rack-webconsole uses a token system to
|
18
|
+
protect against cross-site request forgery.
|
19
|
+
|
20
|
+
##Resources
|
21
|
+
|
22
|
+
* [Example video](http://youtu.be/yKK5J01Dqts?hd=1)
|
23
|
+
* [Documentation](http://rubydoc.info/github/codegram/rack-webconsole)
|
24
|
+
|
25
|
+
|
26
|
+
##Install
|
27
|
+
|
28
|
+
In your Gemfile:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
gem 'rack-webconsole'
|
32
|
+
```
|
33
|
+
|
34
|
+
Rack-webconsole **needs JQuery**. If you are using Rails 3, JQuery is loaded by
|
35
|
+
default. In case you don't want to use JQuery in your application,
|
36
|
+
**rack-webconsole can inject it for you** only when it needs it. To do that you
|
37
|
+
should put this line somewhere in your application (a Rails initializer, or
|
38
|
+
some configuration file):
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
Rack::Webconsole.inject_jquery = true
|
42
|
+
```
|
43
|
+
|
44
|
+
You can also change the javascript key_code used to start webconsole:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
# ` = 96 (default), ^ = 94, ç = 231 ... etc.
|
48
|
+
Rack::Webconsole.key_code = "231"
|
49
|
+
```
|
50
|
+
|
51
|
+
##Usage with Rails 3
|
52
|
+
|
53
|
+
If you are using Rails 3, you have no further steps to do. It works! To give
|
54
|
+
it a try, fire up the Rails server and go to any page, press the ` ` ` key and
|
55
|
+
the console will show :)
|
56
|
+
|
57
|
+
##Usage with Sinatra/Padrino
|
58
|
+
|
59
|
+
With Sinatra and Padrino you have to tell your application to use the
|
60
|
+
middleware:
|
61
|
+
|
62
|
+
```ruby
|
63
|
+
require 'sinatra'
|
64
|
+
require 'rack/webconsole'
|
65
|
+
|
66
|
+
class MySinatraApp < Sinatra::Application
|
67
|
+
use Rack::Webconsole
|
68
|
+
# . . .
|
69
|
+
end
|
70
|
+
|
71
|
+
class SamplePadrino < Padrino::Application
|
72
|
+
use Rack::Webconsole
|
73
|
+
# . . .
|
74
|
+
end
|
75
|
+
```
|
76
|
+
|
77
|
+
NOTE: If you are using Bundler and initializing it from config.ru, you don't
|
78
|
+
have to `require 'rack/webconsole'` manually, otherwise you have to.
|
79
|
+
|
80
|
+
And it works! Fire up the server, go to any page and press the ` ` ` key.
|
81
|
+
|
82
|
+
##Usage with Rails 2
|
83
|
+
|
84
|
+
You need to add the following code to an intializer (i.e. config/initializers/webconsole.rb):
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
require 'rack/webconsole'
|
88
|
+
ActionController::Dispatcher.middleware.insert_after 1, Rack::Webconsole
|
89
|
+
```
|
90
|
+
|
91
|
+
##Commands
|
92
|
+
|
93
|
+
In the console you can issue whatever Ruby commands you want, except multiline commands. Local variables are kept, so you can get a more IRB-esque feeling.
|
94
|
+
|
95
|
+
* `reload!` resets all local variables
|
96
|
+
* `request` returns the current page request object
|
97
|
+
|
98
|
+
##Under the hood
|
99
|
+
|
100
|
+
Run the test suite by typing:
|
101
|
+
|
102
|
+
rake
|
103
|
+
|
104
|
+
You can also build the documentation with the following command:
|
105
|
+
|
106
|
+
rake docs
|
107
|
+
|
108
|
+
## Note on Patches/Pull Requests
|
109
|
+
|
110
|
+
* Fork the project.
|
111
|
+
* Make your feature addition or bug fix.
|
112
|
+
* Add tests for it. This is important so we don't break it in a
|
113
|
+
future version unintentionally.
|
114
|
+
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself we can ignore when we pull)
|
115
|
+
* Send us a pull request. Bonus points for topic branches.
|
116
|
+
|
117
|
+
## Released under the MIT License
|
118
|
+
|
119
|
+
Copyright (c) 2011 Codegram.
|
120
|
+
|
121
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
122
|
+
|
123
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
124
|
+
|
125
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'rack/webconsole/repl'
|
3
|
+
require 'rack/webconsole/asset_helpers'
|
4
|
+
require 'rack/webconsole/assets'
|
5
|
+
require 'rack/webconsole/sandbox'
|
6
|
+
require 'rack/webconsole/shell'
|
7
|
+
|
8
|
+
require 'rack/webconsole/railtie' if defined?(Rails::Railtie)
|
9
|
+
|
10
|
+
# Rack is a modular webserver interface written by Christian Neukirchen.
|
11
|
+
#
|
12
|
+
# Learn more at: https://github.com/rack/rack
|
13
|
+
#
|
14
|
+
module Rack
|
15
|
+
# {Rack::Webconsole} is a Rack middleware that provides an interactive
|
16
|
+
# console à la Rails console, but for any kind of Rack application (Rails,
|
17
|
+
# Sinatra, Padrino...), accessible from your web application's front-end.
|
18
|
+
#
|
19
|
+
# For every request, it normally passes control to the {Assets} middleware,
|
20
|
+
# which injects needed JavaScript, CSS and HTML code for the console to work
|
21
|
+
# properly.
|
22
|
+
#
|
23
|
+
# It also exposes a special route used by the {Repl}, a Ruby evaluator which
|
24
|
+
# is responsible of keeping state between requests, remembering local
|
25
|
+
# variables and giving a true IRB-esque experience.
|
26
|
+
#
|
27
|
+
class Webconsole
|
28
|
+
@@config = {:inject_jquery => false, :key_code => "96"}
|
29
|
+
|
30
|
+
class << self
|
31
|
+
# Returns whether the Asset injecter must inject JQuery or not.
|
32
|
+
#
|
33
|
+
# @return [Boolean] whether to inject JQuery or not.
|
34
|
+
def inject_jquery
|
35
|
+
@@config[:inject_jquery]
|
36
|
+
end
|
37
|
+
|
38
|
+
# Sets whether the Asset injecter must inject JQuery or not.
|
39
|
+
#
|
40
|
+
# @param [Boolean] value whether to inject JQuery or not.
|
41
|
+
def inject_jquery=(value)
|
42
|
+
@@config[:inject_jquery] = value
|
43
|
+
end
|
44
|
+
|
45
|
+
# Returns key code used to start web console.
|
46
|
+
#
|
47
|
+
# @return [String] key code used at keypress event to start web console.
|
48
|
+
def key_code
|
49
|
+
@@config[:key_code]
|
50
|
+
end
|
51
|
+
|
52
|
+
# Sets key code used to start web console.
|
53
|
+
#
|
54
|
+
# @param [String] value key code used at keypress event to start web console.
|
55
|
+
def key_code=(value)
|
56
|
+
value = value.to_s unless value.is_a?(String)
|
57
|
+
@@config[:key_code] = value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Honor the Rack contract by saving the passed Rack application in an ivar.
|
62
|
+
#
|
63
|
+
# @param [Rack::Application] app the previous Rack application in the
|
64
|
+
# middleware chain.
|
65
|
+
def initialize(app)
|
66
|
+
@app = app
|
67
|
+
end
|
68
|
+
|
69
|
+
# Decides where to send the request. In case the path is `/webconsole`
|
70
|
+
# (e.g. when calling the {Repl} endpoint), pass the request onto the
|
71
|
+
# {Repl}. Otherwise, pass it onto the {Assets} middleware, which will
|
72
|
+
# inject the needed assets for the Webconsole to work.
|
73
|
+
#
|
74
|
+
# @param [Hash] env a Rack request environment.
|
75
|
+
def call(env)
|
76
|
+
if env['PATH_INFO'] == '/webconsole'
|
77
|
+
Repl.new(@app).call(env)
|
78
|
+
else
|
79
|
+
Assets.new(@app).call(env)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Rack
|
3
|
+
class Webconsole
|
4
|
+
# Helper module to encapsulate the asset loading logic used by the {Assets}
|
5
|
+
# middleware.
|
6
|
+
#
|
7
|
+
# For now, the strategy is reading the files from disk. In the future, we
|
8
|
+
# should come up with a somewhat more sophisticated strategy, although
|
9
|
+
# {Webconsole} is used only in development environments, where performance
|
10
|
+
# isn't usually a concern.
|
11
|
+
#
|
12
|
+
module AssetHelpers
|
13
|
+
# Loads the HTML from a file in `/public`.
|
14
|
+
#
|
15
|
+
# It contains a form and the needed divs to render the console.
|
16
|
+
#
|
17
|
+
# @return [String] the injectable HTML.
|
18
|
+
def html_code
|
19
|
+
out = ""
|
20
|
+
out << asset('jquery.html') if Webconsole.inject_jquery
|
21
|
+
out << asset('webconsole.html')
|
22
|
+
out
|
23
|
+
end
|
24
|
+
|
25
|
+
# Loads the CSS from a file in `/public`.
|
26
|
+
#
|
27
|
+
# It contains the styles for the console.
|
28
|
+
#
|
29
|
+
# @return [String] the injectable CSS.
|
30
|
+
def css_code
|
31
|
+
'<style type="text/css">' <<
|
32
|
+
asset('webconsole.css') <<
|
33
|
+
'</style>'
|
34
|
+
end
|
35
|
+
|
36
|
+
# Loads the JavaScript from a file in `/public`.
|
37
|
+
#
|
38
|
+
# It contains the JavaScript logic of the webconsole.
|
39
|
+
#
|
40
|
+
# @return [String] the injectable JavaScript.
|
41
|
+
def js_code
|
42
|
+
'<script type="text/javascript">' <<
|
43
|
+
asset('webconsole.js') <<
|
44
|
+
'</script>'
|
45
|
+
end
|
46
|
+
|
47
|
+
# Inteprolates the given variables inside the javascrpt code
|
48
|
+
#
|
49
|
+
# @param [String] javascript The javascript code to insert the variables
|
50
|
+
# @param [Hash] variables A hash containing the variables names (as keys)
|
51
|
+
# and its values
|
52
|
+
#
|
53
|
+
# @return [String] the javascript code with the interpolated variables
|
54
|
+
def render(javascript, variables = {})
|
55
|
+
javascript_with_variables = javascript.dup
|
56
|
+
variables.each_pair do |variable, value|
|
57
|
+
javascript_with_variables.gsub!("$#{variable}", value)
|
58
|
+
end
|
59
|
+
javascript_with_variables
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def asset(file)
|
65
|
+
@assets ||= {}
|
66
|
+
output = ::File.open(::File.join(::File.dirname(__FILE__), '..', '..', '..', 'public', file), 'r:UTF-8') do |f|
|
67
|
+
f.read
|
68
|
+
end
|
69
|
+
@assets[file] ||= output
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module Rack
|
3
|
+
class Webconsole
|
4
|
+
# {Assets} is a Rack middleware responsible for injecting view code for the
|
5
|
+
# console to work properly.
|
6
|
+
#
|
7
|
+
# It intercepts HTTP requests, detects successful HTML responses and
|
8
|
+
# injects HTML, CSS and JavaScript code into those.
|
9
|
+
#
|
10
|
+
class Assets
|
11
|
+
include Webconsole::AssetHelpers
|
12
|
+
|
13
|
+
# Honor the Rack contract by saving the passed Rack application in an ivar.
|
14
|
+
#
|
15
|
+
# @param [Rack::Application] app the previous Rack application in the
|
16
|
+
# middleware chain.
|
17
|
+
def initialize(app)
|
18
|
+
@app = app
|
19
|
+
end
|
20
|
+
|
21
|
+
# Checks for successful HTML responses and injects HTML, CSS and
|
22
|
+
# JavaScript code into them.
|
23
|
+
#
|
24
|
+
# @param [Hash] env a Rack request environment.
|
25
|
+
def call(env)
|
26
|
+
status, headers, response = @app.call(env)
|
27
|
+
return [status, headers, response] unless check_html?(headers, response) && status == 200
|
28
|
+
|
29
|
+
if response.respond_to?(:body)
|
30
|
+
response_body = response.body
|
31
|
+
else
|
32
|
+
response_body = response.first
|
33
|
+
end
|
34
|
+
|
35
|
+
# Regenerate the security token
|
36
|
+
Webconsole::Repl.reset_token
|
37
|
+
|
38
|
+
# Expose the request object to the Repl
|
39
|
+
Webconsole::Repl.request = Rack::Request.new(env)
|
40
|
+
|
41
|
+
# Inject the html, css and js code to the view
|
42
|
+
response_body.gsub!('</body>', "#{code(env)}</body>")
|
43
|
+
|
44
|
+
headers['Content-Length'] = response_body.bytesize.to_s
|
45
|
+
|
46
|
+
[status, headers, [response_body]]
|
47
|
+
end
|
48
|
+
|
49
|
+
# Returns a string with all the HTML, CSS and JavaScript code needed for
|
50
|
+
# the view.
|
51
|
+
#
|
52
|
+
# It puts the security token inside the JavaScript to make AJAX calls
|
53
|
+
# secure.
|
54
|
+
#
|
55
|
+
# @return [String] the injectable code.
|
56
|
+
def code(env)
|
57
|
+
html_code <<
|
58
|
+
css_code <<
|
59
|
+
render(js_code,
|
60
|
+
:TOKEN => Webconsole::Repl.token,
|
61
|
+
:KEY_CODE => Webconsole.key_code,
|
62
|
+
:CONTEXT => env['SCRIPT_NAME'] || "")
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def check_html?(headers, response)
|
68
|
+
body = response.respond_to?(:body) ? response.body : response.first
|
69
|
+
headers['Content-Type'] and
|
70
|
+
headers['Content-Type'].include? 'text/html' and
|
71
|
+
body =~ %r{<html.*</html>}m
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|