Skip to content

Commit 48da359

Browse files
committed
refactor keychain deletion logic for completeness
Introduces a private helper method to handle keychain deletions, ensuring items are removed regardless of synchronizable state or accessibility constraints. This improves reliability when deleting specific keys or all items.
1 parent 87dca4c commit 48da359

File tree

1 file changed

+43
-12
lines changed
  • flutter_secure_storage_darwin/darwin/flutter_secure_storage_darwin/Sources/flutter_secure_storage_darwin

1 file changed

+43
-12
lines changed

flutter_secure_storage_darwin/darwin/flutter_secure_storage_darwin/Sources/flutter_secure_storage_darwin/FlutterSecureStorage.swift

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -338,26 +338,57 @@ class FlutterSecureStorage {
338338

339339
/// Deletes an item from the keychain.
340340
internal func delete(params: KeychainQueryParameters) -> FlutterSecureStorageResponse {
341-
let query = baseQuery(from: params)
342-
let status = SecItemDelete(query as CFDictionary)
343-
// Return nil if nothing is found
344-
if (status == errSecItemNotFound) {
345-
return FlutterSecureStorageResponse(status: errSecSuccess, value: nil)
346-
}
347-
return FlutterSecureStorageResponse(status: status, value: nil)
341+
return performDelete(params: params, clearKey: false)
348342
}
349343

350344
/// Deletes all items matching the query parameters.
351345
internal func deleteAll(params: KeychainQueryParameters) -> FlutterSecureStorageResponse {
352-
let query = baseQuery(from: params)
353-
let status = SecItemDelete(query as CFDictionary)
354-
// Return nil if nothing is found
355-
if (status == errSecItemNotFound) {
346+
return performDelete(params: params, clearKey: true)
347+
}
348+
349+
/// Private helper method to perform keychain deletion.
350+
/// Attempts to delete items with both synchronizable states and without accessibility constraints
351+
/// to ensure complete removal regardless of how items were originally stored.
352+
///
353+
/// - Parameters:
354+
/// - params: The keychain query parameters
355+
/// - clearKey: If true, removes the key constraint to delete all items; if false, deletes specific key
356+
/// - Returns: Response indicating success or failure of the deletion operation
357+
private func performDelete(params: KeychainQueryParameters, clearKey: Bool) -> FlutterSecureStorageResponse {
358+
func deleteFromKeychain(withSynchronizable synchronizable: Bool?) -> OSStatus {
359+
var modifiedParams = params
360+
361+
if clearKey {
362+
modifiedParams.key = nil
363+
}
364+
365+
modifiedParams.isSynchronizable = synchronizable
366+
modifiedParams.accessibilityLevel = nil
367+
modifiedParams.accessControlFlags = nil
368+
369+
let query = baseQuery(from: modifiedParams)
370+
return SecItemDelete(query as CFDictionary)
371+
}
372+
373+
let statusSync = deleteFromKeychain(withSynchronizable: true)
374+
let statusNonSync = deleteFromKeychain(withSynchronizable: false)
375+
376+
// Return success if both operations report item not found
377+
if statusSync == errSecItemNotFound && statusNonSync == errSecItemNotFound {
356378
return FlutterSecureStorageResponse(status: errSecSuccess, value: nil)
357379
}
380+
381+
// Return success if either operation succeeded
382+
if statusSync == errSecSuccess || statusNonSync == errSecSuccess {
383+
return FlutterSecureStorageResponse(status: errSecSuccess, value: nil)
384+
}
385+
386+
// Return the first error encountered
387+
let status = statusSync != errSecItemNotFound ? statusSync : statusNonSync
388+
358389
return FlutterSecureStorageResponse(status: status, value: nil)
359390
}
360-
391+
361392
internal func getPersistentReference(params: KeychainQueryParameters) -> FlutterSecureStorageResponse {
362393
var query = baseQuery(from: params)
363394
query[kSecReturnPersistentRef] = true

0 commit comments

Comments
 (0)