Browse Source

Add synchronizable

Evgenii Neumerzhitckii 9 years ago
parent
commit
46838c80b3

+ 29 - 3
Distrib/KeychainSwiftDistrib.swift

@@ -37,6 +37,15 @@ public class KeychainSwift {
   */
   public var accessGroup: String?
   
+  
+  /**
+   
+  Specifies whether the items can be synchronized with other devices. Setting this property to true will
+   add the item to other devices with the `set` method, obtain synchronizable items with `get` command. Deleting synchronizable items will remove them from all devices.
+   
+  */
+  public var synchronizable: Bool = false
+  
   /// Instantiate a KeychainSwift object
   public init() { }
   
@@ -61,7 +70,7 @@ public class KeychainSwift {
 
   */
   public func set(value: String, forKey key: String,
-    withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool {
+                  withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool {
     
     if let value = value.dataUsingEncoding(NSUTF8StringEncoding) {
       return set(value, forKey: key, withAccess: access)
@@ -98,6 +107,7 @@ public class KeychainSwift {
     ]
       
     query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query)
     lastQueryParameters = query
     
     lastResultCode = SecItemAdd(query as CFDictionaryRef, nil)
@@ -159,9 +169,11 @@ public class KeychainSwift {
       KeychainSwiftConstants.klass       : kSecClassGenericPassword,
       KeychainSwiftConstants.attrAccount : prefixedKey,
       KeychainSwiftConstants.returnData  : kCFBooleanTrue,
-      KeychainSwiftConstants.matchLimit  : kSecMatchLimitOne ]
+      KeychainSwiftConstants.matchLimit  : kSecMatchLimitOne
+    ]
     
     query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query)
     lastQueryParameters = query
     
     var result: AnyObject?
@@ -203,9 +215,11 @@ public class KeychainSwift {
 
     var query: [String: NSObject] = [
       KeychainSwiftConstants.klass       : kSecClassGenericPassword,
-      KeychainSwiftConstants.attrAccount : prefixedKey ]
+      KeychainSwiftConstants.attrAccount : prefixedKey
+    ]
     
     query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query)
     lastQueryParameters = query
     
     lastResultCode = SecItemDelete(query as CFDictionaryRef)
@@ -223,6 +237,7 @@ public class KeychainSwift {
   public func clear() -> Bool {
     var query: [String: NSObject] = [ kSecClass as String : kSecClassGenericPassword ]
     query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query)
     lastQueryParameters = query
     
     lastResultCode = SecItemDelete(query as CFDictionaryRef)
@@ -242,6 +257,14 @@ public class KeychainSwift {
     result[KeychainSwiftConstants.accessGroup] = accessGroup
     return result
   }
+  
+  /// Adds kSecAttrSynchronizable: kSecAttrSynchronizableAny` item to the dictionary when the `synchronizable` property is true.
+  func addSynchronizableIfRequired(items: [String: NSObject]) -> [String: NSObject] {
+    if !synchronizable { return items }
+    var result: [String: NSObject] = items
+    result[KeychainSwiftConstants.attrSynchronizable] = kSecAttrSynchronizableAny
+    return result
+  }
 }
 
 
@@ -383,6 +406,9 @@ public struct KeychainSwiftConstants {
   
   /// Used for specifying a String key when setting/getting a Keychain value.
   public static var attrAccount: String { return toString(kSecAttrAccount) }
+
+  /// Used for specifying synchronization of keychain items between devices.
+  public static var attrSynchronizable: String { return toString(kSecAttrSynchronizable) }
   
   /// An item class key used to construct a Keychain search dictionary.
   public static var klass: String { return toString(kSecClass) }

+ 1 - 1
KeychainSwift/KeychainSwift.swift

@@ -243,7 +243,7 @@ public class KeychainSwift {
     return result
   }
   
-  /// Adds kSecAttrSynchronizable: kSecAttrSynchronizableAny items to the dictionary when the `synchronizable` property is true.
+  /// Adds kSecAttrSynchronizable: kSecAttrSynchronizableAny` item to the dictionary when the `synchronizable` property is true.
   func addSynchronizableIfRequired(items: [String: NSObject]) -> [String: NSObject] {
     if !synchronizable { return items }
     var result: [String: NSObject] = items

+ 28 - 0
KeychainSwiftTests/SynchronizableTests.swift

@@ -40,17 +40,33 @@ class SynchronizableTests: XCTestCase {
     XCTAssertEqual("two", result["one"])
   }
   
+  // MARK: - Set
+  
   func testSet() {
     obj.synchronizable = true
     obj.set("hello :)", forKey: "key 1")
     XCTAssertEqual(kSecAttrSynchronizableAny, obj.lastQueryParameters?["sync"])
   }
   
+  func testSet_doNotSetSynchronizable() {
+    obj.set("hello :)", forKey: "key 1")
+    XCTAssertNil(obj.lastQueryParameters?["sync"])
+  }
+  
+  // MARK: - Get
+  
   func testGet() {
     obj.synchronizable = true
     obj.get("key 1")
     XCTAssertEqual(kSecAttrSynchronizableAny, obj.lastQueryParameters?["sync"])
   }
+  
+  func testGet_doNotSetSynchronizable() {
+    obj.get("key 1")
+    XCTAssertNil(obj.lastQueryParameters?["sync"])
+  }
+  
+  // MARK: - Delete
 
   func testDelete() {
     obj.synchronizable = true
@@ -58,9 +74,21 @@ class SynchronizableTests: XCTestCase {
     XCTAssertEqual(kSecAttrSynchronizableAny, obj.lastQueryParameters?["sync"])
   }
   
+  func testDelete_doNotSetSynchronizable() {
+    obj.delete("key 1")
+    XCTAssertNil(obj.lastQueryParameters?["sync"])
+  }
+  
+  // MARK: - Clear
+  
   func testClear() {
     obj.synchronizable = true
     obj.clear()
     XCTAssertEqual(kSecAttrSynchronizableAny, obj.lastQueryParameters?["sync"])
   }
+  
+  func testClear_doNotSetSynchronizable() {
+    obj.clear()
+    XCTAssertNil(obj.lastQueryParameters?["sync"])
+  }
 }