rack-webconsole 0.0.4 → 0.0.5
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.
- data/Gemfile.lock +1 -1
- data/Readme.md +5 -1
- data/lib/rack/webconsole/assets.rb +10 -1
- data/lib/rack/webconsole/repl.rb +23 -1
- data/lib/rack/webconsole/version.rb +1 -1
- data/public/webconsole.js +1 -1
- data/spec/rack/webconsole/repl_spec.rb +42 -4
- metadata +19 -19
data/Gemfile.lock
CHANGED
data/Readme.md
CHANGED
|
@@ -14,11 +14,15 @@ works. Without any configuration.
|
|
|
14
14
|
|
|
15
15
|
Tested with MRI versions 1.8.7, 1.9.2, ruby-head, and JRuby 1.6.3.
|
|
16
16
|
|
|
17
|
+
**SECURITY NOTE**: From version v0.0.5 rack-webconsole uses a token system to
|
|
18
|
+
protect against cross-site request forgery.
|
|
19
|
+
|
|
17
20
|
##Resources
|
|
18
21
|
|
|
19
22
|
* [Example video](http://youtu.be/yKK5J01Dqts?hd=1)
|
|
20
23
|
* [Documentation](http://rubydoc.info/github/codegram/rack-webconsole)
|
|
21
24
|
|
|
25
|
+
|
|
22
26
|
##Install
|
|
23
27
|
|
|
24
28
|
In your Gemfile:
|
|
@@ -33,7 +37,6 @@ some configuration file):
|
|
|
33
37
|
|
|
34
38
|
Rack::Webconsole.inject_jquery = true
|
|
35
39
|
|
|
36
|
-
|
|
37
40
|
##Usage with Rails 3
|
|
38
41
|
|
|
39
42
|
If you are using Rails 3, you have no further steps to do. It works! To give
|
|
@@ -94,3 +97,4 @@ You can also build the documentation with the following command:
|
|
|
94
97
|
Copyright (c) 2011 Codegram. See LICENSE for details.
|
|
95
98
|
|
|
96
99
|
|
|
100
|
+
|
|
@@ -32,8 +32,12 @@ module Rack
|
|
|
32
32
|
response_body = response.first
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
+
# Regenerate the security token
|
|
36
|
+
Webconsole::Repl.reset_token
|
|
37
|
+
|
|
35
38
|
# Inject the html, css and js code to the view
|
|
36
39
|
response_body.gsub!('</body>', "#{code}</body>")
|
|
40
|
+
|
|
37
41
|
headers['Content-Length'] = (response_body.length + 2).to_s
|
|
38
42
|
|
|
39
43
|
[status, headers, [response_body]]
|
|
@@ -42,9 +46,14 @@ module Rack
|
|
|
42
46
|
# Returns a string with all the HTML, CSS and JavaScript code needed for
|
|
43
47
|
# the view.
|
|
44
48
|
#
|
|
49
|
+
# It puts the security token inside the JavaScript to make AJAX calls
|
|
50
|
+
# secure.
|
|
51
|
+
#
|
|
45
52
|
# @return [String] the injectable code.
|
|
46
53
|
def code
|
|
47
|
-
html_code <<
|
|
54
|
+
html_code <<
|
|
55
|
+
css_code <<
|
|
56
|
+
js_code.gsub('TOKEN', Webconsole::Repl.token)
|
|
48
57
|
end
|
|
49
58
|
|
|
50
59
|
private
|
data/lib/rack/webconsole/repl.rb
CHANGED
|
@@ -9,6 +9,21 @@ module Rack
|
|
|
9
9
|
# variables and stores them in an instance variable for further retrieval.
|
|
10
10
|
#
|
|
11
11
|
class Repl
|
|
12
|
+
@@token = nil
|
|
13
|
+
class << self
|
|
14
|
+
# Returns the autogenerated security token
|
|
15
|
+
#
|
|
16
|
+
# @return [String] the autogenerated token
|
|
17
|
+
def token
|
|
18
|
+
@@token
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Regenerates the token.
|
|
22
|
+
def reset_token
|
|
23
|
+
@@token = Digest::SHA1.hexdigest("#{rand(36**8)}#{Time.now}")[4..20]
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
12
27
|
# Honor the Rack contract by saving the passed Rack application in an ivar.
|
|
13
28
|
#
|
|
14
29
|
# @param [Rack::Application] app the previous Rack application in the
|
|
@@ -30,9 +45,10 @@ module Rack
|
|
|
30
45
|
status, headers, response = @app.call(env)
|
|
31
46
|
|
|
32
47
|
req = Rack::Request.new(env)
|
|
33
|
-
|
|
34
48
|
params = req.params
|
|
35
49
|
|
|
50
|
+
return [status, headers, response] unless check_legitimate(req)
|
|
51
|
+
|
|
36
52
|
result = begin
|
|
37
53
|
$sandbox ||= Sandbox.new
|
|
38
54
|
|
|
@@ -59,6 +75,12 @@ module Rack
|
|
|
59
75
|
headers['Content-Length'] = response_body.length.to_s
|
|
60
76
|
[200, headers, [response_body]]
|
|
61
77
|
end
|
|
78
|
+
|
|
79
|
+
private
|
|
80
|
+
|
|
81
|
+
def check_legitimate(req)
|
|
82
|
+
req.post? && !Repl.token.nil? && req.params['token'] == Repl.token
|
|
83
|
+
end
|
|
62
84
|
end
|
|
63
85
|
end
|
|
64
86
|
end
|
data/public/webconsole.js
CHANGED
|
@@ -33,7 +33,7 @@ $("#console form input").keyup(function(event) {
|
|
|
33
33
|
url: '/webconsole',
|
|
34
34
|
type: 'POST',
|
|
35
35
|
dataType: 'json',
|
|
36
|
-
data: ({query: query}),
|
|
36
|
+
data: ({query: query, token: "TOKEN"}),
|
|
37
37
|
success: function (data) {
|
|
38
38
|
var q = "<div>>> " + query.escapeHTML() + "</div>";
|
|
39
39
|
var r = "<div>=> " + data.result.escapeHTML() + "</div>";
|
|
@@ -15,7 +15,8 @@ module Rack
|
|
|
15
15
|
it 'evaluates the :query param in a sandbox and returns the result' do
|
|
16
16
|
@app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
|
|
17
17
|
env = {}
|
|
18
|
-
|
|
18
|
+
Webconsole::Repl.stubs(:token).returns('abc')
|
|
19
|
+
request = OpenStruct.new(:params => {'query' => 'a = 4; a * 2', 'token' => 'abc'}, :post? => true)
|
|
19
20
|
Rack::Request.stubs(:new).returns request
|
|
20
21
|
|
|
21
22
|
@repl = Webconsole::Repl.new(@app)
|
|
@@ -28,13 +29,14 @@ module Rack
|
|
|
28
29
|
it 'maintains local state in subsequent calls thanks to an evil global variable' do
|
|
29
30
|
@app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
|
|
30
31
|
env = {}
|
|
31
|
-
|
|
32
|
+
Webconsole::Repl.stubs(:token).returns('abc')
|
|
33
|
+
request = OpenStruct.new(:params => {'query' => 'a = 4', 'token' => 'abc'}, :post? => true)
|
|
32
34
|
Rack::Request.stubs(:new).returns request
|
|
33
35
|
@repl = Webconsole::Repl.new(@app)
|
|
34
36
|
|
|
35
37
|
@repl.call(env) # call 1 sets a to 4
|
|
36
38
|
|
|
37
|
-
request = OpenStruct.new(:params => {'query' => 'a * 8'})
|
|
39
|
+
request = OpenStruct.new(:params => {'query' => 'a * 8', 'token' => 'abc'}, :post? => true)
|
|
38
40
|
Rack::Request.stubs(:new).returns request
|
|
39
41
|
|
|
40
42
|
response = @repl.call(env).last.first # call 2 retrieves a and multiplies it by 8
|
|
@@ -46,7 +48,8 @@ module Rack
|
|
|
46
48
|
it "returns any found errors prepended with 'Error:'" do
|
|
47
49
|
@app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
|
|
48
50
|
env = {}
|
|
49
|
-
|
|
51
|
+
Webconsole::Repl.stubs(:token).returns('abc')
|
|
52
|
+
request = OpenStruct.new(:params => {'query' => 'unknown_method', 'token' => 'abc'}, :post? => true)
|
|
50
53
|
Rack::Request.stubs(:new).returns request
|
|
51
54
|
@repl = Webconsole::Repl.new(@app)
|
|
52
55
|
|
|
@@ -54,6 +57,41 @@ module Rack
|
|
|
54
57
|
|
|
55
58
|
JSON.parse(response)['result'].must_match /Error:/
|
|
56
59
|
end
|
|
60
|
+
|
|
61
|
+
it 'rejects non-post requests' do
|
|
62
|
+
@app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
|
|
63
|
+
env = {}
|
|
64
|
+
Webconsole::Repl.stubs(:token).returns('abc')
|
|
65
|
+
request = OpenStruct.new(:params => {'query' => 'unknown_method', 'token' => 'abc'}, :post? => false)
|
|
66
|
+
Rack::Request.stubs(:new).returns request
|
|
67
|
+
@repl = Webconsole::Repl.new(@app)
|
|
68
|
+
|
|
69
|
+
$sandbox.expects(:instance_eval).never
|
|
70
|
+
|
|
71
|
+
@repl.call(env).must_equal @app.call(env)
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
it 'rejects requests with invalid token' do
|
|
75
|
+
@app = lambda { |env| [200, {'Content-Type' => 'text/plain'}, ['hello world']] }
|
|
76
|
+
env = {}
|
|
77
|
+
Webconsole::Repl.stubs(:token).returns('abc')
|
|
78
|
+
request = OpenStruct.new(:params => {'query' => 'unknown_method', 'token' => 'cba'}, :post? => true)
|
|
79
|
+
Rack::Request.stubs(:new).returns request
|
|
80
|
+
@repl = Webconsole::Repl.new(@app)
|
|
81
|
+
|
|
82
|
+
$sandbox.expects(:instance_eval).never
|
|
83
|
+
|
|
84
|
+
@repl.call(env).must_equal @app.call(env)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe 'class methods' do
|
|
89
|
+
describe '#reset_token and #token' do
|
|
90
|
+
it 'returns the security token' do
|
|
91
|
+
Webconsole::Repl.reset_token
|
|
92
|
+
Webconsole::Repl.token.must_be_kind_of String
|
|
93
|
+
end
|
|
94
|
+
end
|
|
57
95
|
end
|
|
58
96
|
|
|
59
97
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rack-webconsole
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.5
|
|
5
5
|
prerelease:
|
|
6
6
|
platform: ruby
|
|
7
7
|
authors:
|
|
@@ -16,7 +16,7 @@ default_executable:
|
|
|
16
16
|
dependencies:
|
|
17
17
|
- !ruby/object:Gem::Dependency
|
|
18
18
|
name: rack
|
|
19
|
-
requirement: &
|
|
19
|
+
requirement: &2151839300 !ruby/object:Gem::Requirement
|
|
20
20
|
none: false
|
|
21
21
|
requirements:
|
|
22
22
|
- - ! '>='
|
|
@@ -24,10 +24,10 @@ dependencies:
|
|
|
24
24
|
version: '0'
|
|
25
25
|
type: :runtime
|
|
26
26
|
prerelease: false
|
|
27
|
-
version_requirements: *
|
|
27
|
+
version_requirements: *2151839300
|
|
28
28
|
- !ruby/object:Gem::Dependency
|
|
29
29
|
name: json
|
|
30
|
-
requirement: &
|
|
30
|
+
requirement: &2151838600 !ruby/object:Gem::Requirement
|
|
31
31
|
none: false
|
|
32
32
|
requirements:
|
|
33
33
|
- - ! '>='
|
|
@@ -35,10 +35,10 @@ dependencies:
|
|
|
35
35
|
version: '0'
|
|
36
36
|
type: :runtime
|
|
37
37
|
prerelease: false
|
|
38
|
-
version_requirements: *
|
|
38
|
+
version_requirements: *2151838600
|
|
39
39
|
- !ruby/object:Gem::Dependency
|
|
40
40
|
name: minitest
|
|
41
|
-
requirement: &
|
|
41
|
+
requirement: &2151838060 !ruby/object:Gem::Requirement
|
|
42
42
|
none: false
|
|
43
43
|
requirements:
|
|
44
44
|
- - ! '>='
|
|
@@ -46,10 +46,10 @@ dependencies:
|
|
|
46
46
|
version: '0'
|
|
47
47
|
type: :development
|
|
48
48
|
prerelease: false
|
|
49
|
-
version_requirements: *
|
|
49
|
+
version_requirements: *2151838060
|
|
50
50
|
- !ruby/object:Gem::Dependency
|
|
51
51
|
name: purdytest
|
|
52
|
-
requirement: &
|
|
52
|
+
requirement: &2151837520 !ruby/object:Gem::Requirement
|
|
53
53
|
none: false
|
|
54
54
|
requirements:
|
|
55
55
|
- - ! '>='
|
|
@@ -57,10 +57,10 @@ dependencies:
|
|
|
57
57
|
version: '0'
|
|
58
58
|
type: :development
|
|
59
59
|
prerelease: false
|
|
60
|
-
version_requirements: *
|
|
60
|
+
version_requirements: *2151837520
|
|
61
61
|
- !ruby/object:Gem::Dependency
|
|
62
62
|
name: mocha
|
|
63
|
-
requirement: &
|
|
63
|
+
requirement: &2151836720 !ruby/object:Gem::Requirement
|
|
64
64
|
none: false
|
|
65
65
|
requirements:
|
|
66
66
|
- - ! '>='
|
|
@@ -68,10 +68,10 @@ dependencies:
|
|
|
68
68
|
version: '0'
|
|
69
69
|
type: :development
|
|
70
70
|
prerelease: false
|
|
71
|
-
version_requirements: *
|
|
71
|
+
version_requirements: *2151836720
|
|
72
72
|
- !ruby/object:Gem::Dependency
|
|
73
73
|
name: yard
|
|
74
|
-
requirement: &
|
|
74
|
+
requirement: &2151836080 !ruby/object:Gem::Requirement
|
|
75
75
|
none: false
|
|
76
76
|
requirements:
|
|
77
77
|
- - ! '>='
|
|
@@ -79,10 +79,10 @@ dependencies:
|
|
|
79
79
|
version: '0'
|
|
80
80
|
type: :development
|
|
81
81
|
prerelease: false
|
|
82
|
-
version_requirements: *
|
|
82
|
+
version_requirements: *2151836080
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
84
|
name: bluecloth
|
|
85
|
-
requirement: &
|
|
85
|
+
requirement: &2151835520 !ruby/object:Gem::Requirement
|
|
86
86
|
none: false
|
|
87
87
|
requirements:
|
|
88
88
|
- - ! '>='
|
|
@@ -90,10 +90,10 @@ dependencies:
|
|
|
90
90
|
version: '0'
|
|
91
91
|
type: :development
|
|
92
92
|
prerelease: false
|
|
93
|
-
version_requirements: *
|
|
93
|
+
version_requirements: *2151835520
|
|
94
94
|
- !ruby/object:Gem::Dependency
|
|
95
95
|
name: rake
|
|
96
|
-
requirement: &
|
|
96
|
+
requirement: &2151834600 !ruby/object:Gem::Requirement
|
|
97
97
|
none: false
|
|
98
98
|
requirements:
|
|
99
99
|
- - ! '>='
|
|
@@ -101,7 +101,7 @@ dependencies:
|
|
|
101
101
|
version: '0'
|
|
102
102
|
type: :development
|
|
103
103
|
prerelease: false
|
|
104
|
-
version_requirements: *
|
|
104
|
+
version_requirements: *2151834600
|
|
105
105
|
description: Rack-based console inside your web applications
|
|
106
106
|
email:
|
|
107
107
|
- info@codegram.com
|
|
@@ -150,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
150
150
|
version: '0'
|
|
151
151
|
segments:
|
|
152
152
|
- 0
|
|
153
|
-
hash:
|
|
153
|
+
hash: -1999695551081588916
|
|
154
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
155
|
none: false
|
|
156
156
|
requirements:
|
|
@@ -159,7 +159,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
159
159
|
version: '0'
|
|
160
160
|
segments:
|
|
161
161
|
- 0
|
|
162
|
-
hash:
|
|
162
|
+
hash: -1999695551081588916
|
|
163
163
|
requirements: []
|
|
164
164
|
rubyforge_project: rack-webconsole
|
|
165
165
|
rubygems_version: 1.6.2
|