|
#!/usr/bin/env ruby |
|
|
|
require 'uri' |
|
require 'net/http' |
|
require 'json' |
|
|
|
require 'optparse' |
|
|
|
authorized_keys_file = File.expand_path '~/.ssh/authorized_keys' |
|
key_matcher = /(ssh-rsa (?:[A-Za-z0-9+\/]{4})*(?:[A-Za-z0-9+\/]{2}==|[A-Za-z0-9+\/]{3}=))( (GH:)?(.*))?/ |
|
|
|
options = {} |
|
|
|
# Define root level parameters |
|
global = OptionParser.new do |opts| |
|
opts.banner = 'Usage: gh_keys command [username]' |
|
end |
|
|
|
# Define subcommands |
|
subcommands = { |
|
'list' => OptionParser.new do |opts| |
|
opts.banner = 'Usage: gh_keys list' |
|
end, |
|
'add' => OptionParser.new do |opts| |
|
opts.banner = 'Usage: gh_keys add username' |
|
end, |
|
'remove' => OptionParser.new do |opts| |
|
opts.banner = 'Usage: gh_keys remove username' |
|
end |
|
} |
|
|
|
# Helper method to force print help |
|
def print_help(global_parser) |
|
ARGV.delete_if {|_| true} |
|
ARGV << '--help' |
|
global_parser.order! |
|
end |
|
|
|
# Start parsing options |
|
global.order! |
|
if ARGV.length >= 1 |
|
command = ARGV.shift |
|
|
|
if subcommands.key? command |
|
subcommands[command].order! |
|
|
|
options[:username] = ARGV.shift() if ARGV.length == 1 |
|
|
|
# Load all key information |
|
gh_keys = {} |
|
other_keys = [] |
|
File.open(authorized_keys_file, 'r') do |io| |
|
lines = io.readlines |
|
lines.each do |line| |
|
matchdata = line.match key_matcher |
|
|
|
if matchdata |
|
if matchdata[3] |
|
gh_keys[matchdata[4]] = [] unless gh_keys.key? matchdata[4] |
|
gh_keys[matchdata[4]] << matchdata[1] |
|
else |
|
other_keys << "#{matchdata[1]}#{matchdata[2]}" |
|
end |
|
end |
|
end |
|
end |
|
|
|
def write_keys file, gh_keys, other_keys |
|
File.open(file, 'w') do |io| |
|
gh_keys.each_pair do |username, keys| |
|
keys.each do |key| |
|
io.puts "#{key} GH:#{username}" |
|
end |
|
end |
|
other_keys.each do |key| |
|
io.puts key |
|
end |
|
end |
|
end |
|
|
|
case command |
|
when 'list' |
|
puts 'GitHub Keys:' |
|
puts '############' |
|
gh_keys.each_pair do |username, keys| |
|
puts "#{username}: " |
|
keys.each do |key| |
|
puts " #{key}" |
|
end |
|
end |
|
puts '' |
|
|
|
puts 'Other Keys:' |
|
puts '###########' |
|
other_keys.each do |key| |
|
puts key |
|
end |
|
puts '' |
|
when 'add' |
|
if options[:username] |
|
uri = URI("https://api.github.com/users/#{options[:username]}/keys") |
|
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http| |
|
request = Net::HTTP::Get.new uri |
|
response = http.request request |
|
|
|
if response.code == '200' |
|
gh_response = JSON.parse response.body |
|
|
|
gh_keys[options[:username]] = [] |
|
gh_response.each do |gh_key| |
|
gh_keys[options[:username]] << gh_key['key'] |
|
puts "Added key: #{gh_key['key']}" |
|
end |
|
end |
|
end |
|
|
|
write_keys authorized_keys_file, gh_keys, other_keys |
|
else |
|
puts 'Missing username' |
|
print_help subcommands['add'] |
|
end |
|
when 'remove' |
|
gh_keys[options[:username]] = [] |
|
puts "Removed keys for #{options[:username]}" |
|
write_keys authorized_keys_file, gh_keys, other_keys |
|
end |
|
else |
|
puts "Unrecognized command: #{command}" |
|
print_help global |
|
end |
|
else |
|
print_help global |
|
end |