Refactored KeychainPasswordItem so that we don't have to pass all class fields to keychainQuery()
This commit is contained in:
parent
543a9d81b9
commit
48841b5214
|
@ -68,18 +68,19 @@ struct KeychainPasswordItem {
|
||||||
|
|
||||||
let service: String
|
let service: String
|
||||||
|
|
||||||
private(set) var account: String
|
private(set) var account: String?
|
||||||
|
|
||||||
let accessGroup: String?
|
let accessGroup: String?
|
||||||
|
|
||||||
// MARK: Intialization
|
// MARK: Intialization
|
||||||
|
|
||||||
init(service: String, account: String, accessGroup: String? = nil) {
|
init(service: String, account: String?, accessGroup: String? = nil) {
|
||||||
self.service = service
|
self.service = service
|
||||||
self.account = account
|
self.account = account
|
||||||
self.accessGroup = accessGroup
|
self.accessGroup = accessGroup
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// MARK: Keychain access
|
// MARK: Keychain access
|
||||||
|
|
||||||
func readPassword() throws -> String {
|
func readPassword() throws -> String {
|
||||||
|
@ -87,7 +88,7 @@ struct KeychainPasswordItem {
|
||||||
Build a query to find the item that matches the service, account and
|
Build a query to find the item that matches the service, account and
|
||||||
access group.
|
access group.
|
||||||
*/
|
*/
|
||||||
var query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
|
var query = keychainQuery()
|
||||||
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
query[kSecMatchLimit as String] = kSecMatchLimitOne
|
||||||
query[kSecReturnAttributes as String] = kCFBooleanTrue
|
query[kSecReturnAttributes as String] = kCFBooleanTrue
|
||||||
query[kSecReturnData as String] = kCFBooleanTrue
|
query[kSecReturnData as String] = kCFBooleanTrue
|
||||||
|
@ -125,7 +126,7 @@ struct KeychainPasswordItem {
|
||||||
var attributesToUpdate = [String : AnyObject]()
|
var attributesToUpdate = [String : AnyObject]()
|
||||||
attributesToUpdate[kSecValueData as String] = encodedPassword as AnyObject?
|
attributesToUpdate[kSecValueData as String] = encodedPassword as AnyObject?
|
||||||
|
|
||||||
let query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
|
let query = keychainQuery()
|
||||||
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
|
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
|
||||||
|
|
||||||
// Throw an error if an unexpected status was returned.
|
// Throw an error if an unexpected status was returned.
|
||||||
|
@ -136,7 +137,7 @@ struct KeychainPasswordItem {
|
||||||
No password was found in the keychain. Create a dictionary to save
|
No password was found in the keychain. Create a dictionary to save
|
||||||
as a new keychain item.
|
as a new keychain item.
|
||||||
*/
|
*/
|
||||||
var newItem = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
|
var newItem = keychainQuery()
|
||||||
newItem[kSecValueData as String] = encodedPassword as AnyObject?
|
newItem[kSecValueData as String] = encodedPassword as AnyObject?
|
||||||
|
|
||||||
// Add a the new item to the keychain.
|
// Add a the new item to the keychain.
|
||||||
|
@ -152,7 +153,7 @@ struct KeychainPasswordItem {
|
||||||
var attributesToUpdate = [String : AnyObject]()
|
var attributesToUpdate = [String : AnyObject]()
|
||||||
attributesToUpdate[kSecAttrAccount as String] = newAccountName as AnyObject?
|
attributesToUpdate[kSecAttrAccount as String] = newAccountName as AnyObject?
|
||||||
|
|
||||||
let query = KeychainPasswordItem.keychainQuery(withService: service, account: self.account, accessGroup: accessGroup)
|
let query = keychainQuery()
|
||||||
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
|
let status = SecItemUpdate(query as CFDictionary, attributesToUpdate as CFDictionary)
|
||||||
|
|
||||||
// Throw an error if an unexpected status was returned.
|
// Throw an error if an unexpected status was returned.
|
||||||
|
@ -163,16 +164,42 @@ struct KeychainPasswordItem {
|
||||||
|
|
||||||
func deleteItem() throws {
|
func deleteItem() throws {
|
||||||
// Delete the existing item from the keychain.
|
// Delete the existing item from the keychain.
|
||||||
let query = KeychainPasswordItem.keychainQuery(withService: service, account: account, accessGroup: accessGroup)
|
let query = keychainQuery()
|
||||||
let status = SecItemDelete(query as CFDictionary)
|
let status = SecItemDelete(query as CFDictionary)
|
||||||
|
|
||||||
// Throw an error if an unexpected status was returned.
|
// Throw an error if an unexpected status was returned.
|
||||||
guard status == noErr || status == errSecItemNotFound else { throw KeychainError.unhandledError(status: status) }
|
guard status == noErr || status == errSecItemNotFound else { throw KeychainError.unhandledError(status: status) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private func keychainQuery() -> [String : AnyObject] {
|
||||||
|
var query = [String : AnyObject]()
|
||||||
|
query[kSecClass as String] = kSecClassGenericPassword
|
||||||
|
query[kSecAttrService as String] = service as AnyObject?
|
||||||
|
|
||||||
|
if let account = account {
|
||||||
|
query[kSecAttrAccount as String] = account as AnyObject?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let accessGroup = accessGroup {
|
||||||
|
query[kSecAttrAccessGroup as String] = accessGroup as AnyObject?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let accessControl = accessControl {
|
||||||
|
query[kSecAttrAccessControl as String] = accessControl as AnyObject?
|
||||||
|
}
|
||||||
|
|
||||||
|
if let authenticationContext = authenticationContext {
|
||||||
|
query[kSecUseAuthenticationContext as String] = authenticationContext as AnyObject?
|
||||||
|
}
|
||||||
|
|
||||||
|
return query
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static func passwordItems(forService service: String, accessGroup: String? = nil) throws -> [KeychainPasswordItem] {
|
static func passwordItems(forService service: String, accessGroup: String? = nil) throws -> [KeychainPasswordItem] {
|
||||||
// Build a query for all items that match the service and access group.
|
// Build a query for all items that match the service and access group.
|
||||||
var query = KeychainPasswordItem.keychainQuery(withService: service, accessGroup: accessGroup)
|
var query = KeychainPasswordItem(service: service, account: nil, accessGroup: accessGroup).keychainQuery()
|
||||||
query[kSecMatchLimit as String] = kSecMatchLimitAll
|
query[kSecMatchLimit as String] = kSecMatchLimitAll
|
||||||
query[kSecReturnAttributes as String] = kCFBooleanTrue
|
query[kSecReturnAttributes as String] = kCFBooleanTrue
|
||||||
query[kSecReturnData as String] = kCFBooleanFalse
|
query[kSecReturnData as String] = kCFBooleanFalse
|
||||||
|
@ -204,21 +231,4 @@ struct KeychainPasswordItem {
|
||||||
return passwordItems
|
return passwordItems
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Convenience
|
|
||||||
|
|
||||||
private static func keychainQuery(withService service: String, account: String? = nil, accessGroup: String? = nil) -> [String : AnyObject] {
|
|
||||||
var query = [String : AnyObject]()
|
|
||||||
query[kSecClass as String] = kSecClassGenericPassword
|
|
||||||
query[kSecAttrService as String] = service as AnyObject?
|
|
||||||
|
|
||||||
if let account = account {
|
|
||||||
query[kSecAttrAccount as String] = account as AnyObject?
|
|
||||||
}
|
|
||||||
|
|
||||||
if let accessGroup = accessGroup {
|
|
||||||
query[kSecAttrAccessGroup as String] = accessGroup as AnyObject?
|
|
||||||
}
|
|
||||||
|
|
||||||
return query
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue