#!/usr/bin/env ruby
require 'rhc-common'

#
# print help
#
def p_usage(exit_code = 255)
    rhlogin = get_var('default_rhlogin') ? "Default: #{get_var('default_rhlogin')}" : "required"
    puts <<USAGE

Usage: rhc sshkey (<command> | --help) [<args>]
Manage multiple keys for the registered rhcloud user.

List of commands
  list                           Display all the SSH keys for the user account
  add                            Add SSH key to the user account
  update                         Update SSH key for the user account
  remove                         Remove SSH key from the user account

List of arguments
  -l|--rhlogin      rhlogin      Red Hat login (RHN or OpenShift login) (#{rhlogin})
  -p|--password     password     RHLogin password (optional, will prompt)
  -i|--identifier   key-name     User-specified identifier for the key
  -k|--ssh          key-filepath SSH public key filepath 
  -d|--debug                     Print Debug info
  -h|--help                      Show Usage info
  --config          path         Path of alternate config file
  --timeout         #            Timeout, in seconds, for the session

USAGE
exit exit_code
end


def validate_args(val_id=true)
  # If provided a config path, check it
  check_cpath($opt)
  
  # Pull in configs from files
  $libra_server = get_var('libra_server')
  debug = get_var('debug') == 'false' ? nil : get_var('debug')
  
  $opt['rhlogin'] = get_var('default_rhlogin') unless $opt['rhlogin']
  p_usage if !RHC::check_rhlogin($opt['rhlogin'])
  
  debug = $opt["debug"] ? true : false
  RHC::debug(debug)
  
  p_usage if val_id && !RHC::check_key($opt['identifier'])
  
  RHC::timeout($opt["timeout"], get_var('timeout'))
  RHC::connect_timeout($opt["timeout"], get_var('timeout'))
  $password = $opt['password'] ? $opt['password'] : RHC::get_password
end

def add_or_update_key(command)
  validate_args(true)
  
  # Read user public ssh key
  if $opt['ssh']
    if File.readable?($opt['ssh'])
      begin
        ssh_keyfile_contents = File.open($opt['ssh']).gets.chomp.split(' ')
        ssh_key = ssh_keyfile_contents[1]
        ssh_key_type = ssh_keyfile_contents[0]
      rescue Exception => e
        puts "Invalid public keyfile format! Please specify a valid user public keyfile."
        exit 1
      end
    else
      puts "Unable to read user public keyfile #{$opt['ssh']}"
      exit 1
    end
  else # create key
    key_name = $opt['identifier']
    puts "Generating ssh key pair for user '#{key_name}' in the dir '#{Dir.pwd}/'"
    # Use system for interaction
    system("ssh-keygen -t rsa -f '#{key_name}'")
    ssh_pub_key_file = Dir.pwd + '/' + key_name + '.pub'
    ssh_keyfile_contents = File.open(ssh_pub_key_file).gets.chomp.split(' ')
    ssh_key = ssh_keyfile_contents[1]
    ssh_key_type = ssh_keyfile_contents[0]
  end

  data = {}
  data[:rhlogin] = $opt['rhlogin']
  data[:key_name] = $opt['identifier']
  data[:ssh] = ssh_key
  data[:action] = 'add-key'
  data[:key_type] = ssh_key_type

  if command == 'add'
    data[:action] = 'add-key'
  elsif command == 'update'
    data[:action] = 'update-key'
  end

  url = URI.parse("https://#{$libra_server}/broker/ssh_keys")
  handle_key_mgmt_response(url, data, $password)
end

def remove_key
  validate_args(true)

  data = {}
  data[:rhlogin] = $opt['rhlogin']
  data[:key_name] = $opt['identifier']
  data[:action] = 'remove-key'

  url = URI.parse("https://#{$libra_server}/broker/ssh_keys")
  handle_key_mgmt_response(url, data, $password)
end

def show_key_list
  validate_args(false)
  
  ssh_keys = RHC::get_ssh_keys($libra_server, $opt['rhlogin'], $password, @http)
  additional_ssh_keys = ssh_keys['keys']
  
  puts ""
  puts "SSH keys"
  puts "========"

  # first list the primary key
  puts "Name: default"
  puts "Type: #{ssh_keys['ssh_type']}"
  puts " Key: #{ssh_keys['ssh_key']}"
  puts ""
    
  # now list the additional keys
  if additional_ssh_keys && additional_ssh_keys.kind_of?(Hash)
    additional_ssh_keys.each do |name, keyval|
      puts "Name: #{name}"
      puts "Type: #{keyval['type']}"
      puts " Key: #{keyval['key']}"
      puts ""
    end
  end
end

def handle_key_mgmt_response(url, data, password)
  RHC::print_post_data(data)
  json_data = RHC::generate_json(data)
  
  response = RHC::http_post(@http, url, json_data, password)
  
  if response.code == '200'
    begin
      json_resp = JSON.parse(response.body)
      RHC::update_server_api_v(json_resp)
      RHC::print_response_success(json_resp)
      puts "Success"
      exit 0
    rescue JSON::ParserError
      RHC::print_response_err(response)
    end
  else
    RHC::print_response_err(response)
  end
  puts "Failure"
  exit 1
end


begin
  argv_c = ARGV.clone

  if ARGV[0] =~ /^(add|update)$/
    ARGV.shift
    opts = GetoptLong.new(
        ["--debug", "-d", GetoptLong::NO_ARGUMENT],
        ["--help", "-h", GetoptLong::NO_ARGUMENT],
        ["--rhlogin", "-l", GetoptLong::REQUIRED_ARGUMENT],
        ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
        ["--identifier", "-i", GetoptLong::REQUIRED_ARGUMENT],
        ["--ssh", "-k", GetoptLong::REQUIRED_ARGUMENT],
        ["--config", GetoptLong::REQUIRED_ARGUMENT],
        ["--timeout", GetoptLong::REQUIRED_ARGUMENT]
    )
  elsif ARGV[0] =~ /^remove$/
    ARGV.shift
    opts = GetoptLong.new(
        ["--debug", "-d", GetoptLong::NO_ARGUMENT],
        ["--help",  "-h", GetoptLong::NO_ARGUMENT],
        ["--rhlogin", "-l", GetoptLong::REQUIRED_ARGUMENT],
        ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
        ["--identifier", "-i", GetoptLong::REQUIRED_ARGUMENT],
        ["--config", GetoptLong::REQUIRED_ARGUMENT],
        ["--timeout", GetoptLong::REQUIRED_ARGUMENT]
    )
  elsif ARGV[0] =~ /^list$/
    ARGV.shift
    opts = GetoptLong.new(
        ["--debug", "-d", GetoptLong::NO_ARGUMENT],
        ["--help",  "-h", GetoptLong::NO_ARGUMENT],
        ["--rhlogin", "-l", GetoptLong::REQUIRED_ARGUMENT],
        ["--password", "-p", GetoptLong::REQUIRED_ARGUMENT],
        ["--config", GetoptLong::REQUIRED_ARGUMENT],
        ["--timeout", GetoptLong::REQUIRED_ARGUMENT]
    )
  else
    opts = GetoptLong.new(
      ["--help",  "-h", GetoptLong::NO_ARGUMENT]
    )
    unless ARGV[0] =~ /^(help|-h|--help)$/
      puts "Missing or invalid command!"
      # just exit at this point
      # printing the usage description will be handled in the rescue
      exit 255
    end
  end

  $opt = {}
  opts.each do |o, a|
    $opt[o[2..-1]] = a.to_s
  end

rescue Exception => e
  p_usage
end

p_usage 0 if $opt["help"]

case argv_c[0]
when "add", "update"
  add_or_update_key(argv_c[0])
when "remove"
  remove_key
when "list", nil
  show_key_list
when "-h", "--help", "help", nil
  p_usage 0
else
  puts "Invalid command!"
  p_usage
end

exit 0
