From 5d3065614d61f67e6097eb387da6f02cdac13d8d Mon Sep 17 00:00:00 2001 From: Laurie Marceau Date: Fri, 25 Nov 2022 13:35:11 -0500 Subject: [PATCH 1/3] Fix deprecation warnings And various minor code fixes --- .../KeychainItemAccessibility.swift | 17 +-- .../MZKeychain/KeychainWrapper.swift | 115 +++++++----------- 2 files changed, 51 insertions(+), 81 deletions(-) diff --git a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift index f35903909b..a34ee690c9 100644 --- a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift +++ b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift @@ -95,31 +95,22 @@ public enum MZKeychainItemAccessibility { case whenUnlockedThisDeviceOnly static func accessibilityForAttributeValue(_ keychainAttrValue: CFString) -> MZKeychainItemAccessibility? { - for (key, value) in keychainItemAccessibilityLookup { - if value == keychainAttrValue { - return key - } - } - return nil + keychainItemAccessibilityLookup.first { $0.value == keychainAttrValue }?.key } } private let keychainItemAccessibilityLookup: [MZKeychainItemAccessibility: CFString] = { - var lookup: [MZKeychainItemAccessibility: CFString] = [ + return [MZKeychainItemAccessibility: CFString] = [ .afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock, .afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, - .always: kSecAttrAccessibleAlways, .whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, - .alwaysThisDeviceOnly: kSecAttrAccessibleAlwaysThisDeviceOnly, .whenUnlocked: kSecAttrAccessibleWhenUnlocked, .whenUnlockedThisDeviceOnly: kSecAttrAccessibleWhenUnlockedThisDeviceOnly, ] - - return lookup }() extension MZKeychainItemAccessibility: MZKeychainAttrRepresentable { - internal var keychainAttrValue: CFString { - return keychainItemAccessibilityLookup[self]! + var keychainAttrValue: CFString { + keychainItemAccessibilityLookup[self]! } } diff --git a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift index cc1b00b8b5..fb1d7ef3db 100644 --- a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift +++ b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift @@ -57,9 +57,7 @@ open class MZKeychainWrapper { /// AccessGroup is used for the kSecAttrAccessGroup property to identify which Keychain Access Group this entry belongs to. This allows you to use the KeychainWrapper with shared keychain access between different applications. public private(set) var accessGroup: String? - private static let defaultServiceName: String = { - Bundle.main.bundleIdentifier ?? "SwiftKeychainWrapper" - }() + private static let defaultServiceName = Bundle.main.bundleIdentifier ?? "SwiftKeychainWrapper" private convenience init() { self.init(serviceName: MZKeychainWrapper.defaultServiceName) @@ -83,11 +81,7 @@ open class MZKeychainWrapper { /// - parameter isSynchronizable: A bool that describes if the item should be synchronizable, to be synched with the iCloud. If none is provided, will default to false /// - returns: True if a value exists for the key. False otherwise. open func hasValue(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - if let _ = data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) { - return true - } else { - return false - } + data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) != nil } open func accessibilityOfKey(_ key: String) -> MZKeychainItemAccessibility? { @@ -109,7 +103,7 @@ open class MZKeychainWrapper { return nil } - return MZKeychainItemAccessibility.accessibilityForAttributeValue(accessibilityAttrValue as CFString) + return .accessibilityForAttributeValue(accessibilityAttrValue as CFString) } /// Get the keys of all keychain entries matching the current ServiceName and AccessGroup if one is set. @@ -150,35 +144,31 @@ open class MZKeychainWrapper { // MARK: Public Getters open func integer(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Int? { - guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else { - return nil - } - - return numberValue.intValue + return object(forKey: key, + ofClass: NSNumber.self, + withAccessibility: accessibility, + isSynchronizable: isSynchronizable)?.intValue } open func float(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Float? { - guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else { - return nil - } - - return numberValue.floatValue + return object(forKey: key, + ofClass: NSNumber.self, + withAccessibility: accessibility, + isSynchronizable: isSynchronizable)?.floatValue } open func double(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Double? { - guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else { - return nil - } - - return numberValue.doubleValue + return object(forKey: key, + ofClass: NSNumber.self, + withAccessibility: accessibility, + isSynchronizable: isSynchronizable)?.doubleValue } open func bool(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool? { - guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else { - return nil - } - - return numberValue.boolValue + return object(forKey: key, + ofClass: NSNumber.self, + withAccessibility: accessibility, + isSynchronizable: isSynchronizable)?.boolValue } /// Returns a string value for a specified key. @@ -192,21 +182,26 @@ open class MZKeychainWrapper { return nil } - return String(data: keychainData, encoding: String.Encoding.utf8) as String? + return String(data: keychainData, encoding: .utf8) } /// Returns an object that conforms to NSCoding for a specified key. /// /// - parameter forKey: The key to lookup data for. + /// - parameter ofClass: The class type of the decoded object. /// - parameter withAccessibility: Optional accessibility to use when retrieving the keychain item. /// - parameter isSynchronizable: A bool that describes if the item should be synchronizable, to be synched with the iCloud. If none is provided, will default to false /// - returns: The decoded object associated with the key if it exists. If no data exists, or the data found cannot be decoded, returns nil. - open func object(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> NSCoding? { + open func object(forKey key: String, + ofClass cls: DecodedObjectType.Type, + withAccessibility accessibility: MZKeychainItemAccessibility? = nil, + isSynchronizable: Bool = false + ) -> DecodedObjectType? where DecodedObjectType : NSObject, DecodedObjectType : NSCoding { guard let keychainData = data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) else { return nil } - return NSKeyedUnarchiver.unarchiveObject(with: keychainData) as? NSCoding + return try? NSKeyedUnarchiver.unarchivedObject(ofClass: cls, from: keychainData) } /// Returns a Data object for a specified key. @@ -279,22 +274,25 @@ open class MZKeychainWrapper { /// - parameter isSynchronizable: A bool that describes if the item should be synchronizable, to be synched with the iCloud. If none is provided, will default to false /// - returns: True if the save was successful, false otherwise. @discardableResult open func set(_ value: String, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - if let data = value.data(using: .utf8) { - return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) - } else { - return false - } + guard let data = value.data(using: .utf8) else { return false } + return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } /// Save an NSCoding compliant object to the keychain associated with a specified key. If an object already exists for the given key, the object will be overwritten with the new value. /// - /// - parameter value: The NSCoding compliant object to save. + /// - parameter value: The NSSecureCoding compliant object to save. /// - parameter forKey: The key to save the object under. /// - parameter withAccessibility: Optional accessibility to use when setting the keychain item. /// - parameter isSynchronizable: A bool that describes if the item should be synchronizable, to be synched with the iCloud. If none is provided, will default to false /// - returns: True if the save was successful, false otherwise. - @discardableResult open func set(_ value: NSCoding, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - let data = NSKeyedArchiver.archivedData(withRootObject: value) + @discardableResult open func set(_ value: T, + forKey key: String, + withAccessibility accessibility: MZKeychainItemAccessibility? = nil, + isSynchronizable: Bool = false + ) -> Bool where T : NSSecureCoding { { + guard let data = try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true) else { + return false + } return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } @@ -318,7 +316,7 @@ open class MZKeychainWrapper { keychainQueryDictionary[SecAttrAccessible] = MZKeychainItemAccessibility.whenUnlocked.keychainAttrValue } - let status: OSStatus = SecItemAdd(keychainQueryDictionary as CFDictionary, nil) + let status = SecItemAdd(keychainQueryDictionary as CFDictionary, nil) if status == errSecSuccess { return true @@ -344,13 +342,8 @@ open class MZKeychainWrapper { let keychainQueryDictionary: [String: Any] = setupKeychainQueryDictionary(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) // Delete - let status: OSStatus = SecItemDelete(keychainQueryDictionary as CFDictionary) - - if status == errSecSuccess { - return true - } else { - return false - } + let status = SecItemDelete(keychainQueryDictionary as CFDictionary) + return status == errSecSuccess } /// Remove all keychain data added through KeychainWrapper. This will only delete items matching the currnt ServiceName and AccessGroup if one is set. @@ -366,13 +359,8 @@ open class MZKeychainWrapper { keychainQueryDictionary[SecAttrAccessGroup] = accessGroup } - let status: OSStatus = SecItemDelete(keychainQueryDictionary as CFDictionary) - - if status == errSecSuccess { - return true - } else { - return false - } + let status = SecItemDelete(keychainQueryDictionary as CFDictionary) + return status == errSecSuccess } /// Remove all keychain data, including data not added through keychain wrapper. /// @@ -393,12 +381,8 @@ open class MZKeychainWrapper { /// @discardableResult private class func deleteKeychainSecClass(_ secClass: AnyObject) -> Bool { let query = [SecClass: secClass] - let status: OSStatus = SecItemDelete(query as CFDictionary) - if status == errSecSuccess { - return true - } else { - return false - } + let status = SecItemDelete(query as CFDictionary) + return status == errSecSuccess } /// Update existing data associated with a specified key name. The existing data will be overwritten by the new data. @@ -411,13 +395,8 @@ open class MZKeychainWrapper { keychainQueryDictionary[SecAttrAccessible] = accessibility.keychainAttrValue } // Update - let status: OSStatus = SecItemUpdate(keychainQueryDictionary as CFDictionary, updateDictionary as CFDictionary) - - if status == errSecSuccess { - return true - } else { - return false - } + let status = SecItemUpdate(keychainQueryDictionary as CFDictionary, updateDictionary as CFDictionary) + return status == errSecSuccess } /// Setup the keychain query dictionary used to access the keychain on iOS for a specified key name. Takes into account the Service Name and Access Group if one is set. From ff88dbd028eea3ee65fa987f270ee6c958d535a4 Mon Sep 17 00:00:00 2001 From: Laurie Marceau Date: Fri, 25 Nov 2022 16:15:49 -0500 Subject: [PATCH 2/3] Fix build after being able to run it --- .../MZKeychain/KeychainItemAccessibility.swift | 2 +- .../ios/FxAClient/MZKeychain/KeychainWrapper.swift | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift index a34ee690c9..9b51c3012f 100644 --- a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift +++ b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift @@ -100,7 +100,7 @@ public enum MZKeychainItemAccessibility { } private let keychainItemAccessibilityLookup: [MZKeychainItemAccessibility: CFString] = { - return [MZKeychainItemAccessibility: CFString] = [ + return [ .afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock, .afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, .whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly, diff --git a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift index fb1d7ef3db..600d1f2b75 100644 --- a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift +++ b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift @@ -251,19 +251,19 @@ open class MZKeychainWrapper { // MARK: Public Setters @discardableResult open func set(_ value: Int, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) + return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } @discardableResult open func set(_ value: Float, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) + return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } @discardableResult open func set(_ value: Double, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) + return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } @discardableResult open func set(_ value: Bool, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool { - return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) + return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) } /// Save a String value to the keychain associated with a specified key. If a String value already exists for the given key, the string will be overwritten with the new value. @@ -289,7 +289,7 @@ open class MZKeychainWrapper { forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false - ) -> Bool where T : NSSecureCoding { { + ) -> Bool where T : NSSecureCoding { guard let data = try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true) else { return false } From a7c7c5d5bbeeee6d66a235a7a239657bf3553b52 Mon Sep 17 00:00:00 2001 From: Laurie Marceau Date: Fri, 25 Nov 2022 16:43:58 -0500 Subject: [PATCH 3/3] Fix swiftlint --- .../ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift index 9b51c3012f..ee51968de9 100644 --- a/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift +++ b/components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift @@ -100,7 +100,7 @@ public enum MZKeychainItemAccessibility { } private let keychainItemAccessibilityLookup: [MZKeychainItemAccessibility: CFString] = { - return [ + [ .afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock, .afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly, .whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,