Open ghost opened 6 years ago
I encounter this also. What I notice is that the keychain that was stored using the "unlock" accessible option can't be access or delete when you change to "afterFirstUnlock"
What I did is first check if data already exists using the "afterFirstUnlock" then if not I'll pull back by checking using the "unlock" accessible options. If the data is stored in the "unlock" accessible options I'll copy it over to "afterFirstUnlock" and delete the old data to avoid redundancy
"first check if data already exists using the "afterFirstUnlock" then if not I'll pull back by checking using the "unlock" accessible options. If the data is stored in the "unlock" accessible options I'll copy it over to "afterFirstUnlock" and delete the old data to avoid redundancy" -- > How I'm suppose to handle that. I'm using the protocol based approach. I'm attaching my code and please let me know how I can handle that:
private let UsernameKey = "com.xxxxx.usernameKey" private let KeyKey = "com.xxxxx.keyKey" private let Service = "xxxxx" private let AuthAccount = "xxxxxx-Authorization"
struct Autorization {
let username: String
let key: String
private struct Access: ReadableSecureStorable, DeleteableSecureStorable, GenericPasswordSecureStorable {
//var accessible: LocksmithAccessibleOption? {return .afterFirstUnlock}
var service: String { return Service }
var account: String { return AuthAccount }
}
}
extension Autorization {
static func readCurrentAuthFromKeychain() -> Autorization? {
let access = Access()
let result = access.readFromSecureStore()
guard let data = result?.data, let username = data[UsernameKey] as? String, let key = data[KeyKey] as? String else { return nil }
return Autorization(username: username, key: key)
}
static func deleteCurrentUserFromKeychain() throws {
let access = Access()
try access.deleteFromSecureStore()
}
}
extension Autorization: CreateableSecureStorable { var data: [String : Any] { return [ UsernameKey: username as AnyObject, KeyKey: key as AnyObject ] }
}
extension Autorization: GenericPasswordSecureStorable { //var accessible: LocksmithAccessibleOption? {return .afterFirstUnlock} var service: String { return Service } var account: String { return AuthAccount } }
I'm not sure how can I change your code, but here is part of my code:
In a helper file:
private let accessible = LocksmithAccessibleOption.afterFirstUnlock
private func loadData(forUsername username: String) -> [String: Any]? {
// case1: try if we can get the value when using "accessibleOption"
// case2: try using the default method, if we can find value
// case3: we didn't have saved data for this username
if let dataTemp = Locksmith.loadDataForUserAccount(userAccount: username, accessibleOption: accessible) {
return dataTemp
} else if let dataTemp = Locksmith.loadDataForUserAccount(userAccount: username) {
// yup we have values with the old "accessibleOption", get it and assign to dataTemp
try! Locksmith.deleteDataForUserAccount(userAccount: username) // remove it so we don't have redundant values for this key
try! Locksmith.updateData(data: dataTemp, forUserAccount: username, accessibleOption: accessible) // assign it to the new "accesibleOption"
return dataTemp // return the value
} else {
return nil
}
}
then I created an extension:
extension Locksmith {
fileprivate static func loadDataForUserAccount(userAccount: String,
inService service: String = LocksmithDefaultService,
accessibleOption: LocksmithAccessibleOption) -> [String: Any]? {
struct ReadRequest: GenericPasswordSecureStorable, ReadableSecureStorable {
let service: String
let account: String
var accessible: LocksmithAccessibleOption?
}
let request = ReadRequest(service: service, account: userAccount, accessible: accessibleOption)
return request.readFromSecureStore()?.data
}
fileprivate static func updateData(data: [String: Any],
forUserAccount userAccount: String,
inService service: String = LocksmithDefaultService,
accessibleOption: LocksmithAccessibleOption) throws {
struct UpdateRequest: GenericPasswordSecureStorable, CreateableSecureStorable {
let service: String
let account: String
let data: [String: Any]
var accessible: LocksmithAccessibleOption?
}
let request = UpdateRequest(service: service, account: userAccount, data: data, accessible: accessibleOption)
return try request.updateInSecureStore()
}
}
I'm not sure if this is the ideal way, but it does works the way we need it.
"else if let dataTemp = Locksmith.loadDataForUserAccount(userAccount: username)" statement returns nil even if there is data in the keychain for the same account.
In earlier version of my app the LocksmithAccessibleOption was default. Now I want to change it to "afterFirstUnlock". for that I added following code in my protocol var accessible: LocksmithAccessibleOption? {return .afterFirstUnlock}
But after using this I'm not able to either delete or access the keychain item at all. Help me here please.