Class: Keychain::Item
- Inherits:
-
Object
- Object
- Keychain::Item
- Defined in:
- lib/mr_keychain.rb
Overview
Methods only need a user's explicit authorization if they want the password data, metadata does not need permission. In these cases, the OS should present an alert asking to allow, deny, or always allow the script to access. You need to be careful when using 'always allow' if you are running this code from interactive ruby or the regular interpreter because you could accidentally allow any future script to not require permission to access any password in the keychain.
Represents an entry in the login keychain.
The big assumption that this class makes is that you only ever want to work with a single keychain item; whether it be searching for metadata, getting passwords, or adding a new entry.
In order to be secure, this class will NEVER cache a password; any time that you change a password, it will be written to the keychain immeadiately.
Instance Attribute Summary collapse
Instance Method Summary collapse
-
#[](key) ⇒ Object
Direct access to the attributes hash of the keychain item.
-
#[]=(key, value) ⇒ Object
Direct access to the attributes hash of the keychain item.
-
#exists? ⇒ true, false
Returns true if there are any item matching the given attributes.
-
#initialize(attributes = {}) ⇒ Item
constructor
You should initialize objects of this class with the attributes relevant to the item you wish to work with, but you can add or remove attributes via accessors as well.
-
#metadata ⇒ Hash
Get all the metadata about a keychain item, they will be keyed according Apple's documentation.
-
#metadata! ⇒ Hash
Update attributes to include all the metadata from the keychain.
-
#password ⇒ String
Returns the password for the first match found, raises an error if no keychain item is found.
-
#password=(new_password) ⇒ String
Updates the password associated with the keychain item.
-
#update!(new_attributes) ⇒ Hash
Updates attributes of the item in the keychain.
Constructor Details
#initialize(attributes = {}) ⇒ Item
You should initialize objects of this class with the attributes relevant to the item you wish to work with, but you can add or remove attributes via accessors as well.
41 42 43 44 |
# File 'lib/mr_keychain.rb', line 41 def initialize attributes = {} @attributes = { KSecClass => KSecClassInternetPassword } @attributes.merge! attributes end |
Instance Attribute Details
#attributes ⇒ Hash
25 26 27 |
# File 'lib/mr_keychain.rb', line 25 def attributes @attributes end |
Instance Method Details
#[](key) ⇒ Object
Direct access to the attributes hash of the keychain item.
28 29 30 |
# File 'lib/mr_keychain.rb', line 28 def [] key @attributes[key] end |
#[]=(key, value) ⇒ Object
Direct access to the attributes hash of the keychain item.
33 34 35 |
# File 'lib/mr_keychain.rb', line 33 def []= key, value @attributes[key] = value end |
#exists? ⇒ true, false
This method asks only for the metadata and doesn't need authorization
Returns true if there are any item matching the given attributes.
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/mr_keychain.rb', line 50 def exists? result = Pointer.new :id search = @attributes.merge( KSecMatchLimit => KSecMatchLimitOne, KSecReturnAttributes => true ) case (error_code = SecItemCopyMatching(search, result)) when ErrSecSuccess then true when ErrSecItemNotFound then false else = SecCopyErrorMessageString(error_code, nil) raise KeychainException, "Error checking keychain item existence: #{message}" end end |
#metadata ⇒ Hash
Get all the metadata about a keychain item, they will be keyed according Apple's documentation.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
# File 'lib/mr_keychain.rb', line 141 def result = Pointer.new :id search = @attributes.merge( KSecMatchLimit => KSecMatchLimitOne, KSecReturnAttributes => true ) case (error_code = SecItemCopyMatching(search, result)) when ErrSecSuccess then result[0] else = SecCopyErrorMessageString(error_code, nil) raise KeychainException, "Error getting metadata: #{message}" end end |
#metadata! ⇒ Hash
Update attributes to include all the metadata from the keychain.
160 161 162 |
# File 'lib/mr_keychain.rb', line 160 def @attributes = end |
#password ⇒ String
We ask for an NSData object here in order to get the password.
Returns the password for the first match found, raises an error if no keychain item is found.
Blank passwords should come back as an empty string, but that hasn't been tested.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/mr_keychain.rb', line 76 def password result = Pointer.new :id search = @attributes.merge( KSecMatchLimit => KSecMatchLimitOne, KSecReturnData => true ) case (error_code = SecItemCopyMatching(search, result)) when ErrSecSuccess then result[0].to_str else = SecCopyErrorMessageString(error_code, nil) raise KeychainException, "Error getting password: #{message}" end end |
#password=(new_password) ⇒ String
Updates the password associated with the keychain item. If the item does not exist in the keychain it will be added first.
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/mr_keychain.rb', line 98 def password= new_password password_data = { KSecValueData => new_password.to_data } if exists? error_code = SecItemUpdate( @attributes, password_data ) else error_code = SecItemAdd( @attributes.merge(password_data), nil ) end case error_code when ErrSecSuccess then password else = SecCopyErrorMessageString(error_code, nil) raise KeychainException, "Error updating password: #{message}" end end |
#update!(new_attributes) ⇒ Hash
This method does not really fit with the rest of the API.
This method does not need authorization unless you are updating the password.
Updates attributes of the item in the keychain. If the item does not exist yet then this method will raise an exception.
Use a value of nil to remove an attribute.
124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/mr_keychain.rb', line 124 def update! new_attributes result = Pointer.new :id query = @attributes.merge( KSecMatchLimit => KSecMatchLimitOne ) case (error_code = SecItemUpdate(query, new_attributes)) when ErrSecSuccess then else = SecCopyErrorMessageString(error_code, nil) raise KeychainException, "Error updating keychain item: #{message}" end end |