Keychain Service et Swift 3

Bonjour à  tous,


J'ai un souci avec une de mes applications depuis le passage à  Xcode 8 et Swift 3.


En effet j'utilise Keychain service et plus précisément le code suivant récupéré sur un blog pour stocker l'identifiant et le mot de passe de l'utilisateur.



import UIKit
import Security

// Identifiers
let serviceIdentifier = "MyService"
let userAccount = "authenticatedUser"
let accessGroup = "MyService"

// Arguments for the keychain queries
let kSecClassValue = NSString(format: kSecClass) as NSString
let kSecAttrAccountValue = NSString(format: kSecAttrAccount) as NSString
let kSecValueDataValue = NSString(format: kSecValueData) as NSString
let kSecClassGenericPasswordValue = NSString(format: kSecClassGenericPassword) as NSString
let kSecAttrServiceValue = NSString(format: kSecAttrService) as NSString
let kSecMatchLimitValue = NSString(format: kSecMatchLimit) as NSString
let kSecReturnDataValue = NSString(format: kSecReturnData) as NSString
let kSecMatchLimitOneValue = NSString(format: kSecMatchLimitOne) as NSString

class KeychainService: NSObject {

/**
* Exposed methods to perform queries.
* Note: feel free to play around with the arguments
* for these if you want to be able to customise the
* service identifier, user accounts, access groups, etc.
*/
class func saveToken(_ token: NSString) {
self.save(serviceIdentifier as NSString, data: token)
}

class func loadToken() -> NSString? {
let token = self.load(service: serviceIdentifier as NSString)
return token as! NSString?
}

class func deleteToken(_ token: String) {
self.delete(token)
}

class func clearToken() {
self.clear()
}

fileprivate class func delete(_ key: String) -> Bool
{
let query = [
(kSecClass as String) : kSecClassGenericPassword,
(kSecAttrAccount as String) : key
] as [String : Any]

return SecItemDelete(query as CFDictionary) == noErr
}

fileprivate class func clear() -> Bool
{
let query = [
(kSecClass as String): kSecClassGenericPassword
]

return SecItemDelete(query as CFDictionary) == noErr
}

fileprivate class func save(_ service: NSString, data: NSString) {
let dataFromString: Data = data.data(using: String.Encoding.utf8.rawValue, allowLossyConversion: false)!

// Instantiate a new default keychain query
let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, dataFromString], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecValueDataValue])

// Delete any existing items
SecItemDelete(keychainQuery as CFDictionary)

// Add the new keychain item
// var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)
SecItemAdd(keychainQuery as CFDictionary, nil)
}

fileprivate class func load(service: NSString) -> AnyObject? {

// Instantiate a new default keychain query
// Tell the query to return a result
// Limit our results to one item
let keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])

var dataTypeRef :Unmanaged<AnyObject>?

// Search for the keychain items
// let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)
let status: OSStatus = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(keychainQuery as CFDictionary, UnsafeMutablePointer($0)) }

let opaque = dataTypeRef?.toOpaque()

var contentsOfKeychain: NSString?

if let op = opaque {
let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()

// Convert the data retrieved from the keychain into a string
contentsOfKeychain = NSString(data: retrievedData as Data, encoding: String.Encoding.utf8.rawValue)

} else {
print("Nothing was retrieved from the keychain. Status code \(status)")
}

return contentsOfKeychain

}
}

Au niveau de l'instruction  



let status: OSStatus = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(keychainQuery as CFDictionary, UnsafeMutablePointer($0)) } 

 j'ai le message :



'init' is unavailable: use 'withMemoryRebound(to:capacity:_)' to temporarily view memory as another layout-compatible type.

Auriez-vous la solution pour remédier à  ce problème, d'avance merci.


Réponses

  • MagiicMagiic Membre
    septembre 2016 modifié #2

    Sur Swift 3 ils ont changé pas mal de chose et notamment l'introduction du type UnsafeRawPointer : https://swift.org/migration-guide/se-0107-migrate.html


     


    Tu dois utiliser une des 3 méthodes qu'ils mentionnent sur ce même lien pour migrer de UnsafePointer<Void> à  UnsafeRawPointer.


     


    Par exemple on aurait quelque chose comme ceci :



    withUnsafePointer(to: &dataTypeRef, {
    $0.withMemoryRebound(to: sockaddr.self, capacity: 1, { aSockAddress in
    SecItemCopyMatching(keychainQuery as CFDictionary,aSockAddress)
    })
    })

  • Merci, 


    j'ai testé le code suivant :



    var dataTypeRef :Unmanaged<AnyObject>?

    let status: OSStatus = withUnsafePointer(to: &dataTypeRef) {
    $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
    dataTypeRef in SecItemCopyMatching(keychainQuery as CFDictionary, &dataTypeRef) }
    }

    Mais j'ai l'erreur suivante :



    Cannot convert value of type 'UnsafeMutablePointer<_>' to expected argument type 'CFTypeRef?'

    le sujet est trop pointu pour moi !


    merci de votre aide.


  • Je pense que je vais supprimer l'utilisation de code étant donné que je ne trouve pas la solution.


    Un conseil à  me donner sur ce que je pourrais utiliser à  la place pour stocker username et password.


    Merci.


  • CéroceCéroce Membre, Modérateur

    Un conseil à  me donner sur ce que je pourrais utiliser à  la place pour stocker username et password.

    ça utilise aussi le Keychain:
    https://github.com/nicklockwood/FXKeychain
  • colas_colas_ Membre
    septembre 2016 modifié #6


    ça utilise aussi le Keychain:
    https://github.com/nicklockwood/FXKeychain




     


     


    Je l'utilise, j'en suis très satisfait. ça permet d'utiliser le Keychain comme un bête dictionnaire.


Connectez-vous ou Inscrivez-vous pour répondre.