devproxy 0.1.0 → 0.2.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.
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 1.8.7
5
+ - ree
data/Gemfile CHANGED
@@ -1,3 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
+
5
+ gem "rake"
6
+ gem "travis-lint"
data/Rakefile CHANGED
@@ -1 +1,5 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task :default => :spec
@@ -0,0 +1,21 @@
1
+ body {
2
+ text-align: center;
3
+ }
4
+
5
+ .details {
6
+ width: 100%;
7
+ }
8
+
9
+ .details table {
10
+ margin: auto;
11
+ font-size: 30px;
12
+ border-collapse: collapse;
13
+ }
14
+
15
+ .details table tr:nth-child(odd) {
16
+ background-color: #efefef;
17
+ }
18
+
19
+ .details table td {
20
+ padding: 5px;
21
+ }
data/devproxy.gemspec CHANGED
@@ -11,6 +11,7 @@ Gem::Specification.new do |gem|
11
11
  gem.summary = %q{https://devproxy.io client gem}
12
12
  gem.description = %q{https://devproxy.io client gem}
13
13
  gem.homepage = "https://github.com/boz/devproxy"
14
+ gem.license = "MIT"
14
15
 
15
16
  gem.add_dependency "net-ssh", "~> 2.6.7"
16
17
  gem.add_development_dependency "rspec"
@@ -0,0 +1,63 @@
1
+ require 'webrick'
2
+ require 'cgi'
3
+ class Devproxy::CLI::Server < WEBrick::HTTPServer
4
+ class Servlet < WEBrick::HTTPServlet::AbstractServlet
5
+ def do_GET(request,response)
6
+ token = request.cookies.detect { |x| x.name == "DEVPROXY" }
7
+ token &&= token.value
8
+ token ||= "NONE"
9
+ sysname = "#{%x{whoami}}@#{%x{hostname}}"
10
+
11
+ response.status = 200
12
+ response['Content-Type'] = "text/html"
13
+ response.body = %{
14
+ <html>
15
+ <head>
16
+ <link rel="stylesheet" href="/css/style.css">
17
+ <title>Devproxy Test Server</title>
18
+ </head>
19
+ <body>
20
+ <h1>Hello from #{h(sysname)}</h2>
21
+ <div class="details">
22
+ <table>
23
+ <caption>Tunnel Details</caption>
24
+ <tbody>
25
+ <tr>
26
+ <td>host</td><td>#{h(request.host)}</td>
27
+ </tr>
28
+ <tr>
29
+ <td>protocol</td><td>#{h(request['x-forwarded-proto'])}</td>
30
+ </tr>
31
+ <tr>
32
+ <td>token</td><td>#{h(token)}</td>
33
+ </tr>
34
+ </tbody>
35
+ </table>
36
+ </div>
37
+ </body>
38
+ </html>
39
+ }
40
+ end
41
+ def h(str)
42
+ CGI::escape_html(str)
43
+ end
44
+ end
45
+ def initialize(*args)
46
+ super
47
+ mount "/" , Servlet
48
+ mount "/css", WEBrick::HTTPServlet::FileHandler, File.join(File.dirname(__FILE__),"..","..","..","data","css")
49
+ end
50
+
51
+ def start(*args)
52
+ @mutex ||= Mutex.new
53
+ @thread ||= Thread.new do
54
+ super(*args)
55
+ end
56
+ end
57
+
58
+ def shutdown
59
+ @mutex.synchronize do
60
+ super
61
+ end if @mutex
62
+ end
63
+ end
data/lib/devproxy/cli.rb CHANGED
@@ -1,10 +1,54 @@
1
1
  require 'devproxy/connection'
2
2
  require 'devproxy/options'
3
3
  require 'optparse'
4
+
4
5
  module Devproxy
5
6
  class CLI < Devproxy::Connection
7
+ class Options < Devproxy::Options
8
+ attr_accessor(:test)
9
+ end
10
+
11
+ autoload :Server, 'devproxy/cli/server'
12
+
13
+ def initialize *args
14
+ super(*args)
15
+ initialize_test_server
16
+ end
17
+
18
+ def loop!
19
+ start_test_server
20
+ super
21
+ end
22
+
23
+ def stop!
24
+ stop_test_server
25
+ super
26
+ end
27
+
28
+ protected
29
+ def testing?
30
+ options.test
31
+ end
32
+
33
+ def initialize_test_server
34
+ return unless testing?
35
+ @test_server = Server.new({
36
+ :Port => options.port,
37
+ :BindAddress => options.listen,
38
+ })
39
+ end
40
+
41
+ def start_test_server
42
+ return unless testing?
43
+ @test_server.start
44
+ end
45
+ def stop_test_server
46
+ return unless testing?
47
+ @test_server.stop
48
+ end
49
+
6
50
  def self.parse(argv)
7
- options = Devproxy::Options::default
51
+ options = Options::default
8
52
  opts = OptionParser.new
9
53
  opts.banner = "Usage: devproxy user [proxy] [options...]"
10
54
 
@@ -21,7 +65,20 @@ module Devproxy
21
65
  options.port = x
22
66
  end
23
67
 
68
+ opts.on "--test-server", "Launch local server for testing" do |x|
69
+ options.test = true
70
+ end
71
+
72
+ opts.on "-v", "--verbose",
73
+ "Verbose output (default: #{options.verbose})" do |x|
74
+ options.verbose = true
75
+ end
76
+
24
77
  if ENV['DEVPROXY_DEVELOPMENT']
78
+ opts.on "-l ADDRESS", "--listen ADDRESS",
79
+ "Local address to listen on (default: #{options.listen})" do |x|
80
+ options.listen = x
81
+ end
25
82
  opts.on "--host HOST", "remote hostname." do |x|
26
83
  options.host = x
27
84
  end
@@ -5,6 +5,7 @@ module Devproxy
5
5
  class Connection
6
6
  class Error < StandardError; end
7
7
  class Error::Authentication < Error ; end
8
+ HEARTBEAT = "HEARTBEAT"
8
9
 
9
10
  attr_reader :options, :ssh
10
11
 
@@ -28,15 +29,27 @@ module Devproxy
28
29
  @halt
29
30
  end
30
31
 
31
- def on_stdout data
32
- $stdout.write data
32
+ def on_connected
33
+ $stdout.puts "Tunneling requests from https://#{options.proxy}.devproxy.io to #{options.listen} port #{options.port}"
34
+ end
35
+
36
+ def on_heartbeat data
37
+ return unless options.verbose
38
+ $stdout.write "."
33
39
  if (@dotno += 1) % MAX_DOTS == 0
34
40
  $stdout.write "\n"
35
41
  end
36
42
  end
37
43
 
44
+ def on_stdout data
45
+ $stdout.write("\n") if options.verbose
46
+ $stdout.puts(data)
47
+ reset_dots!
48
+ end
49
+
38
50
  def on_stderr data
39
- $stderr.puts "\nError: #{data}"
51
+ $stdout.write("\n") if options.verbose
52
+ $stderr.puts(data)
40
53
  reset_dots!
41
54
  end
42
55
 
@@ -56,10 +69,14 @@ module Devproxy
56
69
  def self.create(options)
57
70
  ssh = open_ssh(options)
58
71
  connection = new(options,ssh)
59
- ssh.forward.remote(options.port,"localhost",0,'0.0.0.0')
72
+ ssh.forward.remote(options.port,options.listen,0,'0.0.0.0')
60
73
  channel = ssh.exec(options.proxy) do |ch,stream,data|
61
74
  if stream == :stdout
62
- connection.on_stdout(data)
75
+ if data.start_with?(HEARTBEAT)
76
+ connection.on_heartbeat(data)
77
+ else
78
+ connection.on_stdout(data)
79
+ end
63
80
  else
64
81
  connection.on_stderr(data)
65
82
  end
@@ -67,6 +84,7 @@ module Devproxy
67
84
  channel.on_close do
68
85
  connection.on_close
69
86
  end
87
+ connection.on_connected
70
88
  connection
71
89
  rescue Net::SSH::AuthenticationFailed
72
90
  raise Error::Authentication, "Authentication Failed: Invalid username or SSH key"
@@ -74,6 +92,7 @@ module Devproxy
74
92
  def self.open_ssh(options)
75
93
  Net::SSH.start(options.host, options.username,{
76
94
  :port => options.remote_port,
95
+ :user_known_hosts_file => "/dev/null",
77
96
  })
78
97
  end
79
98
  end
@@ -1,7 +1,7 @@
1
1
  module Devproxy
2
- class Options < Struct.new(:user, :proxy, :port, :host, :remote_port)
2
+ class Options < Struct.new(:user, :proxy, :port, :host, :remote_port, :listen, :verbose)
3
3
  def username
4
- "devproxy-#{user}"
4
+ "devproxy-#{user}" if !!user && !user.empty?
5
5
  end
6
6
  def valid?
7
7
  !( user.nil? || user.empty? ||
@@ -14,6 +14,8 @@ module Devproxy
14
14
  default.host = "ssh.devproxy.io"
15
15
  default.remote_port = 2222
16
16
  default.port = 3000
17
+ default.listen = "0.0.0.0"
18
+ default.verbose = false
17
19
  default
18
20
  end
19
21
  end
@@ -1,3 +1,3 @@
1
1
  module Devproxy
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/readme.md CHANGED
@@ -1,4 +1,4 @@
1
- # Devproxy
1
+ # Devproxy [![Build Status](https://travis-ci.org/boz/devproxy.png?branch=master)](https://travis-ci.org/boz/devproxy)
2
2
 
3
3
  [devproxy.io](https://devproxy.io) client used for tunneling
4
4
  connections from a public domain (`https://example.devproxy.io`) to your
data/spec/cli_spec.rb ADDED
@@ -0,0 +1,33 @@
1
+ require 'spec_helper'
2
+ describe Devproxy::CLI do
3
+ describe "#parse" do
4
+ it "should default the proxy to the given name" do
5
+ options = parse("foo")
6
+ expect(options.user).to eq("foo")
7
+ expect(options.proxy).to eq("foo")
8
+ end
9
+ it "should accept a different proxy name" do
10
+ options = parse("foo","bar")
11
+ expect(options.user).to eq("foo")
12
+ expect(options.proxy).to eq("bar")
13
+ end
14
+ it "should parse the port option" do
15
+ expect(parse("foo","bar","-p" ,"20").port).to eq(20)
16
+ expect(parse("foo","bar","--port","20").port).to eq(20)
17
+ expect(parse("foo","bar" ).port).to eq(Devproxy::Options.default.port)
18
+ end
19
+ it "should parse the test server option" do
20
+ expect(parse("foo","bar","--test-server").test).to be_true
21
+ expect(parse("foo","bar" ).test).to be_false
22
+ end
23
+ it "should parse the verbose option" do
24
+ expect(parse("foo","bar","-v" ).verbose).to be_true
25
+ expect(parse("foo","bar","--verbose").verbose).to be_true
26
+ expect(parse("foo","bar" ).verbose).to be_false
27
+ end
28
+ end
29
+
30
+ def parse(*args)
31
+ Devproxy::CLI::parse(args)
32
+ end
33
+ end
@@ -0,0 +1,47 @@
1
+ require 'spec_helper'
2
+ describe Devproxy::Options do
3
+ describe "defaults" do
4
+ it "should have default values" do
5
+ options = default_options
6
+ expect(options.host ).to eq("ssh.devproxy.io")
7
+ expect(options.remote_port ).to eq(2222)
8
+ expect(options.port ).to eq(3000)
9
+ expect(options.listen ).to eq("0.0.0.0")
10
+ expect(options.verbose ).to eq(false)
11
+ end
12
+ it "should not have username or proxy" do
13
+ options = default_options
14
+ expect(options.username).to be_nil
15
+ expect(options.proxy ).to be_nil
16
+ end
17
+ end
18
+
19
+ describe "valid?" do
20
+ it "should require a username" do
21
+ expect(default_options(:proxy => "foo")).to_not be_valid
22
+ end
23
+ it "should require a username" do
24
+ expect(default_options(:user => "bar")).to_not be_valid
25
+ end
26
+ it "should only need a username and proxy" do
27
+ expect(default_options(:proxy => "foo", :user => "bar")).to be_valid
28
+ end
29
+ end
30
+
31
+ describe "username" do
32
+ it "should include name" do
33
+ expect(default_options(:user => "bar").username).to include("bar")
34
+ end
35
+ it "should be nil if no name is given" do
36
+ expect(default_options.username).to be_nil
37
+ end
38
+ end
39
+
40
+ def default_options(options = {})
41
+ default = Devproxy::Options.default
42
+ options.each do |key,value|
43
+ default.__send__("#{key}=",value)
44
+ end
45
+ default
46
+ end
47
+ end
@@ -0,0 +1,3 @@
1
+ require 'devproxy'
2
+ RSpec.configure do
3
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devproxy
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-07-19 00:00:00.000000000 Z
12
+ date: 2013-07-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: net-ssh
@@ -52,20 +52,27 @@ extensions: []
52
52
  extra_rdoc_files: []
53
53
  files:
54
54
  - .gitignore
55
+ - .travis.yml
55
56
  - Gemfile
56
57
  - LICENSE.txt
57
58
  - Rakefile
58
59
  - bin/devproxy
60
+ - data/css/style.css
59
61
  - devproxy.gemspec
60
62
  - lib/devproxy.rb
61
63
  - lib/devproxy/cli.rb
64
+ - lib/devproxy/cli/server.rb
62
65
  - lib/devproxy/connection.rb
63
66
  - lib/devproxy/net-ssh-patch.rb
64
67
  - lib/devproxy/options.rb
65
68
  - lib/devproxy/version.rb
66
69
  - readme.md
70
+ - spec/cli_spec.rb
71
+ - spec/options_spec.rb
72
+ - spec/spec_helper.rb
67
73
  homepage: https://github.com/boz/devproxy
68
- licenses: []
74
+ licenses:
75
+ - MIT
69
76
  post_install_message:
70
77
  rdoc_options: []
71
78
  require_paths:
@@ -76,16 +83,25 @@ required_ruby_version: !ruby/object:Gem::Requirement
76
83
  - - ! '>='
77
84
  - !ruby/object:Gem::Version
78
85
  version: '0'
86
+ segments:
87
+ - 0
88
+ hash: -760381207862352631
79
89
  required_rubygems_version: !ruby/object:Gem::Requirement
80
90
  none: false
81
91
  requirements:
82
92
  - - ! '>='
83
93
  - !ruby/object:Gem::Version
84
94
  version: '0'
95
+ segments:
96
+ - 0
97
+ hash: -760381207862352631
85
98
  requirements: []
86
99
  rubyforge_project:
87
100
  rubygems_version: 1.8.25
88
101
  signing_key:
89
102
  specification_version: 3
90
103
  summary: https://devproxy.io client gem
91
- test_files: []
104
+ test_files:
105
+ - spec/cli_spec.rb
106
+ - spec/options_spec.rb
107
+ - spec/spec_helper.rb