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 +27 -28
- data/lib/gas/config.rb +5 -5
- data/lib/gas/github_speaker.rb +219 -0
- data/lib/gas/prompter.rb +169 -0
- data/lib/gas/settings.rb +28 -0
- data/lib/gas/ssh.rb +86 -411
- data/lib/gas/version.rb +1 -1
- data/spec/integration/ssh_spec.rb +338 -0
- data/spec/spec_helper.rb +110 -34
- data/spec/{gas → unit}/config_spec.rb +15 -15
- data/spec/{gas → unit}/gitconfig_spec.rb +10 -10
- data/spec/unit/github_speaker_spec.rb +107 -0
- data/spec/unit/settings_spec.rb +56 -0
- data/spec/{gas → unit}/user_spec.rb +0 -0
- metadata +116 -27
- data/spec/gas/ssh_spec.rb +0 -328
data/lib/gas/settings.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Gas
|
2
|
+
|
3
|
+
# Class that contains settings for the app
|
4
|
+
class Settings
|
5
|
+
attr_accessor :base_dir, :github_server
|
6
|
+
attr_reader :gas_dir, :ssh_dir
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@base_dir = '~'
|
10
|
+
@gas_dir = "#{@base_dir}/.gas"
|
11
|
+
@ssh_dir = "#{@base_dir}/.ssh"
|
12
|
+
@github_server = 'api.github.com'
|
13
|
+
end
|
14
|
+
|
15
|
+
def configure
|
16
|
+
yield self if block_given?
|
17
|
+
end
|
18
|
+
|
19
|
+
def gas_dir=(value)
|
20
|
+
@gas_dir = "#{@base_dir}/#{value}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def ssh_dir=(value)
|
24
|
+
@ssh_dir = "#{@base_dir}/#{value}"
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
data/lib/gas/ssh.rb
CHANGED
@@ -1,42 +1,10 @@
|
|
1
1
|
module Gas
|
2
|
-
|
3
2
|
class Ssh
|
4
3
|
require 'highline/import'
|
5
4
|
require 'net/https'
|
6
5
|
require 'json'
|
7
|
-
|
8
|
-
|
9
|
-
# If the user says 'f', the system will
|
10
|
-
# report that there isn't an id_rsa already in gas. This causes a new key to overwrite automatically down the road.
|
11
|
-
# This is for checking if a .gas/rsa file already exists for a nickname which is being registered
|
12
|
-
# If the rsa exists, then we're goona need to ask if we should use it, or if we should delete it
|
13
|
-
#
|
14
|
-
# Returns true to indicate that the user would like to use the rsa file already in .gas ()
|
15
|
-
# Returns false when there is no naming conflicts.
|
16
|
-
def self.user_wants_to_use_key_already_in_gas?
|
17
|
-
if corresponding_rsa_files_exist?
|
18
|
-
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?"
|
19
|
-
puts "Keep current key? [y/n]"
|
20
|
-
|
21
|
-
while true
|
22
|
-
keep_current_file = STDIN.gets.strip
|
23
|
-
|
24
|
-
case keep_current_file
|
25
|
-
|
26
|
-
when "y"
|
27
|
-
return true # keep the files already in .gas, skip making key.
|
28
|
-
when "n"
|
29
|
-
return false
|
30
|
-
else
|
31
|
-
puts "please respond 'y' or 'n'"
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
else # no need to do anything if files don't exist
|
36
|
-
return false
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
6
|
+
require 'digest/md5'
|
7
|
+
extend Prompter
|
40
8
|
|
41
9
|
def self.corresponding_rsa_files_exist?(nickname = '')
|
42
10
|
nickname = @uid if nickname == ''
|
@@ -44,60 +12,27 @@ module Gas
|
|
44
12
|
false
|
45
13
|
end
|
46
14
|
|
47
|
-
|
48
15
|
# Copies a key pair from ~/.ssh to .gas/Nickname*
|
49
16
|
def self.use_current_rsa_files_for_this_user(test = nil)
|
50
17
|
@uid = test unless test.nil?
|
51
|
-
|
52
|
-
|
18
|
+
FileUtils.cp("#{SSH_DIRECTORY}/id_rsa", "#{GAS_DIRECTORY}/#{@uid}_id_rsa")
|
19
|
+
FileUtils.cp("#{SSH_DIRECTORY}/id_rsa.pub", "#{GAS_DIRECTORY}/#{@uid}_id_rsa.pub")
|
20
|
+
FileUtils.chmod 0700, "#{GAS_DIRECTORY}/#{@uid}_id_rsa"
|
21
|
+
FileUtils.chmod 0700, "#{GAS_DIRECTORY}/#{@uid}_id_rsa.pub"
|
53
22
|
return true
|
54
23
|
end
|
55
24
|
|
56
|
-
|
57
25
|
def self.ssh_dir_contains_rsa?
|
58
26
|
return true if File.exists?(SSH_DIRECTORY + "/id_rsa") or File.exists?(SSH_DIRECTORY + "/id_rsa.pub")
|
59
27
|
return false
|
60
28
|
end
|
61
29
|
|
62
|
-
|
63
|
-
|
64
|
-
# Checks if the ~/.ssh directroy contains id_rsa and id_rsa.pub
|
65
|
-
# 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.
|
66
|
-
#
|
67
|
-
def self.user_wants_to_use_key_already_in_ssh?
|
68
|
-
return false unless ssh_dir_contains_rsa?
|
69
|
-
|
70
|
-
#puts "Gas has detected that an ~/.ssh/id_rsa file already exists. Would you like to use this as your ssh key to connect with github? Otherwise a new key will be generated and stored in ~/.gas (no overwrite concerns until you 'gas use nickname')"
|
71
|
-
puts "Generate a brand new ssh key pair? (Choose 'n' to use key in ~/.ssh/id_rsa)"
|
72
|
-
puts "Default: 'y'"
|
73
|
-
puts "[Y/n]"
|
74
|
-
|
75
|
-
while true
|
76
|
-
generate_new_rsa = STDIN.gets.strip.downcase
|
77
|
-
case generate_new_rsa
|
78
|
-
when "y", ""
|
79
|
-
return false
|
80
|
-
when "n"
|
81
|
-
return true # return true if we aren't generating a new key
|
82
|
-
else
|
83
|
-
puts "plz answer 'y' or 'n'"
|
84
|
-
end
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
|
89
|
-
|
90
30
|
# Generates a new sshkey putting it in ~/.gas/nickname_id_rsa
|
91
31
|
# This function can get a little tricky. It's best to strip off the comment here,
|
92
32
|
# because github API doesn't retain the comment...
|
93
33
|
def self.generate_new_rsa_keys_in_gas_dir
|
94
34
|
puts "Generating new ssh key..."
|
95
|
-
# TODO: Prompt user if they'd like to use a more secure password if physical security to their computer is not possible (dumb imo)... Unless we do that thing where we store keys on github!
|
96
35
|
|
97
|
-
# Old ssh key method (relies on unix environment)
|
98
|
-
# puts `ssh-keygen -f ~/.gas/#{@uid}_id_rsa -t rsa -C "#{@email}" -N ""` # ssh-keygen style key creation
|
99
|
-
|
100
|
-
# new sshkey gem method...
|
101
36
|
begin
|
102
37
|
k = SSHKey.generate() # (:comment => "#{@email}")
|
103
38
|
|
@@ -120,124 +55,61 @@ module Gas
|
|
120
55
|
end
|
121
56
|
end
|
122
57
|
|
123
|
-
|
124
|
-
|
125
|
-
def self.user_wants_gas_to_handle_rsa_keys?
|
126
|
-
puts "Do you want gas to handle switching rsa keys for this user?"
|
127
|
-
puts "[Y/n]"
|
128
|
-
|
129
|
-
while true
|
130
|
-
handle_rsa = STDIN.gets.strip
|
131
|
-
|
132
|
-
case handle_rsa
|
133
|
-
when "y", ""
|
134
|
-
return true
|
135
|
-
when "n"
|
136
|
-
puts
|
137
|
-
# check if ~/.gas/rsa exists, if it does, promt the user
|
138
|
-
if corresponding_rsa_files_exist? #in ~/.gas/
|
139
|
-
|
140
|
-
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)"
|
141
|
-
puts "Just let gas handle ssh key for this user? [y/n]"
|
142
|
-
|
143
|
-
while true
|
144
|
-
keep_file = STDIN.gets.strip
|
145
|
-
|
146
|
-
case keep_file
|
147
|
-
when "n"
|
148
|
-
delete "~/.gas/#{@uid}_id_rsa", "~/.gas/#{@uid}_id_rsa.pub"
|
149
|
-
return false
|
150
|
-
when "y"
|
151
|
-
puts "Excelent! Gas will handle rsa keys for this user."
|
152
|
-
return nil
|
153
|
-
else
|
154
|
-
puts "Please use 'y' or 'n' or enter to choose default."
|
155
|
-
end
|
156
|
-
end
|
157
|
-
end
|
158
|
-
return false
|
159
|
-
|
160
|
-
else
|
161
|
-
puts "Please use 'y' or 'n'"
|
162
|
-
end
|
163
|
-
end
|
164
|
-
|
165
|
-
|
166
|
-
end
|
167
|
-
|
168
58
|
# This function creates the ssh keys if needed and puts them in ~/.gas/NICKNAME_id_rsa and ...rsa.pub
|
169
|
-
#
|
170
|
-
#
|
171
59
|
def self.setup_ssh_keys(user)
|
172
60
|
@uid = user.nickname
|
173
61
|
@email = user.email
|
174
62
|
|
175
|
-
|
176
|
-
|
177
|
-
if wants_gas_handling_keys
|
178
|
-
puts
|
179
|
-
|
180
|
-
if user_wants_to_use_key_already_in_gas?
|
63
|
+
if Gas::Prompter.user_wants_gas_to_handle_rsa_keys?
|
64
|
+
if corresponding_rsa_files_exist?(@uid) and Gas::Prompter.user_wants_to_use_key_already_in_gas?(@uid)
|
181
65
|
return true # We don't need to do anything because the .gas directory is already setup
|
182
|
-
elsif user_wants_to_use_key_already_in_ssh? # Check ~/.ssh for a current id_rsa file, if yes, "Do you want to use the current id_rsa file to be used as your key?"
|
66
|
+
elsif !corresponding_rsa_files_exist?(@uid) and ssh_dir_contains_rsa? and Gas::Prompter.user_wants_to_use_key_already_in_ssh? # Check ~/.ssh for a current id_rsa file, if yes, "Do you want to use the current id_rsa file to be used as your key?"
|
183
67
|
use_current_rsa_files_for_this_user # copies the keys from ~/.ssh instead of generating new keys if desired/possible
|
184
68
|
return true
|
185
69
|
else
|
186
70
|
return generate_new_rsa_keys_in_gas_dir
|
187
71
|
end
|
188
72
|
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
73
|
+
else # !Gas::Prompter.user_wants_gas_to_handle_rsa_keys?
|
74
|
+
# check if ~/.gas/rsa exists, if it does, promt the user
|
75
|
+
# because that key must be destroyed (if the user really doesn't want gas handling keys for this user)
|
76
|
+
if corresponding_rsa_files_exist?(@uid) #in ~/.gas/
|
77
|
+
delete_associated_local_keys!(@uid) if Gas::Prompter.user_wants_to_remove_the_keys_that_already_exist_for_this_user?(@uid)
|
78
|
+
end
|
193
79
|
end
|
194
80
|
|
195
81
|
end
|
196
82
|
|
197
|
-
|
198
83
|
# This huge method handles the swapping of id_rsa files on the hdd
|
199
|
-
#
|
200
84
|
def self.swap_in_rsa(nickname)
|
201
85
|
@uid = nickname # woah, this is extremely sloppy I think... in order to use any other class methods,
|
202
86
|
# I need to write to @uid or it will
|
203
87
|
# Have the dumb information from the last time it registered a new git author?
|
204
88
|
|
205
|
-
if
|
206
|
-
|
89
|
+
if corresponding_rsa_files_exist?
|
207
90
|
if ssh_dir_contains_rsa?
|
208
91
|
if current_key_already_backed_up?
|
209
92
|
write_to_ssh_dir!
|
210
93
|
else
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
overwrite = STDIN.gets.strip
|
216
|
-
case overwrite
|
217
|
-
when "y"
|
218
|
-
write_to_ssh_dir!
|
219
|
-
break
|
220
|
-
when "n"
|
221
|
-
puts "Proceeding without swapping rsa keys."
|
222
|
-
break
|
223
|
-
else
|
224
|
-
puts "please respond 'y' or 'n'"
|
225
|
-
end
|
94
|
+
if Gas::Prompter.user_wants_to_overwrite_existing_rsa_key?
|
95
|
+
write_to_ssh_dir!
|
96
|
+
else
|
97
|
+
puts "Proceeding without swapping rsa keys (aborting)."
|
226
98
|
end
|
227
|
-
|
228
99
|
end
|
229
|
-
|
230
|
-
else # if no ~/.ssh/id_rsa exists... no overwrite potential
|
100
|
+
else # if no ~/.ssh/id_rsa exists... no overwrite potential... so just write away
|
231
101
|
write_to_ssh_dir!
|
232
102
|
end
|
233
|
-
|
234
103
|
end
|
235
104
|
end
|
236
105
|
|
237
|
-
|
106
|
+
|
238
107
|
def self.write_to_ssh_dir!
|
108
|
+
supress_process_output = "> /dev/null 2>&1"
|
109
|
+
supress_process_output = "> NUL" if IS_WINDOWS
|
110
|
+
|
239
111
|
# remove the current key from the ssh-agent session (key will no longer be used with github)
|
240
|
-
system(
|
112
|
+
system("ssh-add -d #{SSH_DIRECTORY}/id_rsa #{supress_process_output}") if is_ssh_agent_there?
|
241
113
|
|
242
114
|
FileUtils.cp(GAS_DIRECTORY + "/#{@uid}_id_rsa", SSH_DIRECTORY + "/id_rsa")
|
243
115
|
FileUtils.cp(GAS_DIRECTORY + "/#{@uid}_id_rsa.pub", SSH_DIRECTORY + "/id_rsa.pub")
|
@@ -246,23 +118,24 @@ module Gas
|
|
246
118
|
FileUtils.chmod(0700, SSH_DIRECTORY + "/id_rsa.pub")
|
247
119
|
|
248
120
|
if is_ssh_agent_there?
|
249
|
-
`ssh-add
|
250
|
-
|
251
|
-
|
252
|
-
puts "Looks like there may have been a fatal error in registering the rsa key with ssh-agent. Might be worth looking into"
|
121
|
+
`ssh-add #{SSH_DIRECTORY}/id_rsa #{supress_process_output}` # you need to run this command to get the private key to be set to active on unix based machines. Not sure what to do for windows yet...
|
122
|
+
|
123
|
+
if $?.exitstatus == 1 # exit status 1 means failed
|
124
|
+
puts "Looks like there may have been a fatal error in registering the rsa key with ssh-agent. Might be worth looking into"
|
125
|
+
raise "Exit code on ssh-add command line was one meaning: Error!"
|
253
126
|
end
|
127
|
+
|
254
128
|
else
|
255
129
|
puts "Slight Error: The key should now be in ~/.ssh so that's good, BUT ssh-add could not be found. If you're using windows, you'll need to use git bash or cygwin to emulate this unix command and actually do uploads."
|
256
130
|
end
|
131
|
+
|
257
132
|
end
|
258
133
|
|
259
|
-
|
260
|
-
#
|
134
|
+
# This function scans each file in a directory to check
|
135
|
+
# to see if it is the same file which it's being compared against
|
261
136
|
# dir_to_scan The target directory you'd like to scan
|
262
137
|
# file_to_compare The file's path that you're expecting to find
|
263
138
|
def self.scan_for_file_match(file_to_compare, dir_to_scan)
|
264
|
-
require 'digest/md5'
|
265
|
-
|
266
139
|
pattern = get_md5_hash(file_to_compare)
|
267
140
|
|
268
141
|
@files = Dir.glob(dir_to_scan + "/*" + file_to_compare.split(//).last(1).to_s)
|
@@ -274,7 +147,6 @@ module Gas
|
|
274
147
|
return false
|
275
148
|
end
|
276
149
|
|
277
|
-
|
278
150
|
def self.current_key_already_backed_up?
|
279
151
|
if scan_for_file_match(SSH_DIRECTORY + "/id_rsa", GAS_DIRECTORY) and scan_for_file_match(SSH_DIRECTORY + "/id_rsa.pub", GAS_DIRECTORY)
|
280
152
|
return true
|
@@ -285,243 +157,74 @@ module Gas
|
|
285
157
|
|
286
158
|
def self.get_md5_hash(file_path)
|
287
159
|
if File.exists? file_path
|
288
|
-
|
160
|
+
file = File.open(file_path, "rb")
|
161
|
+
hash = Digest::MD5.hexdigest(file.read)
|
162
|
+
file.close
|
163
|
+
return hash
|
289
164
|
end
|
290
165
|
return nil
|
291
166
|
end
|
292
167
|
|
293
168
|
|
294
|
-
def self.
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
while true
|
299
|
-
upload_key = STDIN.gets.strip.downcase
|
300
|
-
case upload_key
|
301
|
-
when "y", ""
|
302
|
-
return true
|
303
|
-
when "n"
|
304
|
-
return false
|
305
|
-
else
|
306
|
-
puts "Plz respond 'y' or 'n'"
|
307
|
-
end
|
308
|
-
end
|
309
|
-
end
|
310
|
-
|
311
|
-
|
312
|
-
def self.upload_public_key_to_github(user)
|
313
|
-
@uid = user.nickname
|
314
|
-
|
315
|
-
if user_wants_to_install_key_to_github?
|
316
|
-
key_installation_routine!
|
169
|
+
def self.upload_public_key_to_github(user, github_speaker = nil)
|
170
|
+
if Gas::Prompter.user_wants_to_install_key_to_github?
|
171
|
+
key_installation_routine!(user, nil, github_speaker)
|
317
172
|
end
|
318
173
|
end
|
319
174
|
|
320
|
-
|
321
|
-
def self.key_installation_routine!(user = nil, rsa_test = nil)
|
175
|
+
|
176
|
+
def self.key_installation_routine!(user = nil, rsa_test = nil, github_speaker = nil)
|
322
177
|
@uid = user.nickname unless user.nil? # allows for easy testing
|
323
178
|
|
324
|
-
rsa_key = get_associated_rsa_key(@uid)
|
179
|
+
rsa_key = get_associated_rsa_key(@uid).first
|
325
180
|
rsa_key = rsa_test unless rsa_test.nil?
|
326
181
|
return false if rsa_key.nil?
|
327
182
|
|
328
183
|
# TODO: Impliment a key ring system where you store your key on your github in a repository, only it's encrypted. And to decrypt it, there is
|
329
184
|
# A file in your .gas folder!!! That sounds SO fun!
|
330
|
-
|
185
|
+
github_speaker = GithubSpeaker.new(user) if github_speaker.nil?
|
186
|
+
|
187
|
+
puts github_speaker.status
|
331
188
|
|
332
|
-
if
|
189
|
+
if github_speaker.status == :bad_credentials
|
333
190
|
puts "Invalid credentials. Skipping upload of keys to github. "
|
334
191
|
puts "To try again, type $ gas ssh #{@uid}"
|
335
192
|
return false
|
336
193
|
end
|
337
|
-
|
338
|
-
result = post_key!(
|
194
|
+
|
195
|
+
result = github_speaker.post_key!(rsa_key)
|
196
|
+
|
339
197
|
if result
|
340
198
|
puts "Key uploaded successfully!"
|
341
199
|
return true
|
342
200
|
end
|
343
201
|
end
|
344
202
|
|
345
|
-
|
346
|
-
#
|
203
|
+
# Get's the ~/.gas/user_id_rsa and ~/.gas/user_id_rsa.pub strings associated with
|
204
|
+
# the specified user and returns it as an array. Returns array with two nils if there's no keys
|
205
|
+
# [pub_rsa, priv_rsa]
|
347
206
|
def self.get_associated_rsa_key(nickname)
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
end
|
359
|
-
return nil
|
360
|
-
end
|
361
|
-
|
362
|
-
|
363
|
-
def self.get_username_and_password_and_authenticate
|
364
|
-
puts "Type your github.com user name:"
|
365
|
-
print "User: "
|
366
|
-
username = STDIN.gets.strip
|
367
|
-
|
368
|
-
puts "Type your github password:"
|
369
|
-
password = ask("Password: ") { |q| q.echo = false }
|
370
|
-
puts
|
371
|
-
|
372
|
-
credentials = {:username => username, :password => password}
|
373
|
-
|
374
|
-
if valid_github_username_and_pass?(credentials[:username], credentials[:password])
|
375
|
-
return credentials
|
376
|
-
else
|
377
|
-
return false
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
# Get's the username and password from the user, then authenticates. If it fails, it asks them if they'd like to try again.
|
382
|
-
# Returns false if aborted
|
383
|
-
def self.get_username_and_password_diligently
|
384
|
-
while true
|
385
|
-
credentials = get_username_and_password_and_authenticate
|
386
|
-
if !credentials
|
387
|
-
puts "Could not authenticate, try again?"
|
388
|
-
puts "y/n"
|
389
|
-
|
390
|
-
again = STDIN.gets.strip
|
391
|
-
case again.downcase
|
392
|
-
when "y"
|
393
|
-
when "n"
|
394
|
-
return false
|
395
|
-
end
|
396
|
-
else
|
397
|
-
return credentials
|
207
|
+
pub_path = "#{GAS_DIRECTORY}/#{nickname}_id_rsa.pub"
|
208
|
+
priv_path = "#{GAS_DIRECTORY}/#{nickname}_id_rsa"
|
209
|
+
|
210
|
+
if File.exists? pub_path and File.exists? priv_path
|
211
|
+
pub_file = File.open(pub_path, "rb")
|
212
|
+
pub_rsa = pub_file.read.strip
|
213
|
+
pub_file.close
|
214
|
+
if pub_rsa.count(' ') == 2 # special trick to split off the trailing comment text because github API won't store it.
|
215
|
+
pub_rsa = pub_rsa.split(" ")
|
216
|
+
pub_rsa = "#{rsa[0]} #{rsa[1]}"
|
398
217
|
end
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
def self.valid_github_username_and_pass?(username, password)
|
404
|
-
path = '/user'
|
405
|
-
|
406
|
-
http = Net::HTTP.new(GITHUB_SERVER,443)
|
407
|
-
http.use_ssl = true
|
408
|
-
|
409
|
-
req = Net::HTTP::Get.new(path)
|
410
|
-
req.basic_auth username, password
|
411
|
-
response = http.request(req)
|
412
|
-
|
413
|
-
result = JSON.parse(response.body)["message"]
|
414
|
-
|
415
|
-
return false if result == "Bad credentials"
|
416
|
-
return true
|
417
|
-
end
|
418
|
-
|
419
|
-
|
420
|
-
def self.post_key!(credentials, nickname, rsa)
|
421
|
-
puts "Posting key to GitHub.com..."
|
422
|
-
rsa_key = rsa
|
423
|
-
username = credentials[:username]
|
424
|
-
password = credentials[:password]
|
425
|
-
|
426
|
-
|
427
|
-
# find key...
|
428
|
-
if has_key(username, password, rsa_key)
|
429
|
-
puts "Key already installed."
|
430
|
-
return false
|
431
|
-
end
|
432
|
-
title = "GAS: #{nickname}"
|
433
|
-
install_key(username, password, title, rsa_key)
|
434
|
-
end
|
435
|
-
|
436
|
-
|
437
|
-
def self.remove_key_by_id!(username, password, id)
|
438
|
-
server = 'api.github.com'
|
439
|
-
path = "/user/keys/#{id}"
|
440
|
-
|
441
|
-
|
442
|
-
http = Net::HTTP.new(server,443)
|
443
|
-
http.use_ssl = true
|
444
|
-
req = Net::HTTP::Delete.new(path)
|
445
|
-
req.basic_auth username, password
|
446
|
-
|
447
|
-
response = http.request(req)
|
448
|
-
|
449
|
-
return true if response.body.nil?
|
450
|
-
end
|
451
|
-
|
452
|
-
# Cycles through github, looking to see if rsa exists as a public key, then deletes it if it does
|
453
|
-
def self.has_key(username, password, rsa)
|
454
|
-
# get all keys
|
455
|
-
keys = get_keys(username, password)
|
456
|
-
# loop through arrays checking against 'key'
|
457
|
-
keys.each do |key|
|
458
|
-
if key["key"] == rsa
|
459
|
-
return true
|
460
|
-
end
|
461
|
-
end
|
462
|
-
|
463
|
-
return false # key not found
|
464
|
-
end
|
465
|
-
|
218
|
+
|
219
|
+
priv_file = File.open(priv_path, "rb")
|
220
|
+
priv_rsa = priv_file.read.strip
|
221
|
+
priv_file.close
|
466
222
|
|
467
|
-
|
468
|
-
def self.remove_key!(username, password, rsa)
|
469
|
-
# get all keys
|
470
|
-
keys = get_keys(username, password)
|
471
|
-
# loop through arrays checking against 'key'
|
472
|
-
keys.each do |key|
|
473
|
-
if key["key"] == rsa
|
474
|
-
return remove_key_by_id!(username, password, key["id"])
|
475
|
-
end
|
223
|
+
return [pub_rsa, priv_rsa]
|
476
224
|
end
|
477
|
-
|
478
|
-
return false # key not found
|
479
|
-
end
|
480
|
-
|
481
|
-
def self.get_keys(username, password)
|
482
|
-
server = 'api.github.com'
|
483
|
-
path = '/user/keys'
|
484
|
-
|
485
|
-
|
486
|
-
http = Net::HTTP.new(server,443)
|
487
|
-
req = Net::HTTP::Get.new(path)
|
488
|
-
http.use_ssl = true
|
489
|
-
req.basic_auth username, password
|
490
|
-
response = http.request(req)
|
491
|
-
|
492
|
-
return JSON.parse(response.body)
|
493
|
-
end
|
494
|
-
|
495
|
-
|
496
|
-
def self.install_key(username, password, title, rsa_key)
|
497
|
-
server = 'api.github.com'
|
498
|
-
path = '/user/keys'
|
499
|
-
|
500
|
-
http = Net::HTTP.new(server, 443) # 443 for ssl
|
501
|
-
http.use_ssl = true
|
502
|
-
|
503
|
-
req = Net::HTTP::Post.new(path)
|
504
|
-
req.basic_auth username, password
|
505
|
-
req.body = "{\"title\":\"#{title}\", \"key\":\"#{rsa_key}\"}"
|
506
|
-
|
507
|
-
response = http.start {|http| http.request(req) }
|
508
|
-
the_code = response.code
|
509
|
-
|
510
|
-
keys_end = get_keys(username, password).length
|
511
|
-
|
512
|
-
return true if the_code == "201"
|
513
|
-
|
514
|
-
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"
|
515
|
-
|
516
|
-
# currently.. I think it always returns "already_exists" even if successful. API bug.
|
517
|
-
puts "Something may have gone wrong. Either github fixed their API, or your key couldn't be installed." if the_code != "already_exists"
|
518
|
-
|
519
|
-
#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
|
520
|
-
puts "Server Response: #{response.body}"
|
521
|
-
return false
|
225
|
+
return [nil, nil]
|
522
226
|
end
|
523
227
|
|
524
|
-
|
525
228
|
# Cross-platform way of finding an executable in the $PATH.
|
526
229
|
# returns nil if command not present
|
527
230
|
#
|
@@ -546,7 +249,7 @@ module Gas
|
|
546
249
|
def self.delete(nickname)
|
547
250
|
return false unless user_has_ssh_keys?(nickname) # return if no keys
|
548
251
|
|
549
|
-
case user_wants_to_delete_all_ssh_data?
|
252
|
+
case Gas::Prompter.user_wants_to_delete_all_ssh_data?
|
550
253
|
when "a"
|
551
254
|
delete_associated_github_keys!(nickname)
|
552
255
|
delete_associated_local_keys!(nickname)
|
@@ -561,21 +264,24 @@ module Gas
|
|
561
264
|
end
|
562
265
|
|
563
266
|
def self.user_has_ssh_keys?(nickname)
|
564
|
-
return false if get_associated_rsa_key(nickname).nil?
|
267
|
+
return false if get_associated_rsa_key(nickname).first.nil?
|
565
268
|
return true
|
566
269
|
end
|
567
270
|
|
568
|
-
|
569
271
|
def self.delete_associated_github_keys!(nickname)
|
570
|
-
rsa = get_associated_rsa_key(nickname)
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
272
|
+
rsa = get_associated_rsa_key(nickname).first
|
273
|
+
|
274
|
+
credentials = get_nils
|
275
|
+
|
276
|
+
github_speaker = GithubSpeaker.new(nickname, credentials[:username], credentials[:password])
|
277
|
+
|
278
|
+
result = github_speaker.remove_key! rsa
|
576
279
|
puts "The key for this user was not in the specified github account's public keys section." if !result
|
577
280
|
end
|
578
|
-
|
281
|
+
|
282
|
+
# this is just for testing... it gets stubbed... otherwise, the nils are normal and allow for
|
283
|
+
# normal prompting for username and password from within the GithubSpeaker class
|
284
|
+
def self.get_nils; { :username => nil, :password => nil };end
|
579
285
|
|
580
286
|
def self.delete_associated_local_keys!(nickname)
|
581
287
|
puts "Removing associated keys from local machine..."
|
@@ -594,37 +300,6 @@ module Gas
|
|
594
300
|
File.delete("#{GAS_DIRECTORY}/#{nickname}_id_rsa")
|
595
301
|
File.delete("#{GAS_DIRECTORY}/#{nickname}_id_rsa.pub")
|
596
302
|
end
|
597
|
-
|
598
|
-
# This is another prompt function, but it returns a more complicated lexicon
|
599
|
-
#
|
600
|
-
# returns "a", "l", "g", or "n"
|
601
|
-
def self.user_wants_to_delete_all_ssh_data?
|
602
|
-
puts "Would you like to remove all ssh keys too!?! (github account keys can be removed as well!)"
|
603
|
-
puts "a: All, the local copy, and checks github too."
|
604
|
-
puts "l: Remove local keys only."
|
605
|
-
puts "g: Removes keys from github.com only."
|
606
|
-
puts "n: Don't remove this users keys."
|
607
|
-
puts "Default: l"
|
608
|
-
|
609
|
-
while true
|
610
|
-
delete_all_keys = STDIN.gets.strip
|
611
|
-
|
612
|
-
case delete_all_keys.downcase
|
613
|
-
when "a"
|
614
|
-
return "a"
|
615
|
-
when "l", ""
|
616
|
-
return "l"
|
617
|
-
when "g"
|
618
|
-
return "g"
|
619
|
-
when "n"
|
620
|
-
return "n"
|
621
|
-
else
|
622
|
-
puts "please use 'a', 'l', 'g' or 'n' for NONE."
|
623
|
-
end
|
624
|
-
end
|
625
|
-
end
|
626
|
-
|
303
|
+
|
627
304
|
end
|
628
|
-
end
|
629
|
-
|
630
|
-
|
305
|
+
end
|