Class: Mellon::Keychain

Inherits:
Object
  • Object
show all
Defined in:
lib/mellon/keychain.rb

Overview

Keychain provides simple methods for reading and storing keychain entries.

Constant Summary collapse

ENTRY_MISSING =
/SecKeychainSearchCopyNext/.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(path, ensure_exists: true) ⇒ Keychain

Initialize a keychain on the given path.

Parameters:

  • path (String)
  • ensure_exists (Boolean) (defaults to: true)

    check if keychain exists or not



60
61
62
63
64
# 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

Instance Attribute Details

#nameString (readonly)

Returns keychain name (without extension).

Returns:

  • (String)

    keychain name (without extension)



70
71
72
# File 'lib/mellon/keychain.rb', line 70

def name
  @name
end

#pathString (readonly)

Returns path to keychain.

Returns:

  • (String)

    path to keychain



67
68
69
# File 'lib/mellon/keychain.rb', line 67

def path
  @path
end

Class Method Details

.defaultKeychain

Returns default keychain.

Returns:



43
44
45
46
# 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(name) ⇒ Keychain

Find a keychain matching the given name.

Parameters:

  • name (String)

Returns:

Raises:

  • (KeyError)

    if no matching keychain was found



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 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

.listArray<Keychain>

Returns all available keychains.

Returns:

  • (Array<Keychain>)

    all available keychains



49
50
51
52
53
# 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

.search(key) ⇒ Keychain?

Find the first keychain that contains the key.

Parameters:

  • key (String)

Returns:



13
14
15
16
17
18
19
# 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

Instance Method Details

#==(other) ⇒ Boolean

Returns true if the keychains have the same path.

Parameters:

  • other

Returns:

  • (Boolean)

    true if the keychains have the same path



128
129
130
131
132
133
134
# File 'lib/mellon/keychain.rb', line 128

def ==(other)
  if other.is_a?(Keychain)
    path == other.path
  else
    super
  end
end

#[](key) ⇒ String?

Returns contents of entry at key, or nil if not set.

Parameters:

  • key (String)

Returns:

  • (String, nil)

    contents of entry at key, or nil if not set



86
87
88
89
# File 'lib/mellon/keychain.rb', line 86

def [](key)
  _, data = read(key)
  data
end

#[]=(key, data) ⇒ Object

Write data to entry key, or updating existing one if it exists.

Parameters:

  • key (String)
  • data (String)


95
96
97
98
99
100
101
102
103
104
# 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

#eql?(other) ⇒ Boolean

Returns true if the keychains have the same path.

Parameters:

  • other

Returns:

  • (Boolean)

    true if the keychains have the same path



122
123
124
# File 'lib/mellon/keychain.rb', line 122

def eql?(other)
  self == other or super
end

#fetch(key, *args) { ... } ⇒ String

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.

Parameters:

  • key (String)
  • default

Yields:

  • if key does not exist, and block is given

Returns:

  • (String)

    value for key, default, or value from block

Raises:

  • (KeyError)

    if key does not exist, and no default is given



80
81
82
# File 'lib/mellon/keychain.rb', line 80

def fetch(key, *args, &block)
  self[key] or {}.fetch(key, *args, &block)
end

#hashObject

Returns a hash unique to keychains of the same path.

Returns:

  • a hash unique to keychains of the same path



116
117
118
# File 'lib/mellon/keychain.rb', line 116

def hash
  path.hash
end

#keysArray<String>

Retrieve all available keys.

Returns:

  • (Array<String>)


109
110
111
112
113
# File 'lib/mellon/keychain.rb', line 109

def keys
  Utils.parse_dump(command "dump-keychain").map do |keychain, info|
    info[:label]
  end
end