Skip to content

Commit f30fcab

Browse files
fix: dynamic_pointer_cast for HybridStorage weak_ptr + replace deprecated kSecUseAuthenticationUIFail
- Use dynamic_pointer_cast instead of static_pointer_cast when capturing shared_from_this() as weak_ptr<HybridStorage> — required because HybridObject is a virtual base class and static_pointer_cast is ill-formed in that case. - Replace all 6 usages of kSecUseAuthenticationUIFail (deprecated iOS 14) with a disableKeychainInteraction() helper using LAContext.interactionNotAllowed=YES + kSecUseAuthenticationContext to suppress auth prompts without deprecated API.
1 parent f1b4894 commit f30fcab

2 files changed

Lines changed: 16 additions & 8 deletions

File tree

packages/react-native-nitro-storage/cpp/bindings/HybridStorage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,7 @@ std::function<void()> HybridStorage::addOnChange(
277277
listeners_[intScope].push_back({listenerId, callback});
278278
}
279279

280-
std::weak_ptr<HybridStorage> weakSelf = std::static_pointer_cast<HybridStorage>(shared_from_this());
280+
std::weak_ptr<HybridStorage> weakSelf = std::dynamic_pointer_cast<HybridStorage>(shared_from_this());
281281
return [weakSelf, intScope, listenerId]() {
282282
auto self = weakSelf.lock();
283283
if (!self) return; // HybridStorage was destroyed — safe no-op

packages/react-native-nitro-storage/ios/IOSStorageAdapterCpp.mm

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,14 @@
1616
return defaults ?: [NSUserDefaults standardUserDefaults];
1717
}
1818

19+
// Prevents the Keychain from showing auth UI. On iOS 14+ kSecUseAuthenticationUIFail is
20+
// deprecated; the correct replacement is an LAContext with interactionNotAllowed = YES.
21+
static void disableKeychainInteraction(NSMutableDictionary* query) {
22+
LAContext* ctx = [[LAContext alloc] init];
23+
ctx.interactionNotAllowed = YES;
24+
query[(__bridge id)kSecUseAuthenticationContext] = ctx;
25+
}
26+
1927
static CFStringRef accessControlAttr(int level) {
2028
switch (level) {
2129
case 1: return kSecAttrAccessibleAfterFirstUnlock;
@@ -178,7 +186,7 @@ static CFStringRef accessControlAttr(int level) {
178186

179187
static std::vector<std::string> keychainAccountsForService(NSString* service, NSString* accessGroup) {
180188
NSMutableDictionary* query = allAccountsQuery(service, accessGroup);
181-
query[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
189+
disableKeychainInteraction(query);
182190
CFTypeRef result = NULL;
183191
std::vector<std::string> keys;
184192
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
@@ -274,7 +282,7 @@ static CFStringRef accessControlAttr(int level) {
274282
NSMutableDictionary* query = baseKeychainQuery(nsKey, kKeychainService, group);
275283
query[(__bridge id)kSecReturnData] = @YES;
276284
query[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
277-
query[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
285+
disableKeychainInteraction(query);
278286

279287
CFTypeRef result = NULL;
280288
OSStatus status = SecItemCopyMatching((__bridge CFDictionaryRef)query, &result);
@@ -334,12 +342,12 @@ static CFStringRef accessControlAttr(int level) {
334342
}
335343
NSString* group = groupStr.empty() ? nil : [NSString stringWithUTF8String:groupStr.c_str()];
336344
NSMutableDictionary* secureQuery = baseKeychainQuery(nsKey, kKeychainService, group);
337-
secureQuery[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
345+
disableKeychainInteraction(secureQuery);
338346
if (SecItemCopyMatching((__bridge CFDictionaryRef)secureQuery, NULL) == errSecSuccess) {
339347
return true;
340348
}
341349
NSMutableDictionary* biometricQuery = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
342-
biometricQuery[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
350+
disableKeychainInteraction(biometricQuery);
343351
return SecItemCopyMatching((__bridge CFDictionaryRef)biometricQuery, NULL) == errSecSuccess;
344352
}
345353

@@ -484,13 +492,13 @@ static CFStringRef accessControlAttr(int level) {
484492
}
485493
NSString* group = groupStr.empty() ? nil : [NSString stringWithUTF8String:groupStr.c_str()];
486494

487-
// Capture backup before delete — use kSecUseAuthenticationUIFail to avoid prompting
495+
// Capture backup before delete — must not prompt for auth
488496
std::optional<std::string> backup = std::nullopt;
489497
{
490498
NSMutableDictionary* backupQuery = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
491499
backupQuery[(__bridge id)kSecReturnData] = @YES;
492500
backupQuery[(__bridge id)kSecMatchLimit] = (__bridge id)kSecMatchLimitOne;
493-
backupQuery[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
501+
disableKeychainInteraction(backupQuery);
494502
CFTypeRef backupResult = NULL;
495503
if (SecItemCopyMatching((__bridge CFDictionaryRef)backupQuery, &backupResult) == errSecSuccess && backupResult) {
496504
NSData* bData = (__bridge_transfer NSData*)backupResult;
@@ -606,7 +614,7 @@ static CFStringRef accessControlAttr(int level) {
606614
}
607615
NSString* group = groupStr.empty() ? nil : [NSString stringWithUTF8String:groupStr.c_str()];
608616
NSMutableDictionary* query = baseKeychainQuery(nsKey, kBiometricKeychainService, group);
609-
query[(__bridge id)kSecUseAuthenticationUI] = (__bridge id)kSecUseAuthenticationUIFail;
617+
disableKeychainInteraction(query);
610618
return SecItemCopyMatching((__bridge CFDictionaryRef)query, NULL) == errSecSuccess;
611619
}
612620

0 commit comments

Comments
 (0)