فهرست منبع

Merge branch 'lucasmpaim-master'

Evgenii Neumerzhitckii 6 سال پیش
والد
کامیت
96fb84f45a

+ 5 - 0
CHANGELOG.md

@@ -1,6 +1,11 @@
 # KeychainSwift version history
 
 
+## 19.0.0 (2020-01-04)
+
+Added `allKeys` property that returns all key names ([lucasmpaim](https://github.com/lucasmpaim)).
+
+
 ## 18.0.0 (2019-11-03)
 
 Removed deprecated `kSecAttrAccessibleAlways` and `kSecAttrAccessibleAlwaysThisDeviceOnly` access options (https://github.com/evgenyneu/keychain-swift/pull/122).

+ 42 - 4
Distrib/KeychainSwiftDistrib.swift

@@ -100,7 +100,7 @@ open class KeychainSwift {
   open func set(_ value: Data, forKey key: String,
     withAccess access: KeychainSwiftAccessOptions? = nil) -> Bool {
     
-    // The lock prevents the code to be run simlultaneously
+    // The lock prevents the code to be run simultaneously
     // from multiple threads which may result in crashing
     lock.lock()
     defer { lock.unlock() }
@@ -179,7 +179,7 @@ open class KeychainSwift {
   
   */
   open func getData(_ key: String, asReference: Bool = false) -> Data? {
-    // The lock prevents the code to be run simlultaneously
+    // The lock prevents the code to be run simultaneously
     // from multiple threads which may result in crashing
     lock.lock()
     defer { lock.unlock() }
@@ -239,7 +239,7 @@ open class KeychainSwift {
   */
   @discardableResult
   open func delete(_ key: String) -> Bool {
-    // The lock prevents the code to be run simlultaneously
+    // The lock prevents the code to be run simultaneously
     // from multiple threads which may result in crashing
     lock.lock()
     defer { lock.unlock() }
@@ -247,6 +247,38 @@ open class KeychainSwift {
     return deleteNoLock(key)
   }
   
+  /**
+  Return all keys from keychain
+   
+  - returns: An string array with all keys from the keychain.
+   
+  */
+  public var allKeys: [String] {
+    var query: [String: Any] = [
+      KeychainSwiftConstants.klass : kSecClassGenericPassword,
+      KeychainSwiftConstants.returnData : true,
+      KeychainSwiftConstants.returnAttributes: true,
+      KeychainSwiftConstants.returnReference: true,
+      KeychainSwiftConstants.matchLimit: KeychainSwiftConstants.secMatchLimitAll
+    ]
+  
+    query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query, addingItems: false)
+
+    var result: AnyObject?
+
+    let lastResultCode = withUnsafeMutablePointer(to: &result) {
+      SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
+    }
+    
+    if lastResultCode == noErr {
+      return (result as? [[String: Any]])?.compactMap {
+        $0[KeychainSwiftConstants.attrAccount] as? String } ?? []
+    }
+    
+    return []
+  }
+    
   /**
    
   Same as `delete` but is only accessed internally, since it is not thread safe.
@@ -282,7 +314,7 @@ open class KeychainSwift {
   */
   @discardableResult
   open func clear() -> Bool {
-    // The lock prevents the code to be run simlultaneously
+    // The lock prevents the code to be run simultaneously
     // from multiple threads which may result in crashing
     lock.lock()
     defer { lock.unlock() }
@@ -371,6 +403,12 @@ public struct KeychainSwiftConstants {
   /// Used for returning a reference to the data from the keychain
   public static var returnReference: String { return toString(kSecReturnPersistentRef) }
   
+  /// A key whose value is a Boolean indicating whether or not to return item attributes
+  public static var returnAttributes : String { return toString(kSecReturnAttributes) }
+    
+  /// A value that corresponds to matching an unlimited number of items
+  public static var secMatchLimitAll : String { return toString(kSecMatchLimitAll) }
+    
   static func toString(_ value: CFString) -> String {
     return value as String
   }

+ 1 - 1
KeychainSwift.podspec

@@ -1,6 +1,6 @@
 Pod::Spec.new do |s|
   s.name        = "KeychainSwift"
-  s.version     = "18.0.0"
+  s.version     = "19.0.0"
   s.license     = { :type => "MIT" }
   s.homepage    = "https://github.com/evgenyneu/keychain-swift"
   s.summary     = "A library for saving text and data in the Keychain with Swift."

+ 6 - 0
KeychainSwift.xcodeproj/project.pbxproj

@@ -50,6 +50,8 @@
 		7ED6C9C01B1C13AA00FE8090 /* KeychainSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7ED6C96C1B1C118F00FE8090 /* KeychainSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		7EE5B9A11E32F6D400AA56FF /* KeychainSwiftCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7EE5B9A01E32F6D400AA56FF /* KeychainSwiftCBridge.swift */; };
 		C7E1DE4C1E4B7C9F003818F6 /* ConcurrencyTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7E1DE4A1E4B7C9F003818F6 /* ConcurrencyTests.swift */; };
+		F271A1AE23BE071800FCC3B9 /* AllKeysTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F271A1AD23BE071800FCC3B9 /* AllKeysTests.swift */; };
+		F271A1AF23BE082500FCC3B9 /* AllKeysTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = F271A1AD23BE071800FCC3B9 /* AllKeysTests.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -155,6 +157,7 @@
 		7ED6C9C91B1C16EE00FE8090 /* KeychainSwiftDistrib.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainSwiftDistrib.swift; sourceTree = "<group>"; };
 		7EE5B9A01E32F6D400AA56FF /* KeychainSwiftCBridge.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainSwiftCBridge.swift; sourceTree = "<group>"; };
 		C7E1DE4A1E4B7C9F003818F6 /* ConcurrencyTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConcurrencyTests.swift; sourceTree = "<group>"; };
+		F271A1AD23BE071800FCC3B9 /* AllKeysTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AllKeysTests.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
@@ -232,6 +235,7 @@
 				508566961FA34EB1004208ED /* KeychainSwiftTests.swift */,
 				508566971FA34EB1004208ED /* macOS Tests */,
 				5085669A1FA34EB1004208ED /* SynchronizableTests.swift */,
+				F271A1AD23BE071800FCC3B9 /* AllKeysTests.swift */,
 			);
 			path = KeychainSwiftTests;
 			sourceTree = "<group>";
@@ -743,6 +747,7 @@
 			buildActionMask = 2147483647;
 			files = (
 				508566AA1FA34EB1004208ED /* SynchronizableTests.swift in Sources */,
+				F271A1AF23BE082500FCC3B9 /* AllKeysTests.swift in Sources */,
 				508566A41FA34EB1004208ED /* KeychainSwiftTests.swift in Sources */,
 				508566A21FA34EB1004208ED /* KeychainSwiftPrefixedTests.swift in Sources */,
 				508566A81FA34EB1004208ED /* macOS_Tests.swift in Sources */,
@@ -782,6 +787,7 @@
 				5085669B1FA34EB1004208ED /* AccessGroupTests.swift in Sources */,
 				7ED6C9981B1C12B500FE8090 /* TegKeychainConstants.swift in Sources */,
 				5085669D1FA34EB1004208ED /* ClearTests.swift in Sources */,
+				F271A1AE23BE071800FCC3B9 /* AllKeysTests.swift in Sources */,
 				508566A31FA34EB1004208ED /* KeychainSwiftTests.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;

+ 10 - 3
README.md

@@ -37,7 +37,7 @@ Simply add [KeychainSwiftDistrib.swift](https://github.com/evgenyneu/keychain-sw
 
 #### Setup with Carthage (iOS 8+)
 
-Alternatively, add `github "evgenyneu/keychain-swift" ~> 18.0` to your Cartfile and run `carthage update`.
+Alternatively, add `github "evgenyneu/keychain-swift" ~> 19.0` to your Cartfile and run `carthage update`.
 
 #### Setup with CocoaPods (iOS 8+)
 
@@ -45,7 +45,7 @@ If you are using CocoaPods add this text to your Podfile and run `pod install`.
 
     use_frameworks!
     target 'Your target name'
-    pod 'KeychainSwift', '~> 18.0'
+    pod 'KeychainSwift', '~> 19.0'
 
 
 #### Setup with Swift Package Manager
@@ -95,8 +95,14 @@ keychain.delete("my key") // Remove single key
 keychain.clear() // Delete everything from app's Keychain. Does not work on macOS.
 ```
 
-## Advanced options
+#### Return all keys
+
+```Swift
+let keychain = KeychainSwift()
+keychain.allKeys // Returns the names of all keys
+```
 
+## Advanced options
 
 <h3 id="keychain_item_access">Keychain item access</h3>
 
@@ -244,6 +250,7 @@ Here are some other Keychain libraries.
 * Thanks to [mediym41](https://github.com/mediym41) for adding ability to return data as reference.
 * Thanks to [AnthonyOliveri](https://github.com/AnthonyOliveri) for adding ability to run unit tests from Swift Package Manager.
 * Thanks to [philippec](https://github.com/philippec) for removing deprecated access options.
+* Thanks to [lucasmpaim](https://github.com/lucasmpaim) for adding ability to return the names of all keys.
 
 
 

+ 32 - 0
Sources/KeychainSwift.swift

@@ -232,6 +232,38 @@ open class KeychainSwift {
     return deleteNoLock(key)
   }
   
+  /**
+  Return all keys from keychain
+   
+  - returns: An string array with all keys from the keychain.
+   
+  */
+  public var allKeys: [String] {
+    var query: [String: Any] = [
+      KeychainSwiftConstants.klass : kSecClassGenericPassword,
+      KeychainSwiftConstants.returnData : true,
+      KeychainSwiftConstants.returnAttributes: true,
+      KeychainSwiftConstants.returnReference: true,
+      KeychainSwiftConstants.matchLimit: KeychainSwiftConstants.secMatchLimitAll
+    ]
+  
+    query = addAccessGroupWhenPresent(query)
+    query = addSynchronizableIfRequired(query, addingItems: false)
+
+    var result: AnyObject?
+
+    let lastResultCode = withUnsafeMutablePointer(to: &result) {
+      SecItemCopyMatching(query as CFDictionary, UnsafeMutablePointer($0))
+    }
+    
+    if lastResultCode == noErr {
+      return (result as? [[String: Any]])?.compactMap {
+        $0[KeychainSwiftConstants.attrAccount] as? String } ?? []
+    }
+    
+    return []
+  }
+    
   /**
    
   Same as `delete` but is only accessed internally, since it is not thread safe.

+ 6 - 0
Sources/TegKeychainConstants.swift

@@ -34,6 +34,12 @@ public struct KeychainSwiftConstants {
   /// Used for returning a reference to the data from the keychain
   public static var returnReference: String { return toString(kSecReturnPersistentRef) }
   
+  /// A key whose value is a Boolean indicating whether or not to return item attributes
+  public static var returnAttributes : String { return toString(kSecReturnAttributes) }
+    
+  /// A value that corresponds to matching an unlimited number of items
+  public static var secMatchLimitAll : String { return toString(kSecMatchLimitAll) }
+    
   static func toString(_ value: CFString) -> String {
     return value as String
   }

+ 40 - 0
Tests/KeychainSwiftTests/AllKeysTests.swift

@@ -0,0 +1,40 @@
+//
+//  AllKeysTests.swift
+//  KeychainSwiftTests
+//
+//  Created by Lucas Paim on 02/01/20.
+//  Copyright © 2020 Evgenii Neumerzhitckii. All rights reserved.
+//
+
+import XCTest
+@testable import KeychainSwift
+
+
+class AllKeysTests: XCTestCase {
+  
+  var obj: KeychainSwift!
+  
+  override func setUp() {
+    super.setUp()
+    
+    obj = KeychainSwift()
+    obj.clear()
+  }
+  
+  // MARK: - allKeys
+  func testAddSynchronizableGroup_addItemsFalse() {
+    let items: [String] = [
+      "one", "two"
+    ]
+    
+    items.enumerated().forEach { enumerator in
+        self.obj!.set("\(enumerator.offset)", forKey: enumerator.element)
+    }
+    
+    XCTAssertEqual(["one", "two"], obj.allKeys)
+    
+    obj.clear()
+    XCTAssertEqual(obj.allKeys, [])
+    
+  }
+}