tbm 0.1.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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # Tunnels
2
+
3
+ A simple Ruby script to manage named SSH tunnels because I need these regularly and it's a bit of a pain to manage this in some other way.
4
+
5
+ At the moment, this will be a command that you invoke, and leave running. At some point, it might make sense to make this two processes -- one that stays alive while there are active tunnels, and a command-line that interacts with that process. For now, that's more work than I intend to bite off -- more of a v2 feature.
data/Rakefile ADDED
@@ -0,0 +1,42 @@
1
+ require 'rake/clean'
2
+ require 'rake/packagetask'
3
+ require 'rspec/core/rake_task'
4
+ require 'rspec'
5
+ require 'rubygems'
6
+ require 'rubygems/package_task'
7
+ require 'tbm'
8
+
9
+ CLEAN.include( 'coverage', 'pkg' )
10
+
11
+ desc '"spec" (run RSpec)'
12
+ task :default => :spec
13
+
14
+ desc "Run RSpec on spec/*"
15
+ RSpec::Core::RakeTask.new
16
+
17
+ desc "Generate code coverage"
18
+ RSpec::Core::RakeTask.new(:coverage) do |t|
19
+ t.rcov = true
20
+ t.rcov_opts = ['--exclude', 'spec,/gems/,/rubygems/', '--text-report']
21
+ end
22
+
23
+ spec = Gem::Specification.new do |spec|
24
+ spec.name = 'tbm'
25
+ spec.version = Tunnel::VERSION
26
+ spec.date = Tunnel::DATE
27
+ spec.summary = 'Named SSH tunnels, like bookmarks.'
28
+ spec.description = 'The "Tunnel Boring Machine" is meant to bore ssh tunnels through the internet to your desired destination simply and repeatedly, as often as you need them. This is a tool for someone who needs SSH tunnels frequently.'
29
+ spec.author = 'Geoffrey Wiseman'
30
+ spec.email = 'geoffrey.wiseman@codiform.com'
31
+ spec.homepage = 'http://github.com/geoffreywiseman/tunnel-boring-machine'
32
+ spec.executables << 'tbm'
33
+
34
+ spec.files = Dir['{lib,spec}/**/*.rb', 'bin/*', 'Rakefile', 'README.md', 'UNLICENSE']
35
+
36
+ spec.add_dependency( 'net/ssh', '>= 2.6.2' )
37
+ end
38
+
39
+ Gem::PackageTask.new( spec ) do |pkg|
40
+ pkg.need_tar_gz = true
41
+ pkg.need_zip = true
42
+ end
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
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 NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/bin/tbm ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tbm'
4
+
5
+ Tunnel::CommandLineInterface.parse_and_run
data/lib/tbm.rb ADDED
@@ -0,0 +1,4 @@
1
+ require 'tunnel/meta'
2
+ require 'tunnel/cli'
3
+ require 'tunnel/config'
4
+ require 'tunnel/target'
data/lib/tunnel/cli.rb ADDED
@@ -0,0 +1,69 @@
1
+ require 'net/ssh'
2
+
3
+ module Tunnel
4
+ class CommandLineInterface
5
+ def initialize( config )
6
+ @config = config
7
+ @target = nil
8
+ @cancelled = false
9
+ end
10
+
11
+ def parse
12
+ if ARGV.size != 1
13
+ print_targets "SYNTAX: tbm <target>\n\nWhere target is one of:"
14
+ else
15
+ target_name = ARGV[0]
16
+ @target = @config.get_target( target_name )
17
+ print_targets( "Cannot find target: #{target_name}\n\nThese are the targets currently defined:" ) if @target.nil?
18
+ end
19
+ end
20
+
21
+ def print_targets( message )
22
+ puts message
23
+ @config.each_target { |target| puts "\t#{target.name}" }
24
+ end
25
+
26
+
27
+ def valid?
28
+ !@target.nil?
29
+ end
30
+
31
+ def bore
32
+ puts "Starting #{APP_NAME} v#{VERSION}"
33
+ puts
34
+
35
+ trap("INT") { @cancelled = true }
36
+ Net::SSH.start( @target.host, @target.username ) do |session|
37
+ forward_ports( session )
38
+ end
39
+
40
+ puts "Shutting down the machine."
41
+ end
42
+
43
+ def forward_ports( session )
44
+ begin
45
+ puts "Opened connection to #{@target.username}@#{@target.host}:"
46
+ @target.each_forward do |fwd|
47
+ remote_server, port = fwd
48
+ session.forward.local( port, remote_server, port )
49
+ puts "\tforwarded port #{port} to #{remote_server}:#{port}"
50
+ end
51
+ puts "\twaiting for Ctrl-C..."
52
+ session.loop(0.1) { not @cancelled }
53
+ puts "\n\tCtrl-C pressed. Exiting."
54
+ rescue Errno::EACCES
55
+ @cancelled = true
56
+ puts "\tCould not open all ports; you may need to sudo if port < 1000."
57
+ end
58
+ end
59
+
60
+ def self.parse_and_run
61
+ config = Config.new
62
+ if config.valid?
63
+ cli = CommandLineInterface.new( config )
64
+ cli.parse
65
+ cli.bore if cli.valid?
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,93 @@
1
+ require 'etc'
2
+
3
+ module Tunnel
4
+ class Config
5
+ CONFIG_FILE = File.expand_path( '~/.tunnels' )
6
+
7
+ def initialize
8
+ @valid = nil
9
+ @targets = []
10
+ if File.file? CONFIG_FILE
11
+ config_data = YAML.load_file( CONFIG_FILE )
12
+ parse config_data if config_data.is_a? Hash
13
+ else
14
+ puts "Configure your tunnels in ~/.tunnels in YAML form."
15
+ end
16
+ end
17
+
18
+ def valid?
19
+ @valid
20
+ end
21
+
22
+ def get_target( name )
23
+ @targets.find { |target| target.has_name?(name) }
24
+ end
25
+
26
+ def each_target( &block )
27
+ @targets.each { |target| yield target }
28
+ end
29
+
30
+ private
31
+
32
+ def parse( targets )
33
+ targets.each_key { |name| parse_target name, targets[name] }
34
+ @valid = true if @valid.nil? && !@targets.empty?
35
+ end
36
+
37
+ def parse_target( name, config )
38
+ if config.is_a? Hash
39
+ target = create_target( name, config )
40
+ unless target.nil?
41
+ @targets << target
42
+ parse_forward( target, config['forward'] )
43
+ end
44
+ else
45
+ puts "Cannot parse target '#{name}' (#{config.class})"
46
+ @valid = false
47
+ end
48
+ end
49
+
50
+ def create_target( name, config )
51
+ if config.has_key? 'host' then
52
+ if config.has_key? 'username' then
53
+ username = config['username']
54
+ else
55
+ username = Etc.getlogin
56
+ end
57
+ Target.new name, config['host'], username
58
+ else
59
+ puts "Cannot parse target '#{name}': no host found."
60
+ @valid = false
61
+ end
62
+ end
63
+
64
+ def parse_forward( target, config )
65
+ case config
66
+ when nil
67
+ puts "Target #{target.name} has no forwards defined."
68
+ @valid = false
69
+ when Fixnum
70
+ target.forward_port( config )
71
+ when Array
72
+ config.each { |port| target.forward_port(port) }
73
+ when Hash
74
+ config.each_key do |server|
75
+ server_config = config[ server ]
76
+ case server_config
77
+ when Fixnum
78
+ target.forward_port( server_config, server )
79
+ when Array
80
+ server_config.each { |port| target.forward_port( port, server ) }
81
+ else
82
+ puts "Not sure how to handle forward from #{target.host} to #{server}: #{server_config.class}"
83
+ end
84
+ end
85
+ else
86
+ puts "Not sure how to handle forward for '#{target.host}': #{config.class}"
87
+ @valid = false
88
+ end
89
+ end
90
+
91
+ end
92
+
93
+ end
@@ -0,0 +1,5 @@
1
+ module Tunnel
2
+ APP_NAME = "Tunnel Boring Machine"
3
+ VERSION = "0.1.0"
4
+ DATE = '2012-11-23'
5
+ end
@@ -0,0 +1,24 @@
1
+ module Tunnel
2
+ class Target
3
+ attr_reader :name, :host, :username
4
+
5
+ def initialize( name, host, username )
6
+ @name = name
7
+ @host = host
8
+ @username = username
9
+ @forwards = []
10
+ end
11
+
12
+ def forward_port( port, server='localhost' )
13
+ @forwards << [ server, port ]
14
+ end
15
+
16
+ def has_name?( name )
17
+ @name==name
18
+ end
19
+
20
+ def each_forward( &block )
21
+ @forwards.each { |fwd| yield fwd }
22
+ end
23
+ end
24
+ end
metadata ADDED
@@ -0,0 +1,83 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tbm
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Geoffrey Wiseman
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2012-11-23 00:00:00 -05:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ type: :runtime
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ segments:
27
+ - 2
28
+ - 6
29
+ - 2
30
+ version: 2.6.2
31
+ name: net/ssh
32
+ requirement: *id001
33
+ prerelease: false
34
+ description: The "Tunnel Boring Machine" is meant to bore ssh tunnels through the internet to your desired destination simply and repeatedly, as often as you need them. This is a tool for someone who needs SSH tunnels frequently.
35
+ email: geoffrey.wiseman@codiform.com
36
+ executables:
37
+ - tbm
38
+ extensions: []
39
+
40
+ extra_rdoc_files: []
41
+
42
+ files:
43
+ - lib/tbm.rb
44
+ - lib/tunnel/cli.rb
45
+ - lib/tunnel/config.rb
46
+ - lib/tunnel/meta.rb
47
+ - lib/tunnel/target.rb
48
+ - bin/tbm
49
+ - Rakefile
50
+ - README.md
51
+ - UNLICENSE
52
+ has_rdoc: true
53
+ homepage: http://github.com/geoffreywiseman/tunnel-boring-machine
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options: []
58
+
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ segments:
66
+ - 0
67
+ version: "0"
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ requirements: []
76
+
77
+ rubyforge_project:
78
+ rubygems_version: 1.3.6
79
+ signing_key:
80
+ specification_version: 3
81
+ summary: Named SSH tunnels, like bookmarks.
82
+ test_files: []
83
+