module Pwss::CommandSemantics

what we are supposed to do with each command

Constants

DEFAULT_BASENAME

the default filename YOU SHOULDN'T BE USING THESE CONTANSTS. USE `default_filename` INSTEAD

DEFAULT_FILENAME
MAN

TODO: make the list of entries read from code

VERSION

Public Class Methods

add_entry(opts, argv) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 196
def self.add_entry opts, argv
  waiting  = opts[:wait]
  type     = opts[:type] || "entry"
  strategy = opts[:ask] ? "ask" : (opts[:method] || "random")
  length   = opts[:length]

  safe = use_safe opts[:filename]

  # the title can be specified in the argument
  arguments = Hash.new
  arguments["title"] = argv.join(" ") if argv != []
  arguments[:strategy] = strategy
  arguments[:length] = length

  new_entry = eval("Pwss::" + type.capitalize).new
  new_entry.ask arguments

  puts "Adding entry '#{new_entry.entry["title"]}' of type '#{type}' to #{safe.filename}"
  safe.add new_entry.entry
  safe.save
  puts "Entry added"
  
  # make password available in the clipboard, if there is a password to make available
  if new_entry.entry["password"] 
    Pwss::Password.to_clipboard "password", new_entry.entry["password"], waiting
  end
end
all_safes() click to toggle source

return all the default safes we look for

# File lib/pwss/cli/command_semantics.rb, line 100
def self.all_safes
  [".enc", ".gpg", ""].map { |ext| DEFAULT_BASENAME + ext }
end
ambiguous_default() click to toggle source

return true if the default basename appears with different extensions.

for instance: if the DEFAULT_BASENAME appears both with .gpg and .enc (or plain and encrypted).

This is potentially a problem, since all operations are performed on a different file from the one the user believes it is operating on.

# File lib/pwss/cli/command_semantics.rb, line 90
def self.ambiguous_default
  [".enc", ".gpg", ""].map { |ext| File.exist?(DEFAULT_BASENAME + ext) }.count(true) > 1
end
console(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 317
def self.console opts, argv = []
  all_commands = Pwss::CommandSyntax.commands
  all_commands.delete(:console)
  open opts, argv # open and cache the file
  
  i = 0
  while true
    string = Readline.readline('pwss:%03d> ' % i, true)
    string.gsub!(/^pwss /, "") # as a courtesy, remove any leading pwss string
    if string == "exit" or string == "quit" or string == "." then
      exit 0
    end
    reps all_commands, string.split(' ')
    i = i + 1
  end
end
decrypt(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 297
def self.decrypt opts, argv = []
  # filename: passed from options, cached one or, in order, .gpg, .enc, plain (but plain will fail)
  filename = opts[:filename] || (@@cache ? @@cache.filename : default_filename)

  if not File.exist?(filename)
    raise "Error: file #{filename} does not exist."
  end

  if not Pwss::FileOps.encrypted? filename
    raise "Error: #{filename} does not end with '.gpg' or '.enc' (and I assume it to be in plain text)"
  end

  safe = use_safe filename
  safe.toggle_encryption
  safe.save
  puts "A plain text copy now lives in #{safe.filename}"
  puts "You might want to check everything is ok and delete the plain file: #{filename}"
  puts "If you do nothing, the next pwss command will run on #{default_filename}"
end
default(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 340
def self.default opts, argv = []
  if @@cache
    @@cache.filename
  elsif self.no_default
    puts "No default password file found."
    puts "Use -f if you have a password file stored somewhere else."
    puts "pwss init will create #{default_filename}."
  elsif self.ambiguous_default
    puts "Operating on #{default_filename}."
    puts "Warning: #{existing_safes.join(", ")} exist."
  else
    puts "Operating on #{default_filename}"
  end
end
default_filename() click to toggle source

return the default filename

this is obtained by looking for plain text or encryped versions of the DEFAULT_BASENAME, with the following priority: .enc, .gpg, plain text.

If no file is found (like it might be the case when running the init command), use GPG

# File lib/pwss/cli/command_semantics.rb, line 73
def self.default_filename
  [".enc", ".gpg", ""].each do |ext|
    filename = DEFAULT_BASENAME + ext
    return filename if File.exist?(filename)
  end
  return DEFAULT_FILENAME
end
describe(opts = nil, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 137
def self.describe  opts = nil, argv = []
  if opts[:type]
    types = [("Pwss::" + opts[:type].capitalize).to_sym]
  else
    types = [Pwss::Entry] + ObjectSpace.each_object(Class).select { |klass| klass < Pwss::Entry }
  end
  types.each do |type|
    t = eval("#{type}.new")
    puts "#{type.to_s.gsub("Pwss::", "").downcase}:\n  #{t.fields.join(", ")}\n\n"
  end
end
destroy(opts, argv) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 255
def self.destroy opts, argv
  safe = use_safe opts[:filename]

  string = argv.join(" ")
  entries_with_idx = safe.match string
  id = Pwss::Safe.choose_entry entries_with_idx, true    
  if id != -1 then
    safe.destroy id
    safe.save
  end
end
encrypt(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 267
def self.encrypt opts, argv = []
  # filename: use the one passed from the cli or the cached one or .pwss.yaml DEFAULT_*BASE*NAME
  filename = opts[:filename] || (@@cache ? @@cache.filename : DEFAULT_BASENAME)
  encryption = opts[:symmetric] ? :enc : :gpg

  if not File.exist?(filename)
    raise "Error: file #{filename} does not exist."
  end

  if Pwss::FileOps.encrypted? filename
    raise "Error: #{filename} ends with '.gpg' or '.enc' (and I assume these files to be encrypted)"
  end

  if encryption == :enc then
    password = Pwss::Password.ask_password_twice
    if password == "" then
      raise "Error: Please specify a non-empty password."
    end  
  else
    password = nil # it will be asked by GPG
  end
  
  safe = use_safe filename
  safe.toggle_encryption :password => password, :schema => encryption
  safe.save
  puts "An encrypted copy now lives in #{safe.filename}"
  puts "You might want to check everything is ok and delete the plain file: #{filename}"
  puts "If you do nothing, the next pwss command will run on #{default_filename}"
end
existing_safes() click to toggle source

return the existing safes

# File lib/pwss/cli/command_semantics.rb, line 105
def self.existing_safes
  [".enc", ".gpg", ""].map { |ext| DEFAULT_BASENAME + ext }.select { |x| File.exist?(x) }
end
get(opts, argv) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 170
def self.get opts, argv
  waiting = opts[:wait]
  stdout_opt = opts[:stdout]
  field_name = opts[:field] || "password"
  id = opts[:id]

  safe = use_safe opts[:filename]
  show = opts[:show]

  if not id 
    string = argv.join(" ")
    entries_with_idx = safe.match string
    id = Pwss::Safe.choose_entry entries_with_idx
  end

  if id != -1 and safe.get(id) then
    field_value = safe.get_field id, field_name
    if stdout_opt then
      printf("%s", field_value)
    else
      puts (show ? safe.get(id).to_yaml : safe.get_pruned(id).to_yaml )
      Pwss::Password.to_clipboard(field_name, field_value, waiting)
    end
  end
end
help(opts = nil, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 121
def self.help opts = nil, argv = []
  all_commands = Pwss::CommandSyntax.commands
  
  if argv != []
    argv.map { |x| puts all_commands[x.to_sym][0] }
  else
    puts "pwss command [options] [args]"
    puts ""
    puts "Available commands:"
    puts ""
    all_commands.keys.each do |key|
      puts "  " + all_commands[key][0].banner
    end
  end
end
init(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 149
def self.init opts, argv = []
  filename = opts[:filename] || @@cache.filename || DEFAULT_FILENAME

  if File.exist?(filename)
    raise "Error: file #{filename} already exists."
  end

  safe = Pwss::Safe.new filename
  safe.save
  
  puts "New safe created in #{filename}"
end
list(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 162
def self.list opts, argv = []
  safe = use_safe opts[:filename]
  clean = opts[:clean]

  cleaned_entries = safe.prune(["created_at", "updated_at"]).map { |x| Pwss::Fields.to_clean_hash x }
  puts cleaned_entries.to_yaml
end
man(opts = nil, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 117
def self.man opts = nil, argv = []
  puts MAN
end
no_default() click to toggle source

return true if none of the default files exist

# File lib/pwss/cli/command_semantics.rb, line 95
def self.no_default
  [".enc", ".gpg", ""].map { |ext| File.exist?(DEFAULT_BASENAME + ext) }.count(true) == 0
end
open(opts, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 334
def self.open opts, argv = []
  filename = opts[:filename] || default_filename
  @@cache = load_safe filename
  puts "Loaded #{filename}"
end
reps(all_commands, argv) click to toggle source

read-eval-print step

# File lib/pwss/cli/command_semantics.rb, line 356
def self.reps all_commands, argv
  if argv == []
    Pwss::CommandSemantics.help
    exit 0
  else
    command = argv[0]
    syntax_and_semantics = all_commands[command.to_sym]

    if syntax_and_semantics
      opts = syntax_and_semantics[0]
      function = syntax_and_semantics[1]
      
      begin
        parser = Slop::Parser.new(opts)
        result = parser.parse(argv[1..-1])
        options = result.to_hash
        arguments = result.arguments

        eval "Pwss::CommandSemantics::#{function}(options, arguments)"
      rescue Slop::Error => e
        puts "pwss: #{e}"
      rescue Exception => e
        puts e
      end
    else
      puts "pwss: '#{command}' is not a pwss command. See 'pwss help'"
    end
  end
end
update(opts, argv) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 224
def self.update opts, argv
  field    = (opts.to_hash[:password] or opts.to_hash[:method] or opts.to_hash[:ask]) ? "password" : opts.to_hash[:field]
  strategy = opts.to_hash[:ask] ? "ask" : (opts.to_hash[:method] || "random")
  length   = opts.to_hash[:length]
  waiting  = opts.to_hash[:wait]
  string   = argv.join(" ") # the entry we are looking for

  if not field then
    raise "Error: please specify a field to update (use --field, -p, or --ask)"
  end

  safe = use_safe opts[:filename]

  entries_with_idx = safe.match string
  id = Pwss::Safe.choose_entry entries_with_idx, true
  if id != -1 then
    old_value = safe.get_field id, field
    new_value = Pwss::Fields.ask field, { strategy: strategy, length: length }
    printf "Updating #{field} field of '#{safe.entries[id]["title"]}' in #{safe.filename} ..."
    safe.update id, field, new_value
    safe.save
    puts "... done"
    puts "The old value of #{field} is: #{old_value}"
    
    # make the field available in the clipboard, just in case it is needed
    if field == "password"
      Pwss::Password.to_clipboard "password", new_value, waiting
    end
  end
end
version(opts = nil, argv = []) click to toggle source
# File lib/pwss/cli/command_semantics.rb, line 113
def self.version opts = nil, argv = []
  puts "pwss version #{VERSION}"
end

Private Class Methods

load_safe(filename) click to toggle source

load a password safe

# File lib/pwss/cli/command_semantics.rb, line 400
def self.load_safe filename
  if File.exist?(filename)
    safe = Pwss::Safe.new filename
    safe.load
    safe
  else
    raise "Error: file #{filename} does not exist."
  end
end
use_safe(filename) click to toggle source

use a specific filename (if specified), try @@cache if -f is not specified, or the default filename

# File lib/pwss/cli/command_semantics.rb, line 389
def self.use_safe filename
  if filename then
    load_safe filename
  elsif @@cache then
    @@cache
  else
    load_safe default_filename
  end
end