rack-tunnel 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,63 @@
1
+ require 'socket'
2
+ require 'uri'
3
+ require 'open4'
4
+
5
+ module Rack
6
+ class Tunnel
7
+ VERSION = '0.1.0'
8
+ HEADER = 'X-Tunnel-Uri'
9
+
10
+ def initialize(app, uri)
11
+ @app, @uri = app, URI.parse(uri)
12
+
13
+ if @uri.port <= 1024 && @uri.user != 'root'
14
+ raise Error, "root user required for port #{@uri.port}"
15
+ end
16
+ end
17
+
18
+ def call(env)
19
+ establish_tunnel(env['SERVER_PORT']) unless @tunnel_established
20
+ @app.call(env.merge(HEADER => @uri.to_s))
21
+ end
22
+
23
+ def establish_tunnel(local_port)
24
+ pid, _ = Open4.popen4(command(local_port))
25
+
26
+ at_exit do
27
+ Process.kill(9, pid)
28
+ Process.wait
29
+ end
30
+
31
+ wait_for_tunnel
32
+ @tunnel_established = true
33
+ end
34
+
35
+ def command(local_port)
36
+ cmd = %w"ssh"
37
+ cmd << "-R 0.0.0.0:#{@uri.port}:localhost:#{local_port}"
38
+ cmd << @uri.host
39
+ cmd << "-l #{@uri.user}"
40
+ cmd << "-o TCPKeepAlive=yes"
41
+ cmd << "-o ServerAliveInterval=30"
42
+ cmd << "-o ServerAliveCountMax=10"
43
+ cmd << "-o GatewayPorts=yes"
44
+ cmd << "-N"
45
+
46
+ cmd.join(' ')
47
+ end
48
+
49
+ def wait_for_tunnel
50
+ Timeout::timeout(30) do
51
+ begin
52
+ return TCPSocket.new(@uri.host, @uri.port)
53
+ rescue Errno::ECONNREFUSED
54
+ retry
55
+ rescue => e
56
+ raise Error, e.message
57
+ end
58
+ end
59
+ end
60
+
61
+ class Error < StandardError ; end
62
+ end
63
+ end
@@ -0,0 +1,24 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ describe Rack::Tunnel do
4
+ it 'adds the "X-Tunnel-Uri" header' do
5
+ env = JSON.parse(@client.get('/').body)
6
+ env['X-Tunnel-Uri'].should =~ %r{^http://}
7
+ end
8
+
9
+ it 'tunnels over ssh' do
10
+ env = JSON.parse(@client.get('/').body)
11
+ uri = env['X-Tunnel-Uri']
12
+
13
+ Rack::Client.new(uri).get('/').status.should == 200
14
+ end
15
+
16
+ it 'raise an exception if the port is restricted and the user is not root' do
17
+ lambda {
18
+ Rack::Client.new do
19
+ use Rack::Tunnel, "http://#{ENV['USER']}@localhost"
20
+ run lambda { [200, {}, []] }
21
+ end
22
+ }.should raise_error(Rack::Tunnel::Error)
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+
3
+ require 'rack/tunnel'
4
+ require 'realweb'
5
+ require 'rack/client'
6
+ require 'json'
7
+
8
+ RSpec.configure do |config|
9
+ config.color_enabled = true
10
+
11
+ config.before(:all) do
12
+ @server = RealWeb.start_server_in_thread(File.join(File.dirname(__FILE__), 'config.ru'))
13
+ @client = Rack::Client.new("http://127.0.0.1:#{@server.port}")
14
+ end
15
+ end
16
+
metadata ADDED
@@ -0,0 +1,172 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rack-tunnel
3
+ version: !ruby/object:Gem::Version
4
+ hash: 27
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 0
10
+ version: 0.1.0
11
+ platform: ruby
12
+ authors:
13
+ - Ben Burkert
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-10-17 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rack
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: open4
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rack-client
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 1923832053
58
+ segments:
59
+ - 0
60
+ - 3
61
+ - 1
62
+ - pre
63
+ - b
64
+ version: 0.3.1.pre.b
65
+ type: :development
66
+ version_requirements: *id003
67
+ - !ruby/object:Gem::Dependency
68
+ name: json
69
+ prerelease: false
70
+ requirement: &id004 !ruby/object:Gem::Requirement
71
+ none: false
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ hash: 3
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: rspec
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ hash: 3
90
+ segments:
91
+ - 0
92
+ version: "0"
93
+ type: :development
94
+ version_requirements: *id005
95
+ - !ruby/object:Gem::Dependency
96
+ name: realweb
97
+ prerelease: false
98
+ requirement: &id006 !ruby/object:Gem::Requirement
99
+ none: false
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ hash: 3
104
+ segments:
105
+ - 0
106
+ version: "0"
107
+ type: :development
108
+ version_requirements: *id006
109
+ - !ruby/object:Gem::Dependency
110
+ name: rake
111
+ prerelease: false
112
+ requirement: &id007 !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
120
+ version: "0"
121
+ type: :development
122
+ version_requirements: *id007
123
+ description: Automatic port forwading via SSH tunneling.
124
+ email:
125
+ - ben@benburkert.com
126
+ executables: []
127
+
128
+ extensions: []
129
+
130
+ extra_rdoc_files: []
131
+
132
+ files:
133
+ - ./lib/rack/tunnel.rb
134
+ - ./spec/rack_tunnel_spec.rb
135
+ - ./spec/spec_helper.rb
136
+ has_rdoc: true
137
+ homepage: http://github.com/benburkert/rack-tunnel
138
+ licenses: []
139
+
140
+ post_install_message:
141
+ rdoc_options: []
142
+
143
+ require_paths:
144
+ - lib
145
+ required_ruby_version: !ruby/object:Gem::Requirement
146
+ none: false
147
+ requirements:
148
+ - - ">="
149
+ - !ruby/object:Gem::Version
150
+ hash: 3
151
+ segments:
152
+ - 0
153
+ version: "0"
154
+ required_rubygems_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ hash: 3
160
+ segments:
161
+ - 0
162
+ version: "0"
163
+ requirements: []
164
+
165
+ rubyforge_project:
166
+ rubygems_version: 1.3.7
167
+ signing_key:
168
+ specification_version: 3
169
+ summary: Automatic port forwading via SSH tunneling.
170
+ test_files:
171
+ - ./spec/rack_tunnel_spec.rb
172
+ - ./spec/spec_helper.rb