#!/usr/bin/env ruby # CLI client for Trocla. # require 'rubygems' require 'trocla' require 'optparse' require 'yaml' options = { :config_file => nil, :ask_password => true, :trace => false } OptionParser.new do |opts| opts.on('--version', '-V', 'Version information') do puts Trocla::VERSION::STRING exit end opts.on('--config CONFIG', '-c', 'Configuration file') do |v| if File.exist?(v) options[:config_file] = v else STDERR.puts "Cannot find config file: #{v}" exit 1 end end opts.on('--trace', 'Show stack trace on failure') do options[:trace] = true end opts.on('--no-random', 'Do not generate a random password if there is no plain text password available') do options['random'] = false end opts.on('--no-format', 'Do not format a password when setting it using `set`') do options['no_format'] = true end opts.on('--length LENGTH', 'Length for a randomly created password') do |v| options['length'] = v.to_i end opts.on('--password [PASSWORD]', '-p', 'Provide password at command line or STDIN') do |pass| options[:ask_password] = false options[:password] = pass end end.parse! def create(options) [Trocla.new(options.delete(:config_file)).password( options.delete(:trocla_key), options.delete(:trocla_format), options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {}) ), 0] end def get(options) res = Trocla.new(options.delete(:config_file)).get_password( options.delete(:trocla_key), options.delete(:trocla_format), options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {}) ) [res, res.nil? ? 1 : 0] end def set(options) if options.delete(:ask_password) require 'highline/import' password = ask('Enter your password: ') { |q| q.echo = 'x' }.to_s pwd2 = ask('Repeat password: ') { |q| q.echo = 'x' }.to_s unless password == pwd2 STDERR.puts 'Passwords did not match, exiting!' return [nil, 1] end else password = options.delete(:password) || STDIN.read.chomp end format = options.delete(:trocla_format) no_format = options.delete('no_format') trocla = Trocla.new(options.delete(:config_file)) value = if no_format password else trocla.formats(format).format(password, (YAML.safe_load(options.delete(:other_options).shift.to_s) || {})) end trocla.set_password( options.delete(:trocla_key), format, value ) ['', 0] end def reset(options) [Trocla.new(options.delete(:config_file)).reset_password( options.delete(:trocla_key), options.delete(:trocla_format), options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {}) ), 0] end def delete(options) res = Trocla.new(options.delete(:config_file)).delete_password( options.delete(:trocla_key), options.delete(:trocla_format) ) [res, res.nil? ? 1 : 0] end def formats(options) key = (options.delete(:trocla_key) || '') if key.empty? "Available formats: #{Trocla::Formats.all.join(', ')}" else res = Trocla.new(options.delete(:config_file)).available_format( key, options.merge(YAML.safe_load(options.delete(:other_options).shift.to_s) || {}) ) [res.nil? ? res : res.join(', '), res.nil? ? 1 : 0] end end def search(options) res = Trocla.new(options.delete(:config_file)).search_key( options.delete(:trocla_key) ) [res.nil? ? res : res.join("\n"), res.nil? ? 1 : 0] end def check_format(format_name) if format_name.nil? STDERR.puts 'Missing format, exiting...' exit 1 elsif !Trocla::Formats.available?(format_name) STDERR.puts "Error: The format #{format_name} is not available" exit 1 end end actions = ['create', 'get', 'set', 'reset', 'delete', 'formats', 'search'] if (action=ARGV.shift) && actions.include?(action) options[:trocla_key] = ARGV.shift options[:trocla_format] = ARGV.shift options[:other_options] = ARGV check_format(options[:trocla_format]) unless ['delete','formats','search'].include?(action) begin result, excode = send(action, options) if result puts result.is_a?(String) ? result : result.inspect end rescue Exception => e unless e.message == 'exit' STDERR.puts "Action failed with the following message: #{e.message}" STDERR.puts '(See full trace by running task with --trace)' end raise e if options[:trace] exit 1 end exit excode.nil? ? 0 : excode else STDERR.puts "Please supply one of the following actions: #{actions.join(', ')}" STDERR.puts "Use #{$0} --help to get a list of options for these actions" exit 1 end