duse-io/duse.rb

View on GitHub
lib/duse/cli/key_helper.rb

Summary

Maintainability
A
45 mins
Test Coverage
module Duse
  module KeyHelper
    def choose_key(options = { allow_generate: true })
      key = nil
      generate_option = 'Generate a new one'
      choose_myself_option = 'Let me choose it myself'
      choices = possible_ssh_keys
      choices << generate_option if options[:allow_generate]
      choices << choose_myself_option
      terminal.choose do |ssh_keys|
        ssh_keys.prompt = 'Which private ssh-key do you want to use?'
        ssh_keys.choices *choices do |choice|
          key = generate_key if choice == generate_option
          key = choose_private_key_file if choice == choose_myself_option
          key ||= OpenSSL::PKey::RSA.new File.read choice
        end
      end
      key
    end

    def ensure_matching_keys_for(user)
      key_pair = {
        public: user.public_key,
        private: private_key_for(user)
      }
      loop do
        break if matching_keys? key_pair
        warn 'Your private key does not match the public key, please select a new one.'
        key_pair[:private] = choose_key(allow_generate: false)
      end
      Duse::CLIConfig.new.save_private_key_for user, key_pair[:private].to_pem
    end

    def private_key_for(user)
      Duse::CLIConfig.new.private_key_for(user)
    rescue PrivateKeyMissing
      warn 'No private key found, please select one.'
      choose_key(allow_generate: false)
    rescue OpenSSL::PKey::RSAError
      warn 'The private key file does not contain a valid private key, please select a new one.'
      choose_key(allow_generate: false)
    end

    def matching_keys?(key_pair)
      public_key = key_pair[:public]
      private_key = key_pair[:private]
      public_key.params['n'] == private_key.params['n']
    end

    def possible_ssh_keys
      ssh_keys = Dir.glob File.join(ssh_dir, '*')
      ssh_keys.keep_if &method(:valid_ssh_private_key?)
    end

    def choose_private_key_file
      private_key_file = nil
      loop do
        private_key_file = terminal.ask('Private key file: ') { |q| q.default = File.join ssh_dir, 'id_rsa' }
        break if valid_ssh_private_key? private_key_file
      end
      OpenSSL::PKey::RSA.new File.read private_key_file
    end

    def valid_ssh_private_key?(private_key_file)
      rsa_key = OpenSSL::PKey::RSA.new File.read private_key_file
      rsa_key.private?
    rescue
      false
    end

    def generate_key
      OpenSSL::PKey::RSA.generate 4096
    end

    def ssh_dir
      File.join home_dir, '.ssh'
    end

    def home_dir
      File.expand_path '~'
    end
  end
end