Skip to content

Instantly share code, notes, and snippets.

@adamzarn
Last active April 9, 2022 18:42
Show Gist options
  • Save adamzarn/264a88dd4e0ff6bbde0af1b7a509a662 to your computer and use it in GitHub Desktop.
Save adamzarn/264a88dd4e0ff6bbde0af1b7a509a662 to your computer and use it in GitHub Desktop.
A class that makes it easy to store and retrieve string values from the Keychain
import Foundation
/* Example Usage:
Get
----------------------------
let token = Keychain[.token]
Set
----------------------------
Keychain[.token] = value
Keychain[.token] = nil
*/
enum KeychainKey: String {
case token
}
class Keychain {
class subscript(key: KeychainKey) -> String? {
get {
return Keychain.getString(valueForKey: key.rawValue)
}
set {
if let newValue = newValue {
Keychain.setString(value: newValue, forKey: key.rawValue)
} else {
Keychain.removeString(forKey: key.rawValue)
}
}
}
class func setString(value: String, forKey key: String) {
let data = Data(value.utf8)
let query = getSetStringQuery(key: key, data: data)
SecItemDelete(query as CFDictionary)
SecItemAdd(query as CFDictionary, nil)
}
class func removeString(forKey key: String) {
let query = getSetStringQuery(key: key)
SecItemDelete(query as CFDictionary)
}
class func getString(valueForKey key: String) -> String? {
let query = getGetStringQuery(key: key)
var dataTypeRef: AnyObject? = nil
let status: OSStatus = SecItemCopyMatching(query as CFDictionary, &dataTypeRef)
if status == noErr {
guard let data = dataTypeRef as? Data else { return nil }
return String(data: data, encoding: .utf8)
} else {
return nil
}
}
private class func getSetStringQuery(key: String, data: Data? = nil) -> CFDictionary {
return [kSecClass as String: kSecClassGenericPassword as String,
kSecAttrAccount as String: key,
kSecValueData as String: data ?? Data()] as CFDictionary
}
private class func getGetStringQuery(key: String) -> CFDictionary {
return [kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecReturnData as String: kCFBooleanTrue!,
kSecMatchLimit as String: kSecMatchLimitOne] as CFDictionary
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment