tmuxme 0.0.1
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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/bin/tmuxme +132 -0
- data/lib/tmuxme/version.rb +3 -0
- data/lib/tmuxme.rb +5 -0
- data/scripts/tmuxme_install +95 -0
- data/tmuxme.gemspec +26 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d66f4cedbba19c4a4b0942af1a45749f41437613
|
4
|
+
data.tar.gz: f0ab574d9600d278e0676a235f4c8a2c5528e837
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0905c1851374b473116ae596ddf4471842298456e6175db639d68bec1a702c5110f49d27d06a22152787b6f44f431a23c9f5063293de85195e440f696af4d2eb
|
7
|
+
data.tar.gz: 64ff7056b16657534275e83973b264a080bc454ad7e1d272fb9fd92a55c25c87383d947c5b8af72ea48dd35c37589397feb568f5cceb1fa4a7a4445810a92e79
|
data/.gitignore
ADDED
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
tmuxme_client
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.0.0-p247
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Andrew De Ponte, ReachLocal Inc.
|
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.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# TmuxmeClient
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'tmuxme_client'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install tmuxme_client
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/tmuxme
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rest-client'
|
5
|
+
require 'net/ssh'
|
6
|
+
require 'json'
|
7
|
+
require 'thread'
|
8
|
+
|
9
|
+
Thread.abort_on_exception = true
|
10
|
+
|
11
|
+
def generate_authorized_keys_content(public_keys)
|
12
|
+
cleaned_keys = []
|
13
|
+
public_keys.each do |pk|
|
14
|
+
cleaned_keys << "command=\"tmux -S /tmp/tmuxme_pair_sock attach\" #{pk.strip}"
|
15
|
+
end
|
16
|
+
return cleaned_keys.join("\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
if ARGV.length < 1
|
20
|
+
puts "You can't pair program with yourself silly."
|
21
|
+
puts "Usage: tmuxme user1 [user2...]"
|
22
|
+
exit
|
23
|
+
end
|
24
|
+
|
25
|
+
invitees = ARGV.dup
|
26
|
+
pairers = []
|
27
|
+
|
28
|
+
remote_port = nil
|
29
|
+
remote_port_lock = Mutex.new
|
30
|
+
|
31
|
+
begin
|
32
|
+
# back up users authorized_keys file
|
33
|
+
if !File.exists?("#{ENV['HOME']}/.ssh/authorized_keys.tmuxme.original")
|
34
|
+
puts "- Backing up ~/.ssh/authorized_keys to ~/.ssh/authorized_keys.tmuxme.original to store it the first time tmuxme was run"
|
35
|
+
FileUtils.cp("#{ENV['HOME']}/.ssh/authorized_keys", "#{ENV['HOME']}/.ssh/authorized_keys.tmuxme.original")
|
36
|
+
end
|
37
|
+
puts "- Backing up ~/.ssh/authorized_keys to ~/.ssh/authorized_keys.tmuxme.backup"
|
38
|
+
FileUtils.cp("#{ENV['HOME']}/.ssh/authorized_keys", "#{ENV['HOME']}/.ssh/authorized_keys.tmuxme.backup")
|
39
|
+
|
40
|
+
public_keys = []
|
41
|
+
# fetch the specified users public keys
|
42
|
+
invitees.each do |invitee|
|
43
|
+
begin
|
44
|
+
response = RestClient.get "http://tmux.me/api/v1/users/#{invitee}/public_keys.json"
|
45
|
+
current_invitees_public_keys = JSON.parse(response.to_s)
|
46
|
+
if current_invitees_public_keys.empty?
|
47
|
+
puts
|
48
|
+
puts "Warning: Pair (#{invitee}) does not have any public keys on tmux.me. Ask them to add one."
|
49
|
+
else
|
50
|
+
pairers << invitee
|
51
|
+
public_keys.concat(current_invitees_public_keys)
|
52
|
+
end
|
53
|
+
rescue => e
|
54
|
+
case e.response.code
|
55
|
+
when 404
|
56
|
+
puts
|
57
|
+
puts "Warning: Pair (#{invitee}) is not a tmux.me registered user. Please ask them to signup and add their public key."
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
if public_keys.empty?
|
63
|
+
puts
|
64
|
+
puts "Error: Either the users you provided don't exist or they don't have keys on tmux.me."
|
65
|
+
exit 1
|
66
|
+
end
|
67
|
+
|
68
|
+
# generate the new authorized_keys content from obtained public keys
|
69
|
+
content = generate_authorized_keys_content(public_keys)
|
70
|
+
|
71
|
+
original_authorized_keys_content = File.read("#{ENV['HOME']}/.ssh/authorized_keys")
|
72
|
+
|
73
|
+
# prepend the generated content to the authorized_keys file
|
74
|
+
puts "- Updating ~/.ssh/authorized_keys with (#{pairers.join(', ')}) public keys"
|
75
|
+
new_authorized_keys_content = [content, original_authorized_keys_content].join("\n")
|
76
|
+
File.open("#{ENV['HOME']}/.ssh/authorized_keys", "w") do |f|
|
77
|
+
f.write(new_authorized_keys_content)
|
78
|
+
end
|
79
|
+
|
80
|
+
# setup the remote port forward (need to spin off this in a sep thread)
|
81
|
+
Thread.new do
|
82
|
+
port = nil
|
83
|
+
while true
|
84
|
+
# Fetch an un-used high numbered port from the tmux.me REST api.
|
85
|
+
remote_port_lock.synchronize {
|
86
|
+
remote_port = 6000 + rand(50000)
|
87
|
+
port = remote_port
|
88
|
+
}
|
89
|
+
|
90
|
+
begin
|
91
|
+
# Starts the tunnel but blocks so would probably need to throw this in a child
|
92
|
+
# thread of the process.
|
93
|
+
Net::SSH.start("tmux.me", "tunnel") do |ssh|
|
94
|
+
ssh.forward.remote(22, "localhost", port, "0.0.0.0")
|
95
|
+
ssh.loop { true }
|
96
|
+
end
|
97
|
+
rescue Exception => e
|
98
|
+
puts e.message
|
99
|
+
next
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# launch detached tmux sessions
|
105
|
+
`tmux -S /tmp/tmuxme_pair_sock new-session -s tmuxme -d`
|
106
|
+
|
107
|
+
puts
|
108
|
+
puts "E-mail invites will be sent to (#{pairers.join(', ')}) when you press enter below."
|
109
|
+
puts "However, to manually invite (#{pairers.join(', ')}) to the pairing session instruct them to run the following:"
|
110
|
+
puts
|
111
|
+
remote_port_lock.synchronize {
|
112
|
+
puts "\tssh #{ENV['USER']}@tmux.me -p #{remote_port}"
|
113
|
+
}
|
114
|
+
puts
|
115
|
+
print "Press enter to invite (#{pairers.join(', ')}) via e-mail and attach to the tmux session."
|
116
|
+
$stdout.flush
|
117
|
+
garbage = $stdin.gets
|
118
|
+
|
119
|
+
# notify tmux.me service that the pairing session is ready
|
120
|
+
puts "Sending invites to (#{pairers.join(', ')})."
|
121
|
+
remote_port_lock.synchronize {
|
122
|
+
RestClient.post "http://tmux.me/api/v1/pairing_sessions", :system_user => ENV['USER'], :pairing_users => pairers, :port_number => remote_port
|
123
|
+
}
|
124
|
+
|
125
|
+
# attach to tmux session and wait for that process to exit
|
126
|
+
`tmux -S /tmp/tmuxme_pair_sock attach`
|
127
|
+
ensure
|
128
|
+
puts
|
129
|
+
puts "- Restoring ~/.ssh/authorized_keys from ~/.ssh/authorized_keys.tmuxme.backup"
|
130
|
+
# when the tmux process exits then restore the authorized_keys file
|
131
|
+
FileUtils.cp("#{ENV['HOME']}/.ssh/authorized_keys.tmuxme.backup", "#{ENV['HOME']}/.ssh/authorized_keys")
|
132
|
+
end
|
data/lib/tmuxme.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
|
3
|
+
function getAvailableHiddenUserUid()
|
4
|
+
{
|
5
|
+
local __UIDS=$(dscl . -list /Users UniqueID | awk '{print $2}' | sort -ugr)
|
6
|
+
local __NewUID
|
7
|
+
for __NewUID in $__UIDS
|
8
|
+
do
|
9
|
+
if [[ $__NewUID -lt 499 && $__NewUID -ne 498 ]] ; then
|
10
|
+
break;
|
11
|
+
fi
|
12
|
+
done
|
13
|
+
|
14
|
+
echo $((__NewUID+1))
|
15
|
+
}
|
16
|
+
|
17
|
+
function generateRandomPassword()
|
18
|
+
{
|
19
|
+
echo `date | md5`
|
20
|
+
}
|
21
|
+
|
22
|
+
|
23
|
+
# Make sure only root can run our script
|
24
|
+
if [[ $EUID -ne 0 ]]; then
|
25
|
+
echo "This script must be run as root" 1>&2
|
26
|
+
exit 1
|
27
|
+
fi
|
28
|
+
|
29
|
+
# USER_UID=499 # this should be a number under 500 so it is a hidden account
|
30
|
+
USER_UID=$(getAvailableHiddenUserUid)
|
31
|
+
|
32
|
+
# This script is design to provide a simple mechanism to help with automating
|
33
|
+
# the process of creating an account for gitosis to use on systems.
|
34
|
+
|
35
|
+
# The following are variables which are likely to change per installation.
|
36
|
+
USERNAME="tmuxme"
|
37
|
+
USER_FULL_NAME="tmuxme"
|
38
|
+
|
39
|
+
# The following are variables unlikely to change but possibly could change
|
40
|
+
# per installation.
|
41
|
+
PRIMARY_GID=1000
|
42
|
+
|
43
|
+
# The following are variables which are highly unlikely to change and may
|
44
|
+
# only change for differences in the operating system.
|
45
|
+
USER_SHELL="/bin/bash" # Mac OS X 10.5.6
|
46
|
+
# LOC_DOMAIN="/Local/Default" # Mac OS X 10.5.6
|
47
|
+
LOC_DOMAIN="." # Mac OS X 10.5.6
|
48
|
+
|
49
|
+
PASSWORD=$(generateRandomPassword)
|
50
|
+
|
51
|
+
# Tell the system to automatically hide user accounts thate have a UID < 500
|
52
|
+
# LOGIN_WIN_PREFS="/Library/Preferences/com.apple.loginwindow"
|
53
|
+
# defaults write ${LOGIN_WIN_PREFS} Hide500Users -bool YES
|
54
|
+
#
|
55
|
+
# Create the user entry.
|
56
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME}
|
57
|
+
|
58
|
+
# Set the users shell.
|
59
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME} UserShell ${USER_SHELL}
|
60
|
+
|
61
|
+
# Set the users full name.
|
62
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME} RealName "${USER_FULL_NAME}"
|
63
|
+
|
64
|
+
# Associate the user with a unique id.
|
65
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME} UniqueID ${USER_UID}
|
66
|
+
|
67
|
+
# Associate the user with a primary gorup id.
|
68
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME} PrimaryGroupID ${PRIMARY_GID}
|
69
|
+
|
70
|
+
# Create the users home directory.
|
71
|
+
dscl ${LOC_DOMAIN} -create /Users/${USERNAME} NFSHomeDirectory /Users/${USERNAME}
|
72
|
+
|
73
|
+
# Set the users password.
|
74
|
+
dscl ${LOC_DOMAIN} -passwd /Users/${USERNAME} ${PASSWORD}
|
75
|
+
|
76
|
+
|
77
|
+
mkdir -p /Users/${USERNAME}/.ssh
|
78
|
+
touch /Users/${USERNAME}/.ssh/authorized_keys
|
79
|
+
chown -R ${USER_UID}:${PRIMARY_GID} /Users/${USERNAME}
|
80
|
+
chmod 0700 /Users/${USERNAME}/.ssh
|
81
|
+
chmod 0600 /Users/${USERNAME}/.ssh/authorized_keys
|
82
|
+
|
83
|
+
# Enable Remote Login if it is not currently enabled.
|
84
|
+
systemsetup -setremotelogin on &>/dev/null
|
85
|
+
|
86
|
+
if [[ $(dscl ${LOC_DOMAIN} list /Groups | grep 'access_ssh') = 'com.apple.access_ssh' ]]; then
|
87
|
+
# Remote Access is limted to specific users
|
88
|
+
USER_GENERATED_UID=$(dscl . -read /Users/${USERNAME} GeneratedUID | awk '{print $2}')
|
89
|
+
dscl ${LOC_DOMAIN} -read /Groups/com.apple.access_ssh GroupMembership | grep ${USERNAME} &>/dev/null
|
90
|
+
if [[ $? -ne 0 ]]; then # user is not in access list
|
91
|
+
# Append the "tmuxme" user to the list of users allowed to connect remotely
|
92
|
+
dscl ${LOC_DOMAIN} -append /Groups/com.apple.access_ssh GroupMembers ${USER_GENERATED_UID}
|
93
|
+
dscl ${LOC_DOMAIN} -append /Groups/com.apple.access_ssh GroupMembership ${USERNAME}
|
94
|
+
fi
|
95
|
+
fi
|
data/tmuxme.gemspec
ADDED
@@ -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 'tmuxme/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "tmuxme"
|
8
|
+
spec.version = Tmuxme::VERSION
|
9
|
+
spec.authors = ["Andrew De Ponte"]
|
10
|
+
spec.email = ["cyphactor@gmail.com"]
|
11
|
+
spec.description = %q{The official client for the http://tmux.me pair programming service}
|
12
|
+
spec.summary = %q{Command line client for the http://tmux.me pairing service.}
|
13
|
+
spec.homepage = "http://tmux.me"
|
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_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
|
24
|
+
spec.add_dependency "rest-client", "~> 1.6.7"
|
25
|
+
spec.add_dependency "net-ssh", "~> 2.6.8"
|
26
|
+
end
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: tmuxme
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrew De Ponte
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-08-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.3'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.3'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
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: rest-client
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 1.6.7
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.6.7
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: net-ssh
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.6.8
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.6.8
|
69
|
+
description: The official client for the http://tmux.me pair programming service
|
70
|
+
email:
|
71
|
+
- cyphactor@gmail.com
|
72
|
+
executables:
|
73
|
+
- tmuxme
|
74
|
+
extensions: []
|
75
|
+
extra_rdoc_files: []
|
76
|
+
files:
|
77
|
+
- .gitignore
|
78
|
+
- .ruby-gemset
|
79
|
+
- .ruby-version
|
80
|
+
- Gemfile
|
81
|
+
- LICENSE.txt
|
82
|
+
- README.md
|
83
|
+
- Rakefile
|
84
|
+
- bin/tmuxme
|
85
|
+
- lib/tmuxme.rb
|
86
|
+
- lib/tmuxme/version.rb
|
87
|
+
- scripts/tmuxme_install
|
88
|
+
- tmuxme.gemspec
|
89
|
+
homepage: http://tmux.me
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - '>='
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubyforge_project:
|
109
|
+
rubygems_version: 2.0.5
|
110
|
+
signing_key:
|
111
|
+
specification_version: 4
|
112
|
+
summary: Command line client for the http://tmux.me pairing service.
|
113
|
+
test_files: []
|