#!/usr/bin/env ruby # -*- mode: ruby -*- # vi: set ft=ruby : require 'cryptic' require 'thor' # TODO: Add support for localized descriptions # TODO: Add support for localized alias of commands in locales that share the # English alphabet? class CrypticCLI < Thor desc 'decrypt [PRIVATE_KEY] [ENCRYPTED_FILE] [OPTIONS]', 'Decrypt a file with a private key' method_option :passphrase, aliases: %w[-p], default: nil, desc: 'The passphrase to unlock the private key with' method_option :encoding, aliases: %w[-e], default: :none, desc: 'The encoding to use, one of: [:none, :base64]' method_option :path, aliases: %w[-o], default: "cryptic_#{rand(1000..9999)}.txt", desc: 'Where to place the encrypted file' def decrypt(private_key, file) # TODO: Update error handling # * Better utilize custom exceptions # * Catch file read errors data = File.read(file) encrypted = Cryptic::EncryptedData.load(data, options[:encoding]) decrypted_str = encrypted.decrypt(private_key, options[:passphrase]) if decrypted_str.eql?('') $stderr.puts '[Error]: Unable to save the decrypted file' exit 1 else File.open(options[:path], 'w') do |file| file.write decrypted_str end end rescue Cryptic::InvalidData => e $stderr.puts "[Error]: #{e.inspect}".red exit 1 rescue Cryptic::KeyMismatch => e $stderr.puts "[Error]: #{e.inspect}".red exit 1 end desc 'encrypt [PUBLIC_KEY] [TEXT_FILE] [OPTIONS]', 'Encrypt a file with a public key' method_option :encoding, aliases: %w[-e], default: :none, desc: 'The encoding to use, one of: [:none, :base64]' method_option :path, aliases: %w[-o], default: "cryptic_#{rand(1000..9999)}.ctxt", desc: 'Where to place the encrypted file' def encrypt(public_key, file) # TODO: Update error handling; See above TODO. data = File.read(file) encrypted = Cryptic::EncryptedData.new(data, public_key) encrypted_str = encrypted.data if encrypted_str.eql?('') $stderr.puts '[Error]: Unable to save the encrypted file' exit 1 else File.open(options[:path], 'w') do |file| file.write encrypted_str end end end desc 'generate [OPTIONS]', 'Generate a private/public keypair' method_option :bits, aliases: %w[-b size], default: 2048, desc: 'The number of bits to use when generating your key' method_option :passphrase, aliases: %w[-p], default: nil, desc: 'The passphrase to generate the private key with' method_option :path, aliases: %w[-o], default: '.', desc: 'Where to place the generated keys' def generate keypair = Cryptic::Keypair.generate(options[:passphrase], options[:bits]) keypair.save(options[:path]) $stdout.puts "Generated keys saved as '#{File.expand_path(options[:path])}/cryptic_public.pem' and '#{File.expand_path(options[:path])}/cryptic_private.pem'" rescue Cryptic::KeyGenerationFailure => e $stderr.puts "[Error]: #{e.message}".red exit 1 end end CrypticCLI.start(ARGV)