Skip to content
This repository has been archived by the owner on Jan 10, 2023. It is now read-only.

Commit

Permalink
Syntax changes to align closer to Swift 3 guidelines.
Browse files Browse the repository at this point in the history
  • Loading branch information
jrendel committed Oct 1, 2016
1 parent 0903705 commit 048a978
Show file tree
Hide file tree
Showing 8 changed files with 84 additions and 74 deletions.
12 changes: 7 additions & 5 deletions README.md
Expand Up @@ -2,7 +2,7 @@

A simple wrapper for the iOS Keychain to allow you to use it in a similar fashion to User Defaults. Written in Swift.

Provides a defaultKeychainWrapper() function to access singleton instance that is setup to work for most needs.
Provides singleton instance that is setup to work for most needs. Use KeychainWrapper.standard to access the singleton instance.

If you need to customize the keychain access to use a custom identifier or access group, you can create your own instance instead of using the singleton access.

Expand All @@ -14,17 +14,17 @@ Users that want to deviate from this default implementation, now can do so in in

Add a string value to keychain:
```
let saveSuccessful: Bool = KeychainWrapper.defaultKeychainWrapper.set("Some String", forKey: "myKey")
let saveSuccessful: Bool = KeychainWrapper.standard.set("Some String", forKey: "myKey")
```

Retrieve a string value from keychain:
```
let retrievedString: String? = KeychainWrapper.defaultKeychainWrapper.string(forKey: "myKey")
let retrievedString: String? = KeychainWrapper.standard.string(forKey: "myKey")
```

Remove a string value from keychain:
```
let removeSuccessful: Bool = KeychainWrapper.defaultKeychainWrapper.remove(key: "myKey")
let removeSuccessful: Bool = KeychainWrapper.standard.remove(key: "myKey")
```

##Custom Instance
Expand Down Expand Up @@ -55,7 +55,7 @@ let removeSuccessful: Bool = customKeychainWrapperInstance.remove(key: "myKey")
By default, all items saved to keychain can only be accessed when the device is unlocked. To change this accessibility, an optional "withAccessibility" param can be set on all requests. The enum KeychainItemAccessibilty provides an easy way to select the accessibility level desired:

```
KeychainWrapper.defaultKeychainWrapper.set("Some String", forKey: "myKey", withAccessibility: .AfterFirstUnlock)
KeychainWrapper.standard.set("Some String", forKey: "myKey", withAccessibility: .AfterFirstUnlock)
```

##Installation
Expand Down Expand Up @@ -84,6 +84,8 @@ Download and drop ```KeychainWrapper.swift``` and ```KeychainItemAcessibility.sw

## Release History

* 2.2.1
* Syntax updates to be more Swift 3 like
* 2.2
* Updated to support Swift 3.0
* Remove deprecated functions (static access)
Expand Down
4 changes: 2 additions & 2 deletions SwiftKeychainWrapper.podspec
@@ -1,9 +1,9 @@
Pod::Spec.new do |s|
s.name = 'SwiftKeychainWrapper'
s.version = '2.2.0'
s.version = '2.2.1'
s.summary = 'Wrapper for the iOS Keychain written in Swift.'
s.description = <<-DESC
A simple wrapper for the iOS Keychain to allow you to use it in a similar fashion to NSUserDefaults. Supports Access Groups. Written in Swift.'
A simple wrapper for the iOS Keychain to allow you to use it in a similar fashion to UserDefaults. Supports Access Groups. Written in Swift.'
DESC
s.module_name = "SwiftKeychainWrapper"
s.homepage = 'https://github.com/jrendel/SwiftKeychainWrapper'
Expand Down
4 changes: 2 additions & 2 deletions SwiftKeychainWrapper/Info.plist
Expand Up @@ -15,11 +15,11 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>2.2.0</string>
<string>2.2.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>2.2.0</string>
<string>2.2.1</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
Expand Down
14 changes: 11 additions & 3 deletions SwiftKeychainWrapper/KeychainWrapper.swift
Expand Up @@ -42,8 +42,12 @@ private let SecReturnAttributes: String = kSecReturnAttributes as String

/// KeychainWrapper is a class to help make Keychain access in Swift more straightforward. It is designed to make accessing the Keychain services more like using NSUserDefaults, which is much more familiar to people.
open class KeychainWrapper {

@available(*, deprecated: 2.2.1, message: "KeychainWrapper.defaultKeychainWrapper is deprecated, use KeychainWrapper.standard instead")
public static let defaultKeychainWrapper = KeychainWrapper.standard

/// Default keychain wrapper access
public static let defaultKeychainWrapper = KeychainWrapper()
public static let standard = KeychainWrapper()

/// ServiceName is used for the kSecAttrService property to uniquely identify this keychain accessor. If no service name is specified, KeychainWrapper will default to using the bundleIdentifier.
private (set) public var serviceName: String
Expand Down Expand Up @@ -293,13 +297,17 @@ open class KeychainWrapper {
}
}


@available(*, deprecated: 2.2.1, message: "remove is deprecated, use removeObject instead")
@discardableResult open func remove(key: String, withAccessibility accessibility: KeychainItemAccessibility? = nil) -> Bool {
return removeObject(forKey: key, withAccessibility: accessibility)
}

/// Remove an object associated with a specified key. If re-using a key but with a different accessibility, first remove the previous key value using removeObjectForKey(:withAccessibility) using the same accessibilty it was saved with.
///
/// - parameter forKey: The key value to remove data for.
/// - parameter withAccessibility: Optional accessibility level to use when looking up the keychain item.
/// - returns: True if successful, false otherwise.
@discardableResult open func remove(key: String, withAccessibility accessibility: KeychainItemAccessibility? = nil) -> Bool {
@discardableResult open func removeObject(forKey key: String, withAccessibility accessibility: KeychainItemAccessibility? = nil) -> Bool {
let keychainQueryDictionary: [String:Any] = setupKeychainQueryDictionary(forKey: key, withAccessibility: accessibility)

// Delete
Expand Down
70 changes: 35 additions & 35 deletions SwiftKeychainWrapperTests/KeychainWrapperDefaultWrapperTests.swift
Expand Up @@ -25,83 +25,83 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {
// Put teardown code here. This method is called after the invocation of each test method in the class.

// clean up keychain
KeychainWrapper.defaultKeychainWrapper.remove(key: testKey)
KeychainWrapper.defaultKeychainWrapper.remove(key: testKey2)
KeychainWrapper.standard.removeObject(forKey: testKey)
KeychainWrapper.standard.removeObject(forKey: testKey2)

super.tearDown()
}

func testDefaultServiceName() {
let bundleIdentifier = Bundle.main.bundleIdentifier
if let bundleIdentifierString = bundleIdentifier {
XCTAssertEqual(KeychainWrapper.defaultKeychainWrapper.serviceName, bundleIdentifierString, "Service Name should be equal to the bundle identifier when it is accessible")
XCTAssertEqual(KeychainWrapper.standard.serviceName, bundleIdentifierString, "Service Name should be equal to the bundle identifier when it is accessible")
} else {
XCTAssertEqual(KeychainWrapper.defaultKeychainWrapper.serviceName, "SwiftKeychainWrapper", "Service Name should be equal to SwiftKeychainWrapper when the bundle identifier is not accessible")
XCTAssertEqual(KeychainWrapper.standard.serviceName, "SwiftKeychainWrapper", "Service Name should be equal to SwiftKeychainWrapper when the bundle identifier is not accessible")
}
}

func testDefaultAccessGroup() {
XCTAssertNil(KeychainWrapper.defaultKeychainWrapper.accessGroup, "Access Group should be nil when nothing is set")
XCTAssertNil(KeychainWrapper.standard.accessGroup, "Access Group should be nil when nothing is set")
}

func testHasValueForKey() {
XCTAssertFalse(KeychainWrapper.defaultKeychainWrapper.hasValue(forKey: testKey), "Keychain should not have a value for the test key")
XCTAssertFalse(KeychainWrapper.standard.hasValue(forKey: testKey), "Keychain should not have a value for the test key")

KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
KeychainWrapper.standard.set(testString, forKey: testKey)

XCTAssertTrue(KeychainWrapper.defaultKeychainWrapper.hasValue(forKey: testKey), "Keychain should have a value for the test key after it is set")
XCTAssertTrue(KeychainWrapper.standard.hasValue(forKey: testKey), "Keychain should have a value for the test key after it is set")
}

func testRemoveObjectFromKeychain() {
KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
KeychainWrapper.standard.set(testString, forKey: testKey)

XCTAssertTrue(KeychainWrapper.defaultKeychainWrapper.hasValue(forKey: testKey), "Keychain should have a value for the test key after it is set")
XCTAssertTrue(KeychainWrapper.standard.hasValue(forKey: testKey), "Keychain should have a value for the test key after it is set")

KeychainWrapper.defaultKeychainWrapper.remove(key: testKey)
KeychainWrapper.standard.removeObject(forKey: testKey)

XCTAssertFalse(KeychainWrapper.defaultKeychainWrapper.hasValue(forKey: testKey), "Keychain should not have a value for the test key after it is removed")
XCTAssertFalse(KeychainWrapper.standard.hasValue(forKey: testKey), "Keychain should not have a value for the test key after it is removed")
}

func testStringSave() {
let stringSaved = KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
let stringSaved = KeychainWrapper.standard.set(testString, forKey: testKey)

XCTAssertTrue(stringSaved, "String did not save to Keychain")

// clean up keychain
KeychainWrapper.defaultKeychainWrapper.remove(key: testKey)
KeychainWrapper.standard.removeObject(forKey: testKey)
}

func testStringRetrieval() {
KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
KeychainWrapper.standard.set(testString, forKey: testKey)

if let retrievedString = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey) {
if let retrievedString = KeychainWrapper.standard.string(forKey: testKey) {
XCTAssertEqual(retrievedString, testString, "String retrieved for key should equal string saved for key")
} else {
XCTFail("String for Key not found")
}
}

func testStringRetrievalWhenValueDoesNotExist() {
let retrievedString = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey)
let retrievedString = KeychainWrapper.standard.string(forKey: testKey)
XCTAssertNil(retrievedString, "String for Key should not exist")
}

func testMultipleStringSave() {
if !KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey) {
if !KeychainWrapper.standard.set(testString, forKey: testKey) {
XCTFail("String for testKey did not save")
}

if !KeychainWrapper.defaultKeychainWrapper.set(testString2, forKey: testKey2) {
if !KeychainWrapper.standard.set(testString2, forKey: testKey2) {
XCTFail("String for testKey2 did not save")
}

if let string1Retrieved = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey) {
if let string1Retrieved = KeychainWrapper.standard.string(forKey: testKey) {
XCTAssertEqual(string1Retrieved, testString, "String retrieved for testKey should match string saved to testKey")
} else {
XCTFail("String for testKey could not be retrieved")
}

if let string2Retrieved = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey2) {
if let string2Retrieved = KeychainWrapper.standard.string(forKey: testKey2) {
XCTAssertEqual(string2Retrieved, testString2, "String retrieved for testKey2 should match string saved to testKey2")
} else {
XCTFail("String for testKey2 could not be retrieved")
Expand All @@ -110,21 +110,21 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {

func testMultipleStringsSavedToSameKey() {

if !KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey) {
if !KeychainWrapper.standard.set(testString, forKey: testKey) {
XCTFail("String for testKey did not save")
}

if let string1Retrieved = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey) {
if let string1Retrieved = KeychainWrapper.standard.string(forKey: testKey) {
XCTAssertEqual(string1Retrieved, testString, "String retrieved for testKey after first save should match first string saved testKey")
} else {
XCTFail("String for testKey could not be retrieved")
}

if !KeychainWrapper.defaultKeychainWrapper.set(testString2, forKey: testKey) {
if !KeychainWrapper.standard.set(testString2, forKey: testKey) {
XCTFail("String for testKey did not update")
}

if let string2Retrieved = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey) {
if let string2Retrieved = KeychainWrapper.standard.string(forKey: testKey) {
XCTAssertEqual(string2Retrieved, testString2, "String retrieved for testKey after update should match second string saved to testKey")
} else {
XCTFail("String for testKey could not be retrieved after update")
Expand All @@ -133,7 +133,7 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {

func testNSCodingObjectSave() {
let myTestObject = TestObject()
let objectSaved = KeychainWrapper.defaultKeychainWrapper.set(myTestObject, forKey: testKey)
let objectSaved = KeychainWrapper.standard.set(myTestObject, forKey: testKey)

XCTAssertTrue(objectSaved, "Object that implements NSCoding should save to Keychain")
}
Expand All @@ -144,9 +144,9 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {
myTestObject.objectName = testString
myTestObject.objectRating = testInt

KeychainWrapper.defaultKeychainWrapper.set(myTestObject, forKey: testKey)
KeychainWrapper.standard.set(myTestObject, forKey: testKey)

if let retrievedObject = KeychainWrapper.defaultKeychainWrapper.object(forKey: testKey) as? TestObject{
if let retrievedObject = KeychainWrapper.standard.object(forKey: testKey) as? TestObject{
XCTAssertEqual(retrievedObject.objectName, testString, "NSCoding compliant object retrieved for key should have objectName property equal to what it was stored with")
XCTAssertEqual(retrievedObject.objectRating, testInt, "NSCoding compliant object retrieved for key should have objectRating property equal to what it was stored with")
} else {
Expand All @@ -155,15 +155,15 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {
}

func testNSCodingObjectRetrievalWhenValueDoesNotExist() {
let retrievedObject = KeychainWrapper.defaultKeychainWrapper.object(forKey: testKey) as? TestObject
let retrievedObject = KeychainWrapper.standard.object(forKey: testKey) as? TestObject
XCTAssertNil(retrievedObject, "Object for Key should not exist")
}

func testDataSave() {
let testData = testString.data(using: String.Encoding.utf8)

if let data = testData {
let dataSaved = KeychainWrapper.defaultKeychainWrapper.set(data, forKey: testKey)
let dataSaved = KeychainWrapper.standard.set(data, forKey: testKey)

XCTAssertTrue(dataSaved, "Data did not save to Keychain")
} else {
Expand All @@ -177,14 +177,14 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {
return
}

KeychainWrapper.defaultKeychainWrapper.set(testData, forKey: testKey)
KeychainWrapper.standard.set(testData, forKey: testKey)

guard let retrievedData = KeychainWrapper.defaultKeychainWrapper.data(forKey: testKey) else {
guard let retrievedData = KeychainWrapper.standard.data(forKey: testKey) else {
XCTFail("Data for Key not found")
return
}

if KeychainWrapper.defaultKeychainWrapper.dataRef(forKey: testKey) == nil {
if KeychainWrapper.standard.dataRef(forKey: testKey) == nil {
XCTFail("Data references for Key not found")
}

Expand All @@ -196,10 +196,10 @@ class KeychainWrapperDefaultWrapperTests: XCTestCase {
}

func testDataRetrievalWhenValueDoesNotExist() {
let retrievedData = KeychainWrapper.defaultKeychainWrapper.data(forKey: testKey)
let retrievedData = KeychainWrapper.standard.data(forKey: testKey)
XCTAssertNil(retrievedData, "Data for Key should not exist")

let retrievedDataRef = KeychainWrapper.defaultKeychainWrapper.dataRef(forKey: testKey)
let retrievedDataRef = KeychainWrapper.standard.dataRef(forKey: testKey)
XCTAssertNil(retrievedDataRef, "Data ref for Key should not exist")
}
}
12 changes: 6 additions & 6 deletions SwiftKeychainWrapperTests/KeychainWrapperDeleteTests.swift
Expand Up @@ -25,37 +25,37 @@ class KeychainWrapperDeleteTests: XCTestCase {

func testRemoveAllKeysDeletesSpecificKey() {
// save a value we can test delete on
let stringSaved = KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
let stringSaved = KeychainWrapper.standard.set(testString, forKey: testKey)

XCTAssertTrue(stringSaved, "String did not save to Keychain")

// delete all
let removeSuccessful = KeychainWrapper.defaultKeychainWrapper.removeAllKeys()
let removeSuccessful = KeychainWrapper.standard.removeAllKeys()

XCTAssertTrue(removeSuccessful, "Failed to remove all Keys")

// confirm our test value was deleted
let retrievedValue = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey)
let retrievedValue = KeychainWrapper.standard.string(forKey: testKey)

XCTAssertNil(retrievedValue, "Test value was not deleted")
}

func testWipeKeychainDeletesSpecificKey() {
// save a value we can test delete on
let stringSaved = KeychainWrapper.defaultKeychainWrapper.set(testString, forKey: testKey)
let stringSaved = KeychainWrapper.standard.set(testString, forKey: testKey)

XCTAssertTrue(stringSaved, "String did not save to Keychain")

// delete all
KeychainWrapper.wipeKeychain()

// confirm our test value was deleted
let retrievedValue = KeychainWrapper.defaultKeychainWrapper.string(forKey: testKey)
let retrievedValue = KeychainWrapper.standard.string(forKey: testKey)

XCTAssertNil(retrievedValue, "Test value was not deleted")

// clean up keychain
KeychainWrapper.defaultKeychainWrapper.remove(key: testKey)
KeychainWrapper.standard.removeObject(forKey: testKey)
}

func testRemoveAllKeysOnlyRemovesKeysForCurrentServiceName() {
Expand Down

0 comments on commit 048a978

Please sign in to comment.