em-wssh 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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: []