gas 0.1.7 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
data/lib/gas.rb CHANGED
@@ -1,15 +1,21 @@
1
- GAS_DIRECTORY = File.expand_path('~/.gas')
2
- SSH_DIRECTORY = File.expand_path('~/.ssh')
1
+ require 'rbconfig'
2
+
3
+ GAS_DIRECTORY = "#{ENV['HOME']}/.gas" # File.expand_path('~/.gas')
4
+ SSH_DIRECTORY = "#{ENV['HOME']}/.ssh" # File.expand_path('~/.ssh')
3
5
  GITHUB_SERVER = 'api.github.com'
6
+ IS_WINDOWS = (RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/)
4
7
 
5
8
 
6
9
  require 'sshkey' #external
7
10
 
8
11
  require 'gas/version'
12
+ require 'gas/prompter'
9
13
  require 'gas/ssh'
10
14
  require 'gas/user'
11
15
  require 'gas/config'
12
16
  require 'gas/gitconfig'
17
+ require 'gas/settings'
18
+ require 'gas/github_speaker'
13
19
 
14
20
 
15
21
  module Gas
@@ -24,8 +30,6 @@ module Gas
24
30
  puts
25
31
  puts @config
26
32
  puts
27
-
28
- # self.show # XXX: get rid of
29
33
  end
30
34
 
31
35
  # Shows the current user
@@ -43,11 +47,11 @@ module Gas
43
47
  # Sets _nickname_ as current user
44
48
  # @param [String] nickname The nickname to use
45
49
  def self.use(nickname)
46
- self.no_user? nickname
50
+ return false unless self.no_user?(nickname)
47
51
  user = @config[nickname]
48
-
52
+
49
53
  @gitconfig.change_user user # daring change made here! Heads up Walle
50
-
54
+
51
55
  self.show
52
56
  end
53
57
 
@@ -55,21 +59,21 @@ module Gas
55
59
  # @param [String] nickname The nickname of the author
56
60
  # @param [String] name The name of the author
57
61
  # @param [String] email The email of the author
58
- def self.add(nickname, name, email)
62
+ def self.add(nickname, name, email, github_speaker = nil)
59
63
  return false if self.has_user?(nickname)
60
64
  user = User.new name, email, nickname
61
65
  @config.add user
62
66
  @config.save!
63
-
67
+
64
68
  using_ssh = Ssh.setup_ssh_keys user
65
69
 
66
- Ssh.upload_public_key_to_github(user) if using_ssh
67
-
70
+ Ssh.upload_public_key_to_github(user, github_speaker) if using_ssh
71
+
68
72
  puts 'Added new author'
69
73
  puts user
70
74
  end
71
-
72
-
75
+
76
+
73
77
  # Adds an ssh key for the specified user
74
78
  def self.ssh(nickname)
75
79
  if nickname.nil?
@@ -89,26 +93,26 @@ module Gas
89
93
  puts "The ssh feature of gas offers you and the world ease of use, and even marginally enhanced privacy against corporate databases. Did you know that IBM built one of the first automated database systems? These ancient database machines (called tabulators) were used to facilitate the holocaust =("
90
94
  else
91
95
  user = @config[nickname]
92
-
93
-
96
+
97
+
94
98
  # Prompt Remake this user's ssh keys?
95
-
99
+
96
100
  # check for ssh keys
97
101
  if !Ssh.corresponding_rsa_files_exist?(nickname)
98
102
  Ssh.setup_ssh_keys user
99
103
  Ssh.upload_public_key_to_github user
100
- else
104
+ else
101
105
  Ssh.setup_ssh_keys user
102
106
  Ssh.upload_public_key_to_github user
103
107
  end
104
108
  end
105
109
  end
106
-
110
+
107
111
 
108
112
  # Imports current user from .gitconfig to .gas
109
113
  # @param [String] nickname The nickname to give to the new user
110
114
  def self.import(nickname)
111
- self.has_user? nickname
115
+ return false if self.has_user?(nickname)
112
116
  user = @gitconfig.current_user
113
117
 
114
118
  if user
@@ -127,18 +131,13 @@ module Gas
127
131
  # Deletes an author from the config using nickname
128
132
  # @param [String] nickname The nickname of the author
129
133
  def self.delete(nickname)
130
-
134
+
131
135
  return false unless self.no_user? nickname # I re-engineered this section so I could use Gas.delete in a test even when that author didn't exist
132
- # TODO: The name no_user? is now very confusing. It should be changed to something like "is_user?" now maybe?
133
-
134
- Ssh.delete nickname # XXX: there are 2 calls to this in the method!
135
-
136
-
137
- # exit
136
+ # TODO: The name no_user? is now very confusing. It should be changed to something like "user_exists?" now maybe?
137
+ Ssh.delete nickname
138
+
138
139
  @config.delete nickname
139
140
  @config.save!
140
-
141
- #Ssh.delete nickname # TODO: delete this duplicate after...
142
141
 
143
142
  puts "Deleted author #{nickname}"
144
143
  return true
data/lib/gas/config.rb CHANGED
@@ -10,9 +10,9 @@ module Gas
10
10
  # then it creates the ~/.gas FOLDER and saves the old .gas file as ~/git.conf
11
11
  #
12
12
  def migrate_to_gas_dir!
13
- old_config_file = File.expand_path('~/.gas')
14
- config_dir = File.expand_path('~/.gas')
15
- new_config_file = File.expand_path('~/.gas') + "/gas.authors"
13
+ old_config_file = GAS_DIRECTORY
14
+ config_dir = GAS_DIRECTORY
15
+ new_config_file = GAS_DIRECTORY + "/gas.authors"
16
16
 
17
17
  if File.file? old_config_file
18
18
  file = File.open(old_config_file, "rb")
@@ -35,8 +35,8 @@ module Gas
35
35
  # @param [String] config The override config
36
36
  def initialize(users = nil, config = nil)
37
37
  migrate_to_gas_dir! # Migrates old users to the new configuration file location, how thoughtful of me, I know
38
- @config_file = File.expand_path('~/.gas/gas.authors')
39
- @gas_dir = File.expand_path('~/.gas')
38
+ @config_file = "#{GAS_DIRECTORY}/gas.authors"
39
+ @gas_dir = GAS_DIRECTORY
40
40
  @config = ''
41
41
 
42
42
  if config.nil?
@@ -0,0 +1,219 @@
1
+ module Gas
2
+ # A beautiful class that makes working with the github API an enjoyable experience
3
+ class GithubSpeaker
4
+ attr_reader :user, :account_name, :password, :keys, :status
5
+ attr_accessor :server
6
+
7
+ def keys
8
+ refresh_keys if @keys.nil?
9
+ @keys
10
+ end
11
+
12
+ def initialize(user, account_name=nil, password=nil, server = 'api.github.com')
13
+ @user = user
14
+ @server = server
15
+ @keys = nil
16
+
17
+ # sort out username and password... Make it's own function?
18
+ if account_name.nil? and password.nil?
19
+ # Prompt for username and password
20
+ credentials = get_username_and_password_diligently
21
+ @account_name = credentials[:account_name] # this overwrite happens twice to make testing easier... Stub on get_username, kekeke
22
+ @password = credentials[:password]
23
+ else
24
+ @account_name = account_name
25
+ @password = password
26
+ authenticate
27
+ end
28
+
29
+ end
30
+
31
+
32
+ def post_key!(rsa)
33
+ refresh_keys if @keys.nil?
34
+
35
+ puts "Posting key to GitHub.com..."
36
+
37
+ # find key...
38
+ if has_key(rsa)
39
+ puts "Key already installed."
40
+ return false
41
+ end
42
+ title = "GAS: #{@user.nickname}"
43
+ result = install_key(rsa)
44
+
45
+ if result != false
46
+ @keys << result
47
+ return true
48
+ end
49
+ end
50
+
51
+
52
+ def refresh_keys
53
+ raise "Attempted to update keys when unable to authenticate credentials with github" if @status != :authenticated
54
+
55
+ path = '/user/keys'
56
+
57
+ http = Net::HTTP.new(@server,443)
58
+ req = Net::HTTP::Get.new(path)
59
+ http.use_ssl = true
60
+ req.basic_auth @account_name, @password
61
+ response = http.request(req)
62
+
63
+ @keys = JSON.parse(response.body)
64
+ end
65
+
66
+
67
+ # Cycles through github, looking to see if rsa exists as a public key, then deletes it if it does
68
+ def remove_key!(rsa)
69
+ refresh_keys
70
+
71
+ # loop through arrays checking against 'key'
72
+ @keys.each do |key|
73
+ if key["key"] == rsa
74
+ return remove_key_by_id!(key["id"])
75
+ end
76
+ end
77
+
78
+ return false # key not found
79
+ end
80
+
81
+
82
+ private
83
+ def authenticate
84
+ path = '/user'
85
+
86
+ http = Net::HTTP.new(@server,443)
87
+ http.use_ssl = true
88
+
89
+ req = Net::HTTP::Get.new(path)
90
+ req.basic_auth @account_name, @password
91
+ response = http.request(req)
92
+
93
+ result = JSON.parse(response.body)["message"]
94
+
95
+ if result == "Bad credentials"
96
+ @status = :bad_credentials
97
+ return false
98
+ else
99
+ @status = :authenticated
100
+ return true
101
+ end
102
+ end
103
+
104
+ def get_username_and_password_and_authenticate
105
+ puts "Type your github.com user name:"
106
+ print "User: "
107
+ account_name = STDIN.gets.strip
108
+
109
+ puts "Type your github password:"
110
+ password = ask("Password: ") { |q| q.echo = false }
111
+ puts
112
+
113
+ credentials = {:account_name => account_name, :password => password}
114
+ #p credentials
115
+ @account_name = account_name
116
+ @password = password
117
+
118
+ if authenticate
119
+ return credentials
120
+ else
121
+ return false
122
+ end
123
+ end
124
+
125
+ # Get's the username and password from the user, then authenticates. If it fails, it asks them if they'd like to try again.
126
+ # Returns false if aborted
127
+ def get_username_and_password_diligently
128
+ while true
129
+ credentials = get_username_and_password_and_authenticate
130
+ if credentials == false
131
+ puts "Could not authenticate, try again?"
132
+ puts "y/n"
133
+
134
+ again = STDIN.gets.strip
135
+ case again.downcase
136
+ when "y"
137
+ when "n"
138
+ return false
139
+ end
140
+ else
141
+ return credentials
142
+ end
143
+ end
144
+ end
145
+
146
+ def install_key(rsa)
147
+ require "socket"
148
+ host_name = Socket.gethostname
149
+
150
+ title = "GAS: #{@user.nickname} \-#{host_name}"
151
+
152
+ path = '/user/keys'
153
+
154
+ http = Net::HTTP.new(@server, 443) # 443 for ssl
155
+ http.use_ssl = true
156
+
157
+ req = Net::HTTP::Post.new(path)
158
+ req.basic_auth @account_name, @password
159
+ req.body = "{\"title\":\"#{title}\", \"key\":\"#{rsa}\"}"
160
+
161
+ response = http.start {|m_http| m_http.request(req) }
162
+ the_code = response.code
163
+
164
+ key_json = JSON.parse(response.body)
165
+
166
+ return key_json if the_code == "201"
167
+
168
+ puts "The key you are trying to use already exists in another github user's account. You need to use another key." if the_code == "already_exists"
169
+
170
+ # currently.. I think it always returns "already_exists" even if successful. API bug.
171
+ puts "Something may have gone wrong. Either github changed their API, or your key couldn't be installed." if the_code != "already_exists"
172
+
173
+ #return true if my_hash.key?("errors") # this doesn't work due to it being a buggy API atm # false change me to false when they fix their API
174
+ puts "Server Response: #{response.body}"
175
+ return false
176
+ end
177
+
178
+ # Cycles through github, looking to see if rsa exists as a public key, then deletes it if it does
179
+ def has_key(rsa)
180
+ refresh_keys if @keys.nil?
181
+ return false if @keys.empty?
182
+
183
+ # loop through arrays checking against 'key'
184
+ @keys.each do |key|
185
+ return true if key["key"] == rsa
186
+ end
187
+
188
+ return false # key not found
189
+ end
190
+
191
+ def remove_key_by_id!(id)
192
+ path = "/user/keys/#{id}"
193
+
194
+ http = Net::HTTP.new(@server,443)
195
+ http.use_ssl = true
196
+ req = Net::HTTP::Delete.new(path)
197
+ req.basic_auth @account_name, @password
198
+
199
+ response = http.request(req)
200
+
201
+ if response.body.nil?
202
+ #@keys = nil # lame hack! sooo lazy of me. I should learn how to remove the proper key from the @keys hash...
203
+ remove_key_from_keys id
204
+ return true
205
+ end
206
+ end
207
+
208
+
209
+ def remove_key_from_keys(id_to_delete)
210
+ @keys.each.with_index do |key, i|
211
+ @keys.delete_at(i) if key['id'].to_i == id_to_delete.to_i
212
+ end
213
+ end
214
+
215
+
216
+
217
+
218
+ end
219
+ end
@@ -0,0 +1,169 @@
1
+ module Gas
2
+ module Prompter
3
+ @invalid_input_response_with_default = "Please use 'y' or 'n' or enter for default."
4
+ # If the user says 'f', the system will
5
+ # report that there isn't an id_rsa already in gas. This causes a new key to overwrite automatically down the road.
6
+ # This is for checking if a .gas/rsa file already exists for a nickname which is being registered
7
+ # If the rsa exists, then we're goona need to ask if we should use it, or if we should delete it
8
+ #
9
+ # Returns true to indicate that the user would like to use the rsa file already in .gas ()
10
+ # Returns false when there are no naming conflicts.
11
+ def self.user_wants_to_use_key_already_in_gas?(uid = '')
12
+ puts "Gas has detected a key in its archive directory ~/.gas/#{uid}_id_rsa. Should gas use this key or overwrite this key with a brand new one?"
13
+ puts "Keep current key? [y/n]"
14
+
15
+ while true
16
+ keep_current_file = clean_gets
17
+
18
+ case keep_current_file
19
+
20
+ when "y"
21
+ return true # keep the files already in .gas, skip making key.
22
+ when "n"
23
+ return false
24
+ else
25
+ puts "please respond 'y' or 'n'"
26
+ end
27
+ end
28
+ end
29
+
30
+ # Checks if the ~/.ssh directroy contains id_rsa and id_rsa.pub
31
+ # if it does, it asks the user if they would like to use that as their ssh key, instead of generating a new key pair.
32
+ #
33
+ def self.user_wants_to_use_key_already_in_ssh?
34
+ puts "Generate a brand new ssh key pair? (Choose 'n' to use key in ~/.ssh/id_rsa)"
35
+ puts "Default: 'y'"
36
+ puts "[Y/n]"
37
+
38
+ while true
39
+ generate_new_rsa = clean_gets.downcase
40
+ case generate_new_rsa
41
+ when "y", ""
42
+ return false
43
+ when "n"
44
+ return true # return true if we aren't generating a new key
45
+ else
46
+ puts @invalid_input_response_with_default
47
+ end
48
+ end
49
+ end
50
+
51
+ def self.user_wants_gas_to_handle_rsa_keys?
52
+ puts
53
+ puts "Do you want gas to handle switching rsa keys for this user?"
54
+ puts "[Y/n]"
55
+
56
+ while true
57
+ handle_rsa = clean_gets
58
+
59
+ case handle_rsa
60
+ when "y", ""
61
+ return true
62
+ when "n"
63
+ return false
64
+ else
65
+ puts "Please use 'y' or 'n'"
66
+ end
67
+ end
68
+ end
69
+
70
+ def self.user_wants_to_remove_the_keys_that_already_exist_for_this_user?(uid)
71
+ puts
72
+ puts "Well... there's already a ~/.gas/#{uid}_id_rsa configured and ready to go. Are you sure you don't want gas to handle rsa switching? (Clicking no will delete the key from the gas directory)"
73
+ puts "Just let gas handle ssh key for this user? [y/n]"
74
+
75
+ while true
76
+ keep_file = clean_gets
77
+
78
+ case keep_file
79
+ when "n"
80
+ return true
81
+ when "y"
82
+ puts "Excelent! Gas will handle rsa keys for this user."
83
+ return false
84
+ else
85
+ puts @invalid_input_response_with_default
86
+ end
87
+ end
88
+ end
89
+
90
+ # This is another prompt function, but it returns a more complicated lexicon
91
+ #
92
+ # returns "a", "l", "g", or "n"
93
+ def self.user_wants_to_delete_all_ssh_data?
94
+ puts "Would you like to remove all of this user's ssh keys too!?!"
95
+ puts "(github account keys can be removed as well!)"
96
+ puts
97
+ puts "a: All, the local copy, and checks github too."
98
+ puts "l: Remove local key only."
99
+ puts "g: Removes key from github.com only."
100
+ puts "n: Don't remove this user's keys."
101
+ puts "Default: l"
102
+
103
+ while true
104
+ delete_all_keys = clean_gets
105
+
106
+ case delete_all_keys.downcase
107
+ when "a"
108
+ return "a"
109
+ when "l", ""
110
+ return "l"
111
+ when "g"
112
+ return "g"
113
+ when "n"
114
+ return "n"
115
+ else
116
+ puts "please use 'a', 'l', 'g' or 'n' for NONE."
117
+ end
118
+ end
119
+ end
120
+
121
+ def self.user_wants_to_install_key_to_github?
122
+ puts "Gas can automatically install this ssh key into the github account of your choice. Would you like gas to do this for you? (Requires inputting github username and password)"
123
+ puts "[Y/n]"
124
+
125
+ while true
126
+ upload_key = clean_gets.downcase
127
+ case upload_key
128
+ when "y", ""
129
+ return true
130
+ when "n"
131
+ return false
132
+ else
133
+ puts @invalid_input_response_with_default
134
+ end
135
+ end
136
+ end
137
+
138
+ def self.user_wants_to_overwrite_existing_rsa_key?
139
+ puts "~/.ssh/id_rsa already exists. Overwrite?"
140
+ puts "[y/n]"
141
+
142
+ while true
143
+ overwrite = clean_gets
144
+ case overwrite
145
+ when "y"
146
+ return true
147
+ when "n"
148
+ return false
149
+ else
150
+ puts "please respond 'y' or 'n'"
151
+ end
152
+ end
153
+ end
154
+
155
+ # If the user hits ctrl+c with this, it will exit cleanly
156
+ def self.clean_gets
157
+ begin
158
+ getit = STDIN.gets.strip
159
+ rescue SystemExit, Interrupt # catch if they hit ctrl+c
160
+ puts
161
+ puts "Safely aborting operation..." # reassure user that ctrl+c is fine to use.
162
+ exit
163
+ end
164
+
165
+ return getit
166
+ end
167
+
168
+ end
169
+ end