class Mellon::Keychain
Keychain
provides simple methods for reading and storing keychain entries.
Constants
- ENTRY_MISSING
Attributes
@return [String] keychain name (without extension)
@return [String] path to keychain
Public Class Methods
@return [Keychain] default keychain
# File lib/mellon/keychain.rb, line 43 def default keychain_path = Utils.security("default-keychain")[KEYCHAIN_REGEXP, 1] new(keychain_path, ensure_exists: false) end
Find a keychain matching the given name.
@param [String] name @return [Keychain] @raise [KeyError] if no matching keychain was found
# File lib/mellon/keychain.rb, line 26 def find(name) quoted = Regexp.quote(name) regexp = Regexp.new(quoted, Regexp::IGNORECASE) keychains = list keychain = keychains.find do |keychain| keychain.name =~ regexp end if keychain.nil? raise KeyError, "Could not find keychain “#{name}” in #{keychains.map(&:name).join(", ")}" end keychain end
@return [Array<Keychain>] all available keychains
# File lib/mellon/keychain.rb, line 49 def list Utils.security("list-keychains").scan(KEYCHAIN_REGEXP).map do |(keychain_path)| new(keychain_path, ensure_exists: false) end end
Initialize a keychain on the given path.
@param [String] path @param [Boolean] ensure_exists check if keychain exists or not
# File lib/mellon/keychain.rb, line 60 def initialize(path, ensure_exists: true) @path = path @name = File.basename(path, ".keychain") command "show-keychain-info" if ensure_exists end
Find the first keychain that contains the key.
@param [String] key @return [Keychain, nil]
# File lib/mellon/keychain.rb, line 13 def search(key) output = Utils.security("find-generic-password", "-l", key) new(output[/keychain: "(.+)"/i, 1], ensure_exists: false) rescue CommandError => e raise unless e.message =~ ENTRY_MISSING nil end
Public Instance Methods
@param other @return [Boolean] true if the keychains have the same path
# File lib/mellon/keychain.rb, line 128 def ==(other) if other.is_a?(Keychain) path == other.path else super end end
@param [String] key @return [String, nil] contents of entry at key, or nil if not set
# File lib/mellon/keychain.rb, line 86 def [](key) _, data = read(key) data end
Write data to entry key, or updating existing one if it exists.
@param [String] key @param [String] data
# File lib/mellon/keychain.rb, line 95 def []=(key, data) info, _ = read(key) info ||= {} if data write(key, data, info) else delete(key, info) end end
@param other @return [Boolean] true if the keychains have the same path
# File lib/mellon/keychain.rb, line 122 def eql?(other) self == other or super end
Retrieve a value, but if it does not exist return the default value, or call the provided block, or raise an error. See Hash#fetch.
@param [String] key @param default @return [String] value for key, default, or value from block @yield if key does not exist, and block is given @raise [KeyError] if key does not exist, and no default is given
# File lib/mellon/keychain.rb, line 80 def fetch(key, *args, &block) self[key] or {}.fetch(key, *args, &block) end
@return a hash unique to keychains of the same path
# File lib/mellon/keychain.rb, line 116 def hash path.hash end
Retrieve all available keys.
@return [Array<String>]
# File lib/mellon/keychain.rb, line 109 def keys Utils.parse_dump(command "dump-keychain").map do |keychain, info| info[:label] end end
Private Instance Methods
Execute a command with the context of this keychain.
@param [Array<String>] command
# File lib/mellon/keychain.rb, line 199 def command(*command, &block) command += [path] Utils.security *command, &block end
Delete the entry matching key and options.
@param [String] key @param [Hash] options @option (see write
)
# File lib/mellon/keychain.rb, line 185 def delete(key, options = {}) info = Utils.build_info(key, options) command "delete-generic-password", "-a", info[:account_name], "-s", info[:service_name], "-l", info[:label], "-D", info[:kind], "-C", info[:type] end
Read a key from the keychain.
@param [String] key @return [Array<Hash, String>, nil] tuple of entry info, and text contents, or nil if key does not exist
# File lib/mellon/keychain.rb, line 142 def read(key) command "find-generic-password", "-g", "-l", key do |info, password_info| [Utils.parse_info(info), Utils.parse_contents(password_info)] end rescue CommandError => e raise unless e.message =~ ENTRY_MISSING nil end
Write data with given key to the keychain, or update existing key if it exists.
@note keychain entries are not unique by key, but also by the information
provided through options; two entries with same key but different account name (for example), will become two different entries when writing.
@param [String] key @param [String] data @param [Hash] options @option options [#to_s] :type (:note) one of Mellon::TYPES @option options [String] :account_name (“”) @option options [String] :service_name (key) @option options [String] :label (service_name) @raise [CommandError] if writing fails
# File lib/mellon/keychain.rb, line 166 def write(key, data, options = {}) info = Utils.build_info(key, options) command "add-generic-password", "-a", info[:account_name], "-s", info[:service_name], "-l", info[:label], "-D", info[:kind], "-C", info[:type], "-T", "", # which applications have access (none) "-U", # upsert "-w", data end