-
-
Save ffried/2d6b0b8cefa53a1cdddf to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import Security | |
class Keychain { | |
class func save(key: String, data: NSData) -> Bool { | |
let query: [String: AnyObject] = [ | |
kSecClass : kSecClassGenericPassword, | |
kSecAttrAccount : key, | |
kSecValueData : data ] | |
SecItemDelete(query as CFDictionaryRef) | |
let status: OSStatus = SecItemAdd(query as CFDictionaryRef, nil) | |
return status == noErr | |
} | |
class func load(key: String) -> NSData? { | |
let query: [String: AnyObject] = [ | |
kSecClass : kSecClassGenericPassword, | |
kSecAttrAccount : key, | |
kSecReturnData : kCFBooleanTrue, | |
kSecMatchLimit : kSecMatchLimitOne ] | |
var dataTypeRef :Unmanaged<AnyObject>? | |
let status: OSStatus = SecItemCopyMatching(query, &dataTypeRef) | |
if status == noErr { | |
return (dataTypeRef!.takeRetainedValue() as NSData) | |
} else { | |
return nil | |
} | |
} | |
class func delete(key: String) -> Bool { | |
let query: [String: AnyObject] = [ | |
kSecClass : kSecClassGenericPassword, | |
kSecAttrAccount : key ] | |
let status: OSStatus = SecItemDelete(query as CFDictionaryRef) | |
return status == noErr | |
} | |
class func clear() -> Bool { | |
let query: [String: AnyObject] = [ kSecClass : kSecClassGenericPassword ] | |
let status: OSStatus = SecItemDelete(query as CFDictionaryRef) | |
return status == noErr | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
import XCTest | |
class KeychainTests: XCTestCase { | |
override func setUp() { | |
super.setUp() | |
Keychain.clear() | |
} | |
override func tearDown() { | |
Keychain.clear() | |
super.tearDown() | |
} | |
func testSaveLoad() { | |
let key1 = "testSaveLoadKey1" | |
let key2 = "testSaveLoadKey2" | |
let saveData = "data".dataValue | |
XCTAssertTrue(Keychain.load(key1) == nil) | |
XCTAssertTrue(Keychain.load(key2) == nil) | |
XCTAssertTrue(Keychain.save(key1, data: saveData)) | |
XCTAssertTrue(Keychain.load(key1) != nil) | |
XCTAssertTrue(Keychain.load(key2) == nil) | |
let loadData = Keychain.load(key1)! | |
XCTAssertEqual(loadData.stringValue, saveData.stringValue) | |
} | |
func testDelete() { | |
let key1 = "testDeleteKey1" | |
let key2 = "testDeleteKey2" | |
let saveData = "testDeleteData".dataValue | |
XCTAssertTrue(Keychain.save(key1, data: saveData)) | |
XCTAssertTrue(Keychain.save(key2, data: saveData)) | |
XCTAssertTrue(Keychain.load(key1) != nil) | |
XCTAssertTrue(Keychain.load(key2) != nil) | |
XCTAssertTrue(Keychain.delete(key1)) | |
XCTAssertTrue(Keychain.load(key1) == nil) | |
XCTAssertTrue(Keychain.load(key2) != nil) | |
} | |
func testClear() { | |
let key = "testClearKey" | |
let data = "testClearData".dataValue | |
Keychain.save(key, data: data) | |
XCTAssertTrue(Keychain.load(key) != nil) | |
Keychain.clear() | |
XCTAssertTrue(Keychain.load(key) == nil) | |
} | |
} | |
extension String { | |
public var dataValue: NSData { | |
return dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)! | |
} | |
} | |
extension NSData { | |
public var stringValue: String { | |
return NSString(data: self, encoding: NSUTF8StringEncoding) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment