@@ -226,6 +226,51 @@ - (NSString *)messageForError:(NSError *)error
226226 });
227227}
228228
229+ RCT_EXPORT_METHOD (hasItem:(NSString *)key options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){
230+ NSString * keychainService = [RCTConvert NSString: options[@" keychainService" ]];
231+ if (keychainService == NULL ) {
232+ keychainService = @" app" ;
233+ }
234+
235+ // Create dictionary of search parameters
236+ NSMutableDictionary * query = [NSMutableDictionary dictionaryWithObjectsAndKeys: (__bridge id )(kSecClassGenericPassword ), kSecClass ,
237+ keychainService, kSecAttrService ,
238+ key, kSecAttrAccount ,
239+ kSecAttrSynchronizableAny , kSecAttrSynchronizable ,
240+ kCFBooleanTrue , kSecReturnAttributes ,
241+ kCFBooleanTrue , kSecReturnData ,
242+ nil ];
243+
244+
245+ dispatch_async (dispatch_get_main_queue (), ^{
246+ if (UIApplication.sharedApplication .protectedDataAvailable ) {
247+ // Look up server in the keychain
248+ NSDictionary * found = nil ;
249+ CFTypeRef foundTypeRef = NULL ;
250+ OSStatus osStatus = SecItemCopyMatching ((__bridge CFDictionaryRef) query, (CFTypeRef*)&foundTypeRef);
251+
252+ if (osStatus != noErr && osStatus != errSecItemNotFound) {
253+ NSError *error = [NSError errorWithDomain: NSOSStatusErrorDomain code: osStatus userInfo: nil ];
254+ reject ([NSString stringWithFormat: @" %ld " ,(long )error.code], [self messageForError: error], nil );
255+ return ;
256+ }
257+
258+ found = (__bridge NSDictionary *)(foundTypeRef);
259+ if (!found) {
260+ resolve (@(FALSE ));
261+ } else {
262+ // Found
263+ resolve (@(TRUE ));
264+ }
265+ } else {
266+ // TODO: could change to instead of erroring out, listen for protectedDataDidBecomeAvailable and call getItemWIthQuery when it does
267+ // Experiment for now by returning an error and let the js side retry
268+ reject (@" protected_data_unavailable" , @" Protected data not available yet. Retry operation" , nil );
269+ }
270+ });
271+ }
272+
273+
229274- (void )getItemWithQuery : (NSDictionary *)query resolver : (RCTPromiseResolveBlock)resolve rejecter : (RCTPromiseRejectBlock)reject {
230275 // Look up server in the keychain
231276 NSDictionary * found = nil ;
@@ -245,7 +290,6 @@ - (void)getItemWithQuery:(NSDictionary *)query resolver:(RCTPromiseResolveBlock)
245290 // Found
246291 NSString * value = [[NSString alloc ] initWithData: [found objectForKey: (__bridge id )(kSecValueData )] encoding: NSUTF8StringEncoding];
247292 resolve (value);
248-
249293 }
250294}
251295
0 commit comments