Skip to content

Commit 0ce488e

Browse files
authored
Fix deprecation warnings in iOS Swift Keychain Wrapper code (#5259)
* Fix deprecation warnings And various minor code fixes * Fix build after being able to run it * Fix swiftlint
1 parent c4368db commit 0ce488e

2 files changed

Lines changed: 55 additions & 85 deletions

File tree

components/fxa-client/ios/FxAClient/MZKeychain/KeychainItemAccessibility.swift

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -95,31 +95,22 @@ public enum MZKeychainItemAccessibility {
9595
case whenUnlockedThisDeviceOnly
9696

9797
static func accessibilityForAttributeValue(_ keychainAttrValue: CFString) -> MZKeychainItemAccessibility? {
98-
for (key, value) in keychainItemAccessibilityLookup {
99-
if value == keychainAttrValue {
100-
return key
101-
}
102-
}
103-
return nil
98+
keychainItemAccessibilityLookup.first { $0.value == keychainAttrValue }?.key
10499
}
105100
}
106101

107102
private let keychainItemAccessibilityLookup: [MZKeychainItemAccessibility: CFString] = {
108-
var lookup: [MZKeychainItemAccessibility: CFString] = [
103+
[
109104
.afterFirstUnlock: kSecAttrAccessibleAfterFirstUnlock,
110105
.afterFirstUnlockThisDeviceOnly: kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,
111-
.always: kSecAttrAccessibleAlways,
112106
.whenPasscodeSetThisDeviceOnly: kSecAttrAccessibleWhenPasscodeSetThisDeviceOnly,
113-
.alwaysThisDeviceOnly: kSecAttrAccessibleAlwaysThisDeviceOnly,
114107
.whenUnlocked: kSecAttrAccessibleWhenUnlocked,
115108
.whenUnlockedThisDeviceOnly: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
116109
]
117-
118-
return lookup
119110
}()
120111

121112
extension MZKeychainItemAccessibility: MZKeychainAttrRepresentable {
122-
internal var keychainAttrValue: CFString {
123-
return keychainItemAccessibilityLookup[self]!
113+
var keychainAttrValue: CFString {
114+
keychainItemAccessibilityLookup[self]!
124115
}
125116
}

components/fxa-client/ios/FxAClient/MZKeychain/KeychainWrapper.swift

Lines changed: 51 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -57,9 +57,7 @@ open class MZKeychainWrapper {
5757
/// 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.
5858
public private(set) var accessGroup: String?
5959

60-
private static let defaultServiceName: String = {
61-
Bundle.main.bundleIdentifier ?? "SwiftKeychainWrapper"
62-
}()
60+
private static let defaultServiceName = Bundle.main.bundleIdentifier ?? "SwiftKeychainWrapper"
6361

6462
private convenience init() {
6563
self.init(serviceName: MZKeychainWrapper.defaultServiceName)
@@ -83,11 +81,7 @@ open class MZKeychainWrapper {
8381
/// - 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
8482
/// - returns: True if a value exists for the key. False otherwise.
8583
open func hasValue(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
86-
if let _ = data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) {
87-
return true
88-
} else {
89-
return false
90-
}
84+
data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) != nil
9185
}
9286

9387
open func accessibilityOfKey(_ key: String) -> MZKeychainItemAccessibility? {
@@ -109,7 +103,7 @@ open class MZKeychainWrapper {
109103
return nil
110104
}
111105

112-
return MZKeychainItemAccessibility.accessibilityForAttributeValue(accessibilityAttrValue as CFString)
106+
return .accessibilityForAttributeValue(accessibilityAttrValue as CFString)
113107
}
114108

115109
/// Get the keys of all keychain entries matching the current ServiceName and AccessGroup if one is set.
@@ -150,35 +144,31 @@ open class MZKeychainWrapper {
150144
// MARK: Public Getters
151145

152146
open func integer(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Int? {
153-
guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else {
154-
return nil
155-
}
156-
157-
return numberValue.intValue
147+
return object(forKey: key,
148+
ofClass: NSNumber.self,
149+
withAccessibility: accessibility,
150+
isSynchronizable: isSynchronizable)?.intValue
158151
}
159152

160153
open func float(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Float? {
161-
guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else {
162-
return nil
163-
}
164-
165-
return numberValue.floatValue
154+
return object(forKey: key,
155+
ofClass: NSNumber.self,
156+
withAccessibility: accessibility,
157+
isSynchronizable: isSynchronizable)?.floatValue
166158
}
167159

168160
open func double(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Double? {
169-
guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else {
170-
return nil
171-
}
172-
173-
return numberValue.doubleValue
161+
return object(forKey: key,
162+
ofClass: NSNumber.self,
163+
withAccessibility: accessibility,
164+
isSynchronizable: isSynchronizable)?.doubleValue
174165
}
175166

176167
open func bool(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool? {
177-
guard let numberValue = object(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) as? NSNumber else {
178-
return nil
179-
}
180-
181-
return numberValue.boolValue
168+
return object(forKey: key,
169+
ofClass: NSNumber.self,
170+
withAccessibility: accessibility,
171+
isSynchronizable: isSynchronizable)?.boolValue
182172
}
183173

184174
/// Returns a string value for a specified key.
@@ -192,21 +182,26 @@ open class MZKeychainWrapper {
192182
return nil
193183
}
194184

195-
return String(data: keychainData, encoding: String.Encoding.utf8) as String?
185+
return String(data: keychainData, encoding: .utf8)
196186
}
197187

198188
/// Returns an object that conforms to NSCoding for a specified key.
199189
///
200190
/// - parameter forKey: The key to lookup data for.
191+
/// - parameter ofClass: The class type of the decoded object.
201192
/// - parameter withAccessibility: Optional accessibility to use when retrieving the keychain item.
202193
/// - 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
203194
/// - returns: The decoded object associated with the key if it exists. If no data exists, or the data found cannot be decoded, returns nil.
204-
open func object(forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> NSCoding? {
195+
open func object<DecodedObjectType>(forKey key: String,
196+
ofClass cls: DecodedObjectType.Type,
197+
withAccessibility accessibility: MZKeychainItemAccessibility? = nil,
198+
isSynchronizable: Bool = false
199+
) -> DecodedObjectType? where DecodedObjectType : NSObject, DecodedObjectType : NSCoding {
205200
guard let keychainData = data(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable) else {
206201
return nil
207202
}
208203

209-
return NSKeyedUnarchiver.unarchiveObject(with: keychainData) as? NSCoding
204+
return try? NSKeyedUnarchiver.unarchivedObject(ofClass: cls, from: keychainData)
210205
}
211206

212207
/// Returns a Data object for a specified key.
@@ -256,19 +251,19 @@ open class MZKeychainWrapper {
256251
// MARK: Public Setters
257252

258253
@discardableResult open func set(_ value: Int, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
259-
return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
254+
return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
260255
}
261256

262257
@discardableResult open func set(_ value: Float, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
263-
return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
258+
return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
264259
}
265260

266261
@discardableResult open func set(_ value: Double, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
267-
return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
262+
return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
268263
}
269264

270265
@discardableResult open func set(_ value: Bool, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
271-
return set(Int(NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
266+
return set(Int(truncating: NSNumber(value: value)), forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
272267
}
273268

274269
/// 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.
@@ -279,22 +274,25 @@ open class MZKeychainWrapper {
279274
/// - 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
280275
/// - returns: True if the save was successful, false otherwise.
281276
@discardableResult open func set(_ value: String, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
282-
if let data = value.data(using: .utf8) {
283-
return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
284-
} else {
285-
return false
286-
}
277+
guard let data = value.data(using: .utf8) else { return false }
278+
return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
287279
}
288280

289281
/// 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.
290282
///
291-
/// - parameter value: The NSCoding compliant object to save.
283+
/// - parameter value: The NSSecureCoding compliant object to save.
292284
/// - parameter forKey: The key to save the object under.
293285
/// - parameter withAccessibility: Optional accessibility to use when setting the keychain item.
294286
/// - 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
295287
/// - returns: True if the save was successful, false otherwise.
296-
@discardableResult open func set(_ value: NSCoding, forKey key: String, withAccessibility accessibility: MZKeychainItemAccessibility? = nil, isSynchronizable: Bool = false) -> Bool {
297-
let data = NSKeyedArchiver.archivedData(withRootObject: value)
288+
@discardableResult open func set<T>(_ value: T,
289+
forKey key: String,
290+
withAccessibility accessibility: MZKeychainItemAccessibility? = nil,
291+
isSynchronizable: Bool = false
292+
) -> Bool where T : NSSecureCoding {
293+
guard let data = try? NSKeyedArchiver.archivedData(withRootObject: value, requiringSecureCoding: true) else {
294+
return false
295+
}
298296

299297
return set(data, forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
300298
}
@@ -318,7 +316,7 @@ open class MZKeychainWrapper {
318316
keychainQueryDictionary[SecAttrAccessible] = MZKeychainItemAccessibility.whenUnlocked.keychainAttrValue
319317
}
320318

321-
let status: OSStatus = SecItemAdd(keychainQueryDictionary as CFDictionary, nil)
319+
let status = SecItemAdd(keychainQueryDictionary as CFDictionary, nil)
322320

323321
if status == errSecSuccess {
324322
return true
@@ -344,13 +342,8 @@ open class MZKeychainWrapper {
344342
let keychainQueryDictionary: [String: Any] = setupKeychainQueryDictionary(forKey: key, withAccessibility: accessibility, isSynchronizable: isSynchronizable)
345343

346344
// Delete
347-
let status: OSStatus = SecItemDelete(keychainQueryDictionary as CFDictionary)
348-
349-
if status == errSecSuccess {
350-
return true
351-
} else {
352-
return false
353-
}
345+
let status = SecItemDelete(keychainQueryDictionary as CFDictionary)
346+
return status == errSecSuccess
354347
}
355348

356349
/// 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 {
366359
keychainQueryDictionary[SecAttrAccessGroup] = accessGroup
367360
}
368361

369-
let status: OSStatus = SecItemDelete(keychainQueryDictionary as CFDictionary)
370-
371-
if status == errSecSuccess {
372-
return true
373-
} else {
374-
return false
375-
}
362+
let status = SecItemDelete(keychainQueryDictionary as CFDictionary)
363+
return status == errSecSuccess
376364
}
377365
/// Remove all keychain data, including data not added through keychain wrapper.
378366
///
@@ -393,12 +381,8 @@ open class MZKeychainWrapper {
393381
///
394382
@discardableResult private class func deleteKeychainSecClass(_ secClass: AnyObject) -> Bool {
395383
let query = [SecClass: secClass]
396-
let status: OSStatus = SecItemDelete(query as CFDictionary)
397-
if status == errSecSuccess {
398-
return true
399-
} else {
400-
return false
401-
}
384+
let status = SecItemDelete(query as CFDictionary)
385+
return status == errSecSuccess
402386
}
403387

404388
/// 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 {
411395
keychainQueryDictionary[SecAttrAccessible] = accessibility.keychainAttrValue
412396
}
413397
// Update
414-
let status: OSStatus = SecItemUpdate(keychainQueryDictionary as CFDictionary, updateDictionary as CFDictionary)
415-
416-
if status == errSecSuccess {
417-
return true
418-
} else {
419-
return false
420-
}
398+
let status = SecItemUpdate(keychainQueryDictionary as CFDictionary, updateDictionary as CFDictionary)
399+
return status == errSecSuccess
421400
}
422401

423402
/// 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.

0 commit comments

Comments
 (0)