class SecretKeys::CLI::Base

Constants

MAX_SUMMARY_LENGTH

Attributes

input[R]
secret_key[R]

Public Class Methods

new(argv) click to toggle source
# File lib/secret_keys/cli.rb, line 14
def initialize(argv)
  # make sure we can only use stdin once
  @stdin_used = false
  @secrets = nil
  parse_options(argv)
end

Public Instance Methods

action_name() click to toggle source

Subclasses should return the action name for the help banner

# File lib/secret_keys/cli.rb, line 31
def action_name
  "<encrypt|decrypt|read|edit>"
end
format() click to toggle source

Return the output format.

# File lib/secret_keys/cli.rb, line 41
def format
  return @format if [:json, :yaml].include?(@format)
  secrets.input_format
end
parse_additional_options(opts) click to toggle source

Subclasses can override this method to parse additional options beyond the standard set.

# File lib/secret_keys/cli.rb, line 22
def parse_additional_options(opts)
end
run!() click to toggle source

Subclasses must implement this method to execute the logic.

# File lib/secret_keys/cli.rb, line 36
def run!
  raise NotImplementedError
end
secrets() click to toggle source

@return [SecretKeys] the secrets

# File lib/secret_keys/cli.rb, line 26
def secrets
  @secrets ||= SecretKeys.new(@input, @secret_key)
end

Protected Instance Methods

encrypted_file_contents() click to toggle source
# File lib/secret_keys/cli.rb, line 48
def encrypted_file_contents
  encrypted = secrets.encrypted_hash
  string = (format == :yaml ? YAML.dump(encrypted) : JSON.pretty_generate(encrypted))
  string << $/ unless string.end_with?($/) # ensure file ends with system dependent new line
  string
end

Private Instance Methods

access_key(parent, key, write: false) { |parent, k| ... } click to toggle source

@param parent data structure to recurse over @param key to access @yield context of key and parent @yieldparam parent the parent object @yieldparam key the last child node

# File lib/secret_keys/cli.rb, line 136
def access_key(parent, key, write: false)
  splits = key.split(".")
  last_key = splits.length - 1
  splits.each_with_index do |curr, idx|
    if parent.is_a?(Array)
      k = curr.to_i
      raise ArgumentError, "Array index must be a positive number" if curr != k.to_s || k < 0
    elsif parent.is_a?(Hash) || parent.is_a?(SecretKeys)
      k = curr
    else
      raise ArgumentError, "No such key: #{key.inspect}"
    end

    return yield(parent, k) if idx == last_key

    if parent[k].nil?
      return nil unless write
      parent[k] = {}
    end
    parent = parent[k]
  end
end
can_i_haz_stdin!() click to toggle source

Mark that you want to use stdin and raise an exception if it's already been used.

# File lib/secret_keys/cli.rb, line 126
def can_i_haz_stdin!
  raise ArgumentError, "stdin (-) cannot be specified multiple times" if @stdin_used
  @stdin_used = true
end
get_secret_key(value) click to toggle source
# File lib/secret_keys/cli.rb, line 105
def get_secret_key(value)
  if value == "-"
    can_i_haz_stdin!
    if $stdin.tty?
      $stdin.getpass("Secret key: ")
    else
      $stdin.gets.chomp
    end
  else
    value
  end
end
parse_options(argv) click to toggle source
# File lib/secret_keys/cli.rb, line 57
    def parse_options(argv)
      @secret_key = nil
      @format = nil

      OptionParser.new do |opts|
        opts.banner = "Usage: secret_keys #{action_name} [options] [--] [INFILE|-]"

        opts.separator("\nGlobal options:")

        secret_docs = split(<<~HELP)
          Encryption key used to encrypt strings in the file.
          This value can also be passed in the SECRET_KEYS_ENCRYPTION_KEY environment variable or via STDIN by specifying '-'.
        HELP
        opts.on("-s", "--secret-key=SECRET", String, *secret_docs) do |value|
          raise ArgumentError, "You have already passed in the secret key" unless @secret_key.nil?
          @secret_key = get_secret_key(value)
        end

        secret_file_docs = split(<<~HELP)
          Path to a file that contains the encryption key.
          This value can also be passed in the SECRET_KEYS_ENCRYPTION_KEY_FILE environment variable.
        HELP
        opts.on("--secret-key-file=PATH", String, *secret_file_docs) do |value|
          raise ArgumentError, "You have already passed in the secret key" unless @secret_key.nil?
          @secret_key = File.read(value).chomp
        end

        opts.on("-f", "--format FORMAT", [:json, :yaml], "Set the output format. By default this will be the same as the input format.") do |value|
          @format = value
        end

        opts.on("-h", "--help", "Prints this help") do
          puts opts.help
          exit
        end

        parse_additional_options(opts)
      end.order!(argv)

      @input = argv.shift
      if @input.nil? || @input == "-"
        can_i_haz_stdin!
        @input = $stdin
      end

      raise ArgumentError.new("Too many arguments") unless argv.empty?
    end
split(docstring, length: MAX_SUMMARY_LENGTH) click to toggle source

@return [Array] array of strings from docstring, split at length

# File lib/secret_keys/cli.rb, line 119
def split(docstring, length: MAX_SUMMARY_LENGTH)
  docstring = docstring.strip
  docstring.gsub!(/\s+/, " ")
  docstring.scan(/(.{1,#{length}})(?:\s+|\z)/).flatten
end