em-wssh 0.3.0

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5594f5ba9ee7af40c50e16a6495afe8567c1ae8e
4
+ data.tar.gz: 5d311ce91fcd6c547070ce9dfd805c44dbc8b204
5
+ SHA512:
6
+ metadata.gz: bf4bc293ae6fda9f53b3183566fb9a644146e9e70022cbd11273ea76274a8fbda896a367ff0219b3a6ac8e338ef49e23474b1703965ee427897776c4aa2f3fd1
7
+ data.tar.gz: cfd455480307b436d080bd803ac188dd90c615b7b270b04cfdfbe83bc07f6b8f8d501aeff8c45503fc7aa946bfe17a89d441f8ce19eb6227f7c31b6346c87acb
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ log
@@ -0,0 +1,17 @@
1
+ I: Install dependencies
2
+ bundle install
3
+ --:
4
+ B: Build gem
5
+ bundle exec rake build
6
+ L: Install gem locally
7
+ bundle exec rake install
8
+ U: Uninstall gem
9
+ gem uninstall -ax em-wssh
10
+ --:
11
+ S: Start server
12
+ bundle exec ruby bin/wssh server -new_console:cb
13
+ C: Start CONNECT proxy
14
+ bundle exec ruby bin/wssh connect ws://localhost:4567/test -new_console:cb
15
+ 2: Start both servers
16
+ bundle exec ruby bin/wssh server -new_console:cb
17
+ bundle exec ruby bin/wssh connect ws://localhost:4567/test -new_console:cb
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in em-wssh.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Stas Ukolov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,97 @@
1
+ # em-wssh
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/em-wssh.svg)](http://badge.fury.io/rb/em-wssh)
4
+
5
+ Ruby version of ssh thru websocket proxying.
6
+
7
+ [Original version](https://github.com/ukoloff/wssh) uses Node.js
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ ```ruby
14
+ gem 'em-wssh' if Gem.win_platform?
15
+ ```
16
+
17
+ And then execute:
18
+
19
+ ```sh
20
+ $ bundle
21
+ ```
22
+
23
+ Or install it yourself as:
24
+
25
+ ```sh
26
+ $ gem install em-wssh
27
+ ```
28
+
29
+ ## Usage
30
+
31
+ ...
32
+
33
+ ## Data flow
34
+
35
+ Normal SSH session is very simple:
36
+
37
+ * SSH Client
38
+ * TCP Connection
39
+ * SSH Server, listening on TCP port 22
40
+
41
+ WSSH session is:
42
+
43
+ * SSH Client with -o ProxyCommand='ruby client.rb WSSH-URI'
44
+ * client.rb listening to its stdin
45
+ * Websocket (HTTP/HTTPS) connection to nginx
46
+ * nginx [configured](nginx/ssh) to redirect connection to WSSH server
47
+ * Another Websocket connection from nginx to WSSH server
48
+ * WSSH server, listening to dedicated TCP port (4567 by default)
49
+ * Normal TCP connection
50
+ * Normal SSH Server, listening on TCP port 22
51
+
52
+ And nginx stage can be omited in development/testing scenarios.
53
+
54
+ In some scenarios this path can be even longer:
55
+
56
+ * SSH Client, capable to connect via HTTP proxy (eg PuTTY/PLink)
57
+ * TCP connection to local proxy
58
+ * connect.rb listening to dedicated port (3122 by default)
59
+ * Websocket (HTTP/HTTPS) connection to nginx
60
+ * nginx [configured](nginx/ssh) to redirect connection to WSSH server
61
+ * Another Websocket connection from nginx to WSSH server
62
+ * WSSH server, listening to dedicated TCP port (4567 by default)
63
+ * Normal TCP connection
64
+ * Normal SSH Server, listening on TCP port 22
65
+
66
+ ## Windows bugs
67
+
68
+ Windows installation of EventMachine has a few bugs:
69
+
70
+ 1. Using STDIN [blocks](https://groups.google.com/forum/#!topic/eventmachine/5rDIOA2uOoA) all other connections
71
+ 2. By default SSL/TLS is not available
72
+ 3. No root certificates available ([Fixed](https://github.com/ukoloff/openssl-win-root))
73
+
74
+ So, this package is in fact almost unusable on MS Windows.
75
+
76
+ The only exception: if you connect to Non-TLS WSSH server
77
+ (ws: or http:, not wss: or https:), you **can** start connect.rb
78
+ and then use SSH client, capable to connect via HTTP proxy.
79
+
80
+ To connect to TLS WSSH server, you should use Node.js version.
81
+
82
+ ## See also
83
+
84
+ * [Node.js version](https://github.com/ukoloff/wssh)
85
+ * [Python version](https://github.com/progrium/wssh)
86
+
87
+ ## Credits
88
+
89
+ * [nginx](http://nginx.org/)
90
+ * [Ruby](https://www.ruby-lang.org/)
91
+ * [EventMachine](https://github.com/eventmachine/eventmachine)
92
+ * [EM-WebSocket](https://github.com/igrigorik/em-websocket)
93
+ * [faye-websocket](https://github.com/faye/faye-websocket-ruby)
94
+ * [Node.js](http://nodejs.org/)
95
+ * [OpenSSH](http://www.openssh.com/)
96
+ * [Net::SSH](https://github.com/net-ssh/net-ssh)
97
+ * [PuTTY](http://www.chiark.greenend.org.uk/~sgtatham/putty/)
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,2 @@
1
+ require_relative '../lib/em/wssh/exe'
2
+ EventMachine::Wssh::Exe.do!
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'em/wssh'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "em-wssh"
8
+ spec.version = EventMachine::Wssh::VERSION
9
+ spec.authors = ["Stas Ukolov"]
10
+ spec.email = ["ukoloff@gmail.com"]
11
+ spec.description = 'Proxy SSH connection through Websocket (nginx)'
12
+ spec.summary = ''
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "em-websocket" # server side
22
+ spec.add_dependency "faye-websocket" # client side
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ end
@@ -0,0 +1,20 @@
1
+ # Catch all regexp
2
+ //: localhost
3
+
4
+ # Simple rule
5
+ self: localhost
6
+
7
+ # Disabled
8
+ none: false
9
+
10
+ # Allowed
11
+ github.com: true
12
+ gitlab.com: true
13
+ bitbucket.org: true
14
+
15
+ # Sample regexp
16
+ /lab$/i: gitlab.com
17
+
18
+ # Allow intranet IPs
19
+ /10(?:\.\d+){3}/: true
20
+ /192\.168(?:\.\d+){2}/: true
@@ -0,0 +1,5 @@
1
+ module EventMachine
2
+ module Wssh
3
+ VERSION = "0.3.0"
4
+ end
5
+ end
@@ -0,0 +1 @@
1
+ Dir.glob(File.expand_path '../*.rb', __FILE__){|f|require f}
@@ -0,0 +1,95 @@
1
+ require_relative '../wssh'
2
+
3
+ module EventMachine::Wssh
4
+ module Client
5
+ Need=%w(faye/websocket)
6
+
7
+ def self.help
8
+ puts <<-EOT
9
+ WSSH client
10
+
11
+ Usage: ruby #{File.basename __FILE__} ws[s]://host[:port]/uri
12
+ EOT
13
+ exit 1
14
+ end
15
+
16
+ def self.getopt
17
+ help if ARGV.length!=1
18
+ @uri=ARGV[0]
19
+ end
20
+
21
+ class Ws
22
+ def initialize uri
23
+ @buf=[]
24
+
25
+ @ws=Faye::WebSocket::Client.new uri
26
+
27
+ @ws.on :open do |event| onopen end
28
+ @ws.on :message do |event| onmessage event.data end
29
+ @ws.on :close do |event| onclose end
30
+ @ws.on :error do |error| onerror error end
31
+ end
32
+
33
+ def queue data
34
+ if @buf
35
+ @buf << data
36
+ else
37
+ @ws.send data
38
+ end
39
+ end
40
+
41
+ def onopen
42
+ @buf.each{|data| @ws.send data}
43
+ @buf=nil
44
+ end
45
+
46
+ def onmessage data
47
+ print data.pack 'C*'
48
+ end
49
+
50
+ def onclose
51
+ bye
52
+ end
53
+
54
+ def onerror error
55
+ bye
56
+ end
57
+
58
+ def bye
59
+ @ws.close if @ws
60
+ @ws=nil
61
+ @buf=nil
62
+ EM.stop_event_loop
63
+ end
64
+ end
65
+
66
+ module Stdio
67
+ def initialize ws
68
+ @ws = ws
69
+ end
70
+
71
+ def receive_data data
72
+ @ws.queue data.unpack 'C*'
73
+ end
74
+
75
+ def unbind
76
+ @ws.bye
77
+ end
78
+ end
79
+
80
+ def self.listen!
81
+ EM.attach $stdin, Stdio, Ws.new(@uri)
82
+ end
83
+
84
+ def self.loop!
85
+ self::Need.each{|f| require f}
86
+ EM.run{ listen! }
87
+ end
88
+
89
+ def self.go!
90
+ getopt
91
+ STDOUT.sync=true
92
+ loop!
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,163 @@
1
+ require_relative 'service'
2
+
3
+ module EventMachine::Wssh
4
+ module Connect
5
+ extend Service
6
+
7
+ Need=%w(faye/websocket)
8
+
9
+ @options={
10
+ host: 'localhost',
11
+ port: 3122,
12
+ daemon: false,
13
+ args: :uri,
14
+ log: 'log/connect.log',
15
+ pid: 'tmp/pids/connect.pid',
16
+ }
17
+
18
+ def self.help
19
+ puts <<-EOF
20
+ Simple HTTP CONNECT proxy to WSSH daemon
21
+
22
+ Usage: ruby #{File.basename __FILE__} [options...] ws[s]://host[:port]/uri
23
+ EOF
24
+ helptions
25
+ end
26
+
27
+ class Dst
28
+ attr_accessor :http
29
+
30
+ Connect=Module.nesting[1]
31
+
32
+ def self.count
33
+ @n||=0
34
+ @n+=1
35
+ end
36
+
37
+ def initialize(http)
38
+ self.http=http
39
+ @count=self.class.count
40
+ end
41
+
42
+ def log *msg
43
+ Connect.log "<#{@count}>", *msg
44
+ end
45
+
46
+ def send data
47
+ @ws.send data.unpack 'C*' if data.length>0
48
+ end
49
+
50
+ def connect! host
51
+ log "Redirect to", uri="#{Connect.options[:uri]}/#{host}"
52
+
53
+ http.onbody
54
+
55
+ @ws = Faye::WebSocket::Client.new uri
56
+
57
+ @ws.on :open do |event| onopen end
58
+ @ws.on :message do |event| onmessage event.data end
59
+ @ws.on :close do |event| onclose end
60
+ @ws.on :error do |error| onerror error end
61
+ end
62
+
63
+ def onopen
64
+ log "Connected to WSSHD"
65
+ http.onopen
66
+ end
67
+
68
+ def onmessage data
69
+ http.send_data Array===data ? data.pack('C*') : data
70
+ end
71
+
72
+ def onerror error
73
+ log "Websocket error", error
74
+ bye
75
+ end
76
+
77
+ def onclose
78
+ log "Websocket closed"
79
+ bye
80
+ end
81
+
82
+ def bye
83
+ http.close_connection if http
84
+ @ws.close if @ws
85
+ instance_variables.each{|v| remove_instance_variable v if '@count'!=v.to_s}
86
+ end
87
+ end
88
+
89
+ module Http
90
+ attr_accessor :dst
91
+
92
+ def log *msg
93
+ dst.log *msg
94
+ end
95
+
96
+ def wssh data
97
+ dst.send data
98
+ end
99
+
100
+ def post_init
101
+ self.dst = Dst.new self
102
+
103
+ port, ip = Socket.unpack_sockaddr_in get_peername
104
+ log "Client connected from", "#{ip}:#{port}"
105
+ end
106
+
107
+ def receive_data data
108
+ if @body
109
+ if Array===@body
110
+ @body << data
111
+ else
112
+ wssh data
113
+ end
114
+ return
115
+ end
116
+
117
+ if @hdrs
118
+ @hdrs << data
119
+ else
120
+ @hdrs = data
121
+ end
122
+ while m=/\r?\n/.match(@hdrs)
123
+ @hdrs=m.post_match
124
+ receive_line m.pre_match
125
+ end
126
+ end
127
+
128
+ def receive_line line
129
+ @nhdr||=0
130
+ if 1==(@nhdr+=1)
131
+ m=/^connect\s+([-.\w]+):22(?:$|\s)/i.match line
132
+ return @wssh = m[1] if m
133
+ @hdrs=''
134
+ log "Bad request"
135
+ send_data "HTTP/1.0 500 Bad request\r\n\r\n"
136
+ dst.bye
137
+ else
138
+ dst.connect! @wssh if 0==line.length
139
+ end
140
+ end
141
+
142
+ def onbody
143
+ @body=[@hdrs]
144
+ @hdrs=''
145
+ send_data "HTTP/1.0 200 Ok\r\n\r\n"
146
+ end
147
+
148
+ def onopen
149
+ @body.each{|data| wssh data}
150
+ @body=true
151
+ end
152
+
153
+ def unbind
154
+ log "Client disconnected"
155
+ dst.bye
156
+ end
157
+ end
158
+
159
+ def self.listen!
160
+ EM.start_server options[:host], options[:port], Http
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,25 @@
1
+ require_relative '../wssh'
2
+
3
+ module EventMachine::Wssh
4
+ module Exe
5
+ def self.do!
6
+ cmd = ARGV.shift
7
+ help unless /\A\w+\Z/.match cmd
8
+ cmd=cmd.downcase
9
+ begin
10
+ require_relative cmd
11
+ rescue LoadError
12
+ help
13
+ end
14
+ m=Module.nesting[1].const_get cmd.sub(/^./){|s|s.upcase}
15
+ help unless Module===m and m.respond_to? :go!
16
+ m.go!
17
+ end
18
+
19
+ def self.help
20
+ require_relative 'help'
21
+ Help.go!
22
+ exit
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,20 @@
1
+ require_relative 'all'
2
+
3
+ module EventMachine::Wssh
4
+ module Help
5
+ def self.go!
6
+ m=Module.nesting[1]
7
+ list=m.constants
8
+ .map{|n|m.const_get n}
9
+ .grep(Module)
10
+ .select{|m| m.respond_to? :go!}
11
+ .map{|m| m.name.split(/\W+/).last.downcase}
12
+ .sort
13
+ puts <<-EOT
14
+ WSSH v#{VERSION}
15
+
16
+ Available commands: #{list*', '}
17
+ EOT
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,159 @@
1
+ require_relative 'service'
2
+
3
+ module EventMachine::Wssh
4
+ module Server
5
+ extend Service
6
+
7
+ Need=%w(yaml em-websocket)
8
+
9
+ @options={
10
+ host: 'localhost',
11
+ port: 4567,
12
+ daemon: false,
13
+ hosts: 'hosts.yml',
14
+ log: 'log/wsshd.log',
15
+ pid: 'tmp/pids/wsshd.pid',
16
+ }
17
+
18
+ def self.help
19
+ puts <<-EOF
20
+ Proxy ssh connection through websocket
21
+
22
+ Usage: ruby #{File.basename __FILE__} [options...]
23
+ EOF
24
+ helptions
25
+ end
26
+
27
+ module Ssh
28
+ attr_accessor :req
29
+
30
+ def initialize req
31
+ self.req=req
32
+ end
33
+
34
+ def log *msg
35
+ req.log *msg
36
+ end
37
+
38
+ def post_init
39
+ log "Connected to SSH server"
40
+ req.ssh=self
41
+ req.buf.each{|data| send_data data}
42
+ req.buf=nil
43
+ end
44
+
45
+ def receive_data data
46
+ req.ws.send_binary data
47
+ end
48
+
49
+ def unbind
50
+ log 'SSH server closed connection'
51
+ req.bye
52
+ end
53
+ end
54
+
55
+ class Req
56
+ attr_accessor :ws, :buf, :ssh
57
+
58
+ Server=Module.nesting[1]
59
+
60
+ def self.count
61
+ @n||=0
62
+ @n+=1
63
+ end
64
+
65
+ def initialize ws
66
+ self.ws=ws
67
+ self.buf=[]
68
+
69
+ @count=self.class.count
70
+
71
+ port, ip=Socket.unpack_sockaddr_in ws.get_peername
72
+ log "Connect from", ip
73
+
74
+ ws.onopen{|handshake| onopen handshake}
75
+ ws.onbinary{|msg| ondata msg}
76
+ ws.onclose{|code, body| onclose}
77
+ ws.onerror{|err| onerror err}
78
+ end
79
+
80
+ def log *msg
81
+ Server.log "<#{@count}>", *msg
82
+ end
83
+
84
+ def onopen handshake
85
+ xf=handshake.headers_downcased['x-forwarded-for']
86
+ log "Forwarded for", xf if xf
87
+ log "Request", handshake.path
88
+ unless host = resolve(handshake.path) rescue nil
89
+ log "Invalid host"
90
+ bye
91
+ return
92
+ end
93
+ log "Connecting to", host
94
+ EM.connect host, 22, Ssh, self
95
+ end
96
+
97
+ def ondata msg
98
+ if buf
99
+ buf << msg
100
+ else
101
+ ssh.send_data msg
102
+ end
103
+ end
104
+
105
+ def onclose
106
+ log 'Client closed connection'
107
+ bye
108
+ end
109
+
110
+ def onerror err
111
+ log "Websocket error", err
112
+ bye
113
+ end
114
+
115
+ def resolve(path)
116
+ path = path.to_s
117
+ .split(/[^-.\w]+/)
118
+ .select{|s|s.length>0}
119
+ .select{|s|!s.match /^[-_.]|[-_.]$/}
120
+ .last
121
+ yml = YAML.load_file Server.path(:hosts)
122
+
123
+ if yml.key? path
124
+ host = yml[path]
125
+ raise 'X' unless host
126
+ host = path if true===host
127
+ host = host.to_s.strip
128
+ raise 'X' if 0==host.length
129
+ return host
130
+ end
131
+
132
+ host=nil
133
+
134
+ yml.each do |k, v|
135
+ next unless m=/^\/(.*)\/(i?)$/.match(k)
136
+ next unless Regexp.new(m[1], m[2]).match path
137
+ raise 'X' unless v
138
+ host = true===v ? path : v
139
+ host = host.to_s.strip
140
+ raise 'X' if 0==host.length
141
+ end
142
+ raise 'X' unless host
143
+ host
144
+ end
145
+
146
+ def bye
147
+ ssh.close_connection if ssh
148
+ ws.close if ws
149
+ instance_variables.each{|v| remove_instance_variable v if '@count'!=v.to_s}
150
+ end
151
+ end
152
+
153
+ def self.listen!
154
+ EM::WebSocket.run host: options[:host], port: options[:port] do |ws|
155
+ Req.new ws
156
+ end
157
+ end
158
+ end
159
+ end
@@ -0,0 +1,116 @@
1
+ require_relative '../wssh'
2
+
3
+ module EventMachine::Wssh
4
+ module Service
5
+ attr_reader :options
6
+
7
+ def log *msg
8
+ msg.unshift "[#{Time.now}]"
9
+ puts msg*' '
10
+ end
11
+
12
+ def helptions
13
+ puts <<-EOF
14
+
15
+ -a --all Listen to all interfaces
16
+ -b --base=dir Set home directory
17
+ -d --daemon Run daemonized
18
+ -h --help Show this help
19
+ -l --listen=port Listen to port
20
+ -v --version Show version
21
+ EOF
22
+ exit 1
23
+ end
24
+
25
+ def getopt
26
+ require 'getoptlong'
27
+ opts = GetoptLong.new(
28
+ ['-l', '--listen', GetoptLong::REQUIRED_ARGUMENT],
29
+ ['-b', '--base', GetoptLong::REQUIRED_ARGUMENT],
30
+ ['-d', '--daemon', GetoptLong::NO_ARGUMENT],
31
+ ['-a', '--all', GetoptLong::NO_ARGUMENT],
32
+ ['-v', '--version', GetoptLong::NO_ARGUMENT],
33
+ )
34
+ begin
35
+ opts.each do |opt, arg|
36
+ case opt
37
+ when '-d'
38
+ options[:daemon]=true
39
+ when '-l'
40
+ options[:port]=arg
41
+ when '-b'
42
+ options[:base]=File.expand_path arg
43
+ when '-a'
44
+ options[:host]='0.0.0.0'
45
+ when '-v'
46
+ puts VERSION
47
+ exit 1
48
+ end
49
+ end
50
+ rescue
51
+ help
52
+ end
53
+ args=options[:args]
54
+ args=args.nil? ? [] : [args] unless Array===args
55
+ help if args.length!=ARGV.length
56
+ args.each{|arg| options[arg]=ARGV.shift}
57
+ end
58
+
59
+ def homebase
60
+ x = File.expand_path '..', __FILE__
61
+ x = File.dirname x until File.exists? File.join x, 'Gemfile'
62
+ x
63
+ end
64
+
65
+ def path(sym)
66
+ File.join options[:base]||=homebase, options[sym]
67
+ end
68
+
69
+ def mkdir(sym)
70
+ require 'fileutils'
71
+ FileUtils.mkdir_p File.dirname file=(path sym)
72
+ file
73
+ end
74
+
75
+ def daemonize!
76
+ throw 'Cannot daemonize on Windows!' if Gem.win_platform?
77
+
78
+ log "Going on in background..."
79
+
80
+ f = File.open mkdir(:log), 'a'
81
+ f.sync=true
82
+
83
+ STDIN.reopen '/dev/null'
84
+ STDOUT.reopen f
85
+ STDERR.reopen f
86
+
87
+ Process.daemon true, true
88
+ end
89
+
90
+ def daemonize?
91
+ daemonize! if options[:daemon]
92
+ end
93
+
94
+ def pid
95
+ File.write p=mkdir(:pid), $$
96
+ at_exit do
97
+ log "Exiting..."
98
+ File.unlink p
99
+ end
100
+ end
101
+
102
+ def loop!
103
+ self::Need.each{|f| require f}
104
+ EM.run{ listen! }
105
+ end
106
+
107
+ def go!
108
+ getopt
109
+ daemonize?
110
+ log "Listening on #{options[:host]}:#{options[:port]}"
111
+ pid
112
+ loop!
113
+ end
114
+
115
+ end
116
+ end
@@ -0,0 +1,8 @@
1
+ location /ssh {
2
+ proxy_pass http://localhost:4567;
3
+ proxy_http_version 1.1;
4
+ proxy_set_header Upgrade $http_upgrade;
5
+ proxy_set_header Connection "upgrade";
6
+ proxy_set_header X-Real-IP $remote_addr;
7
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
8
+ }
metadata ADDED
@@ -0,0 +1,119 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: em-wssh
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Stas Ukolov
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-03-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: em-websocket
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faye-websocket
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '>='
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '>='
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '1.3'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '1.3'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Proxy SSH connection through Websocket (nginx)
70
+ email:
71
+ - ukoloff@gmail.com
72
+ executables:
73
+ - wssh
74
+ extensions: []
75
+ extra_rdoc_files: []
76
+ files:
77
+ - .gitignore
78
+ - FarMenu.ini
79
+ - Gemfile
80
+ - LICENSE.txt
81
+ - README.md
82
+ - Rakefile
83
+ - bin/wssh
84
+ - em-wssh.gemspec
85
+ - hosts.yml
86
+ - lib/em/wssh.rb
87
+ - lib/em/wssh/all.rb
88
+ - lib/em/wssh/client.rb
89
+ - lib/em/wssh/connect.rb
90
+ - lib/em/wssh/exe.rb
91
+ - lib/em/wssh/help.rb
92
+ - lib/em/wssh/server.rb
93
+ - lib/em/wssh/service.rb
94
+ - nginx/ssh
95
+ homepage: ''
96
+ licenses:
97
+ - MIT
98
+ metadata: {}
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - '>='
106
+ - !ruby/object:Gem::Version
107
+ version: '0'
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - '>='
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubyforge_project:
115
+ rubygems_version: 2.4.6
116
+ signing_key:
117
+ specification_version: 4
118
+ summary: ''
119
+ test_files: []