Code Monkey home page Code Monkey logo

Comments (9)

ChristopherCarranza avatar ChristopherCarranza commented on June 19, 2024 13

@kishikawakatsumi would something like this be acceptable? Keeping in mind the below code is just a generic keychain query for example purposes, also the code below is specific to something we know is locked behind TouchID in the keychain. We currently use this to solve that problem. I'd def like to be using this as part of the framework.

public func contains(_ key: String) -> Bool {
        // We spcify kSecUseAuthenticationUIFail so that the error
        // errSecInteractionNotAllowed will be returned if an item needs
        // to authenticate with UI and the authentication UI will not be presented.
        let keychainQuery: [AnyHashable: Any] = [
            kSecClass as AnyHashable: kSecClassGenericPassword,
            kSecAttrService as AnyHashable: Bundle.main.bundleIdentifier!,
            kSecAttrAccount as AnyHashable: key,
            kSecUseAuthenticationUI as AnyHashable: kSecUseAuthenticationUIFail
        ]
        
        var result: AnyObject?
        let status = SecItemCopyMatching(keychainQuery as CFDictionary, &result)

        // If that status is errSecInteractionNotAllowed, then
        // we know that the key is present, but you cannot interact with
        // it without authentication. Otherwise, we assume the key is not present.
        return status == errSecInteractionNotAllowed
    }

Maybe something like this in Keychain

public func contains(_ key: String) throws -> Bool {
        var query = options.query()
        query[AttributeAccount] = key
        query[UseAuthenticationUI] = UseAuthenticationUIFail
        
        let status = SecItemCopyMatching(query as CFDictionary, nil)
        switch status {
        case errSecSuccess, errSecInteractionNotAllowed:
            return true
        case errSecItemNotFound:
            return false
        default:
            throw securityError(status: status)
        }
    }

from keychainaccess.

MikeBenton2 avatar MikeBenton2 commented on June 19, 2024 1

@ChristopherCarranza Great thinking! This was an amazing workaround!

from keychainaccess.

hmlongco avatar hmlongco commented on June 19, 2024 1

Noting that UseAuthenticationUIFail is deprecated as of iOS 14.

I'm using something like the following...

    func has(service: String, account: String, options: [Options] = []) -> Bool {
        var query = self.query(service: service, account: account, options: options)
        query[kSecUseAuthenticationContext as String] = internalContext

        var secItemResult: CFTypeRef?
        status = SecItemCopyMatching(query as CFDictionary, &secItemResult)

        if status == errSecSuccess || status == errSecInteractionNotAllowed {
            return true
        }

        return false
    }

    private var internalContext: LAContext? = {
        let context = LAContext()
        context.interactionNotAllowed = true
        return context
    }()

from keychainaccess.

kishikawakatsumi avatar kishikawakatsumi commented on June 19, 2024

@kylejm I've tried a various way of that, there is no way to check whether the value exists or not, I think 😢 . If there is a possibility that the value would be protected with Touch ID, you should always execute keychain method asynchronously.

from keychainaccess.

ky1ejs avatar ky1ejs commented on June 19, 2024

Ah that's lame. No worries, I've worked around the problem by storing a flag to mark that the credential is stored. I hate this solution! 😩. Thanks for the reply :)

from keychainaccess.

lolgear avatar lolgear commented on June 19, 2024

@hmlongco
Thanks for your example.
I have this comment above query setup.

        // specify kSecUseAuthenticationUIFail so that the error
        // errSecInteractionNotAllowed will be returned if an item needs
        // to authenticate with UI and the authentication UI will not be presented.

Will this behavior persist if I change query to LAContext-based query with context.interactionNotAllowed = true?

from keychainaccess.

fritzfr avatar fritzfr commented on June 19, 2024

The code from @ChristopherCarranza above works, but you should also check for errSecSuccess:

private func checkForKeychainItemExistence(itemName: String, completion: @escaping (Bool) -> Void) {
	let keychainQuery: [AnyHashable: Any] = [
		kSecClass as AnyHashable: kSecClassGenericPassword,
		kSecAttrService as AnyHashable: "KEYCHAIN_SERVICE_NAME_HERE",
		kSecAttrAccount as AnyHashable: itemName,
		kSecUseAuthenticationUI as AnyHashable: kSecUseAuthenticationUIFail
	]
	
	var result: AnyObject?
	let status = SecItemCopyMatching(keychainQuery as CFDictionary, &result)

        // also check for errSecSuccess here!
	completion(status == errSecInteractionNotAllowed || status == errSecSuccess)
}

from keychainaccess.

fritzfr avatar fritzfr commented on June 19, 2024

After playing around with it a lot I noticed some inconsistent behaviour of the SecItemCopyMatching status response.

Sometimes, it returns 0, meaning errSecSuccess. So to truly check if an item is there, you should also check for that code.

from keychainaccess.

hoanglk25 avatar hoanglk25 commented on June 19, 2024

The code from @ChristopherCarranza above works, but you should also check for errSecSuccess:

private func checkForKeychainItemExistence(itemName: String, completion: @escaping (Bool) -> Void) {
	let keychainQuery: [AnyHashable: Any] = [
		kSecClass as AnyHashable: kSecClassGenericPassword,
		kSecAttrService as AnyHashable: "KEYCHAIN_SERVICE_NAME_HERE",
		kSecAttrAccount as AnyHashable: itemName,
		kSecUseAuthenticationUI as AnyHashable: kSecUseAuthenticationUIFail
	]
	
	var result: AnyObject?
	let status = SecItemCopyMatching(keychainQuery as CFDictionary, &result)

        // also check for errSecSuccess here!
	completion(status == errSecInteractionNotAllowed || status == errSecSuccess)
}

KEYCHAIN_SERVICE_NAME_HERE what that ?, I can't find service name

from keychainaccess.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.