Search code examples
swift4keychain

Locksmith error: Locksmith.LocksmithError.interactionNotAllowed


we're using Locksmith to save user data for Keychain. In our end everything works as it should but for some reason we receive crashes with the error Locksmith.LocksmithError.interactionNotAllowed.

Follows the code where the crash happen:

func updateUserAccessToken(forAccount account: String, token: String) {
    var userAccessToken = Locksmith.loadDataForUserAccount(userAccount: account) ?? [String: Any]()
    userAccessToken[“token”] = token
    try! Locksmith.updateData(data: userAccessToken, forUserAccount: account)
}

Why is the code above crashes for other users? 'til . now we can't replicate the said crash. Any help is very much appreciated. Thanks!

UPDATE: So we finally able to replicate this crash, and it's because we're accessing the keychain while the device is locked. I found out you can change the Keychain's "accessibility option" but I'm not sure how to do it in Locksmith. Anybody?


Solution

  • I found out that if you're using a protocol base approach changing the accessibility option is much more easier. But unfortunately our app doesn't use it. So what I did was I created an extension as follow:

    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()
        }
    }
    

    NOTE: changing the "accessibility option" may loss your access to the data previously saved with the default "accessibility option". If you need those data you may need to handle it separately.