class Muchkeys::ApplicationClient

Attributes

client[RW]
config[RW]
key_validator[RW]
secret_adapter[RW]

Public Class Methods

new(config = Muchkeys.config) click to toggle source
# File lib/muchkeys/application_client.rb, line 14
def initialize(config = Muchkeys.config)
  @config = config
  @secret_adapter = Muchkeys::Secret.new(self)
  @key_validator = Muchkeys::KeyValidator.new(self)
  @client = Muchkeys::ConsulClient.new(self)
end

Public Instance Methods

all(key_name) click to toggle source
# File lib/muchkeys/application_client.rb, line 60
def all(key_name)
  search_paths(key_name).map { |path| fetch_key(path) }.compact
end
allow_unsafe_operation() { || ... } click to toggle source
# File lib/muchkeys/application_client.rb, line 21
def allow_unsafe_operation
  client.unsafe = true
  yield
ensure
  client.unsafe = false
end
delete_key(key) click to toggle source
# File lib/muchkeys/application_client.rb, line 48
def delete_key(key)
  client.delete(key)
end
each_path() { |path| ... } click to toggle source
# File lib/muchkeys/application_client.rb, line 85
def each_path
  known_keys.each do |key|
    search_paths(key).each do |path|
      yield path if fetch_key(path)
    end
  end
end
fetch_key(key_name, public_key: nil, private_key: nil) click to toggle source
# File lib/muchkeys/application_client.rb, line 68
def fetch_key(key_name, public_key: nil, private_key: nil)
  if is_secret?(key_name)
    fetch_secret_key(key_name, public_key, private_key)
  else
    fetch_plain_key(key_name)
  end
end
first(key_name) click to toggle source
# File lib/muchkeys/application_client.rb, line 52
def first(key_name)
  # http://stackoverflow.com/questions/17853912/ruby-enumerables-is-there-a-detect-for-results-of-block-evaluation
  # weirdly, this seems to be the most straightforward method of doing this
  # without a monkey patch, as there is neither a core method that returns
  # the first non-nil result of evaluating the block, or a lazy compact
  search_paths(key_name).detect { |path| v = fetch_key(path) and break v }
end
known_keys() click to toggle source
# File lib/muchkeys/application_client.rb, line 76
def known_keys
  @known_keys ||= application_search_paths
    .map { |path| client.get(path, recursive: true) }
    .compact
    .each_with_object([]) { |response, keys| keys << parse_recurse_response(response) }
    .flatten
    .uniq
end
search_paths(key_name = nil) click to toggle source
# File lib/muchkeys/application_client.rb, line 64
def search_paths(key_name = nil)
  application_search_paths.map { |p| [p, key_name].join('/') }
end
set_app_key(key, value, type: nil, **options) click to toggle source
# File lib/muchkeys/application_client.rb, line 28
def set_app_key(key, value, type: nil, **options)
  set_key(key, value, scope: :application, type: type, **options)
end
set_key(key, value, scope: nil, type: nil, **options) click to toggle source
# File lib/muchkeys/application_client.rb, line 36
def set_key(key, value, scope: nil, type: nil, **options)
  if scope && type
    key = construct_key_path(key, scope, type) || key
  end

  if type == :secret
    value = secret_adapter.encrypt_string(value.chomp, config.public_key).to_s
  end

  client.put(value, key, **options)
end
set_shared_key(key, value, type: nil, **options) click to toggle source
# File lib/muchkeys/application_client.rb, line 32
def set_shared_key(key, value, type: nil, **options)
  set_key(key, value, scope: :shared, type: type, **options)
end
verify_keys(*required_keys) click to toggle source
# File lib/muchkeys/application_client.rb, line 93
def verify_keys(*required_keys)
  if (required_keys - known_keys).any?
    # if there are any required keys (in the .env file) that are not known
    # about by the app's consul space, raise an error
    raise Muchkeys::KeyNotSet, "Consul isn't set with any keys for #{required_keys - known_keys}."
  end
end

Private Instance Methods

application_search_paths() click to toggle source
# File lib/muchkeys/application_client.rb, line 103
def application_search_paths
  @application_search_paths ||= config.search_paths.collect { |path|
    path % { application_name: config.application_name }
  }
end
construct_key_path(key, scope, type) click to toggle source
# File lib/muchkeys/application_client.rb, line 109
def construct_key_path(key, scope, type)
  found_paths = application_search_paths.select { |path|
    case
    when scope == :application && type == :secret
      path.include?(application_name) && is_secret?(path)
    when scope == :application && type == :config
      path.include?(application_name) && !is_secret?(path)
    when scope == :shared && type == :secret
      !path.include?(application_name) && is_secret?(path)
    when scope == :shared && type == :config
      !path.include?(application_name) && !is_secret?(path)
    else
      false
    end
  }

  raise AmbigousPath, "This key could go in multiple folders, please provide full path" if found_paths.many?

  [found_paths.first, key].join("/")
end
fetch_plain_key(key_name) click to toggle source
# File lib/muchkeys/application_client.rb, line 136
def fetch_plain_key(key_name)
  client.get(key_name).presence
end
fetch_secret_key(key_name, public_key=nil, private_key=nil) click to toggle source
# File lib/muchkeys/application_client.rb, line 140
def fetch_secret_key(key_name, public_key=nil, private_key=nil)
  result = fetch_plain_key(key_name)

  # Don't try to decrypt if the value is nil
  return nil if result.blank?

  public_pem  = public_key || certfile_name(key_name)
  private_pem = private_key || certfile_name(key_name)

  decrypt_string(result, public_pem, private_pem)
end
parse_recurse_response(response) click to toggle source
# File lib/muchkeys/application_client.rb, line 130
def parse_recurse_response(response)
  JSON.parse(response)
    .collect { |r| r['Key'].rpartition("/").last }
    .reject(&:empty?)
end