evgenyneu / keychain-swift

Helper functions for saving text in Keychain securely for iOS, OS X, tvOS and watchOS.
MIT License
2.82k stars 345 forks source link

MacOS Catalyst 13.0 #120

Closed dcarriola closed 4 years ago

dcarriola commented 4 years ago

Hi, I'm trying to make my universal app to run on macOS Catalina with the new Catalyst feature. It runs fine (with some warnings of deprecated code) but when I'm trying to save the login credentials using KeychainSwift, nothing is getting saved. Everything works fine when using iOS but I would also like my app to run on macOS.

Please, let me know if I need to do something else to make it work in this scenario.

Thanks in advance!

evgenyneu commented 4 years ago

Thanks for reporting @dcarriola. I have not tried Catalyst yet. Could you run the following code and see if it prints "My secretive bee 🐝" message to the debug console? This will show if Keychain works or not.

  override func viewDidLoad() {
    super.viewDidLoad()

    let itemKey = "My key"
    let itemValue = "My secretive bee 🐝"
    deleteFromKeychain(itemKey: itemKey)
    addToKeychain(itemKey: itemKey, itemValue: itemValue)
    readFromKeychain(itemKey: itemKey)
  }

  func deleteFromKeychain(itemKey: String) {
    let queryDelete: [String: AnyObject] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: itemKey as AnyObject,
    ]

    let resultCodeDelete = SecItemDelete(queryDelete as CFDictionary)

    if resultCodeDelete != noErr {
      print("Error deleting from Keychain: \(resultCodeDelete)")
    }
  }

  func addToKeychain(itemKey: String, itemValue: String) {
    guard let valueData = itemValue.data(using: String.Encoding.utf8) else {
      print("Error saving text to Keychain")
      return
    }

    let queryAdd: [String: AnyObject] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: itemKey as AnyObject,
      kSecValueData as String: valueData as AnyObject,
      kSecAttrAccessible as String: kSecAttrAccessibleWhenUnlocked,
    ]

    let resultCode = SecItemAdd(queryAdd as CFDictionary, nil)

    if resultCode != noErr {
      print("Error saving to Keychain: \(resultCode)")
    }
  }

  func readFromKeychain(itemKey: String) {
    let queryLoad: [String: AnyObject] = [
      kSecClass as String: kSecClassGenericPassword,
      kSecAttrAccount as String: itemKey as AnyObject,
      kSecReturnData as String: kCFBooleanTrue,
      kSecMatchLimit as String: kSecMatchLimitOne,
    ]

    var result: AnyObject?

    let resultCodeLoad = withUnsafeMutablePointer(to: &result) {
      SecItemCopyMatching(queryLoad as CFDictionary, UnsafeMutablePointer($0))
    }

    if resultCodeLoad == noErr {
      if let result = result as? Data,
        let keyValue = NSString(data: result,
                                encoding: String.Encoding.utf8.rawValue) as? String {

        // Found successfully
        print(keyValue)
      }
    } else {
      print("Error loading from Keychain: \(resultCodeLoad)")
    }
  }
chinotapales commented 4 years ago

Hey there,

I ran your code snippet on Mac Catalyst with Deployment Target 13.1 and this is my output:

Error deleting from Keychain: -34018 Error saving to Keychain: -34018 Error loading from Keychain: -25300

Hopefully this issue will be resolved.. Thanks!

evgenyneu commented 4 years ago

Thanks, I've asked on stackoveflow.

dcarriola commented 4 years ago

hey @evgenyneu, just saw your stackoverflow post and the answer works. I just added "keychain sharing" within the signing & capabilities (even if i leave the keychain group empty) and it works. Thanks a lot!