Skip to content

Commit 1608d5b

Browse files
committed
Merge remote-tracking branch 'origin/master'
2 parents 0d58dd2 + 580aa9d commit 1608d5b

3 files changed

Lines changed: 79 additions & 43 deletions

File tree

index.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,4 +62,4 @@ export declare function isSensorAvailable(): Promise<
6262
export declare function isHardwareDetected(): Promise<boolean>;
6363
export declare function hasEnrolledFingerprints(): Promise<boolean>;
6464
export declare function cancelFingerprintAuth(): void;
65-
export declare function setInvalidatedByBiometricEnrollment(boolean): void;
65+
export declare function setInvalidatedByBiometricEnrollment(set: boolean): void;

ios/RNSensitiveInfo/RNSensitiveInfo.m

Lines changed: 77 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -144,63 +144,95 @@ - (NSString *)messageForError:(NSError *)error
144144
}
145145

146146
RCT_EXPORT_METHOD(getItem:(NSString *)key options:(NSDictionary *)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){
147-
148-
147+
148+
149149
NSString * keychainService = [RCTConvert NSString:options[@"keychainService"]];
150150
if (keychainService == NULL) {
151151
keychainService = @"app";
152152
}
153+
154+
// Create dictionary of search parameters
155+
NSMutableDictionary* query = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass,
156+
keychainService, kSecAttrService,
157+
key, kSecAttrAccount,
158+
kCFBooleanTrue, kSecReturnAttributes,
159+
kCFBooleanTrue, kSecReturnData,
160+
nil];
161+
162+
if([RCTConvert NSString:options[@"kSecUseOperationPrompt"]] != NULL){
163+
[query setValue:[RCTConvert NSString:options[@"kSecUseOperationPrompt"]] forKey:(NSString *)kSecUseOperationPrompt];
164+
}
165+
166+
if([RCTConvert BOOL:options[@"touchID"]]){
167+
LAContext *context = [[LAContext alloc] init];
168+
context.localizedFallbackTitle = @"";
169+
context.touchIDAuthenticationAllowableReuseDuration = 1;
170+
171+
[query setValue:context forKey:(NSString *)kSecUseAuthenticationContext];
172+
173+
NSString *prompt = @"";
174+
if ([RCTConvert NSString:options[@"kSecUseOperationPrompt"]] != NULL) {
175+
prompt = [RCTConvert NSString:options[@"kSecUseOperationPrompt"]];
176+
}
177+
178+
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
179+
localizedReason:prompt
180+
reply:^(BOOL success, NSError * _Nullable error) {
181+
if (!success) {
182+
if (error) {
183+
reject(nil, error.localizedDescription, error);
184+
} else {
185+
reject(nil, @"The user name or passphrase you entered is not correct.", nil);
186+
}
187+
return;
188+
}
189+
190+
[self getItemWithQuery:query resolver:resolve rejecter:reject];
191+
}];
192+
return;
193+
}
194+
195+
[self getItemWithQuery:query resolver:resolve rejecter:reject];
196+
}
153197

154-
// Create dictionary of search parameters
155-
NSMutableDictionary* query = [NSMutableDictionary dictionaryWithObjectsAndKeys:(__bridge id)(kSecClassGenericPassword), kSecClass,
156-
keychainService, kSecAttrService,
157-
key, kSecAttrAccount,
158-
kCFBooleanTrue, kSecReturnAttributes,
159-
kCFBooleanTrue, kSecReturnData,
160-
nil];
161-
162-
if([RCTConvert NSString:options[@"kSecUseOperationPrompt"]] != NULL){
163-
[query setValue:[RCTConvert NSString:options[@"kSecUseOperationPrompt"]] forKey:(NSString *)kSecUseOperationPrompt];
164-
}
165-
166-
// Look up server in the keychain
167-
NSDictionary* found = nil;
168-
CFTypeRef foundTypeRef = NULL;
169-
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef*)&foundTypeRef);
170-
171-
if (osStatus != noErr && osStatus != errSecItemNotFound) {
172-
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
173-
reject([NSString stringWithFormat:@"%ld",(long)error.code], [self messageForError:error], nil);
174-
return;
175-
}
176-
177-
found = (__bridge NSDictionary*)(foundTypeRef);
178-
if (!found) {
179-
resolve(nil);
180-
} else {
181-
// Found
182-
NSString* value = [[NSString alloc] initWithData:[found objectForKey:(__bridge id)(kSecValueData)] encoding:NSUTF8StringEncoding];
183-
resolve(value);
184-
185-
}
186-
198+
- (void)getItemWithQuery:(NSDictionary *)query resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject {
199+
// Look up server in the keychain
200+
NSDictionary* found = nil;
201+
CFTypeRef foundTypeRef = NULL;
202+
OSStatus osStatus = SecItemCopyMatching((__bridge CFDictionaryRef) query, (CFTypeRef*)&foundTypeRef);
203+
204+
if (osStatus != noErr && osStatus != errSecItemNotFound) {
205+
NSError *error = [NSError errorWithDomain:NSOSStatusErrorDomain code:osStatus userInfo:nil];
206+
reject([NSString stringWithFormat:@"%ld",(long)error.code], [self messageForError:error], nil);
207+
return;
208+
}
209+
210+
found = (__bridge NSDictionary*)(foundTypeRef);
211+
if (!found) {
212+
resolve(nil);
213+
} else {
214+
// Found
215+
NSString* value = [[NSString alloc] initWithData:[found objectForKey:(__bridge id)(kSecValueData)] encoding:NSUTF8StringEncoding];
216+
resolve(value);
217+
218+
}
187219
}
188220

189221
RCT_EXPORT_METHOD(getAllItems:(NSDictionary *)options resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject){
190-
222+
191223
NSString * keychainService = [RCTConvert NSString:options[@"keychainService"]];
192-
224+
193225
NSMutableArray* finalResult = [[NSMutableArray alloc] init];
194226
NSMutableDictionary *query = [NSMutableDictionary dictionaryWithObjectsAndKeys:
195227
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnAttributes,
196228
(__bridge id)kSecMatchLimitAll, (__bridge id)kSecMatchLimit,
197229
(__bridge id)kCFBooleanTrue, (__bridge id)kSecReturnData,
198230
nil];
199-
231+
200232
if (keychainService) {
201233
[query setObject:keychainService forKey:(NSString *)kSecAttrService];
202234
}
203-
235+
204236
NSArray *secItemClasses = [NSArray arrayWithObjects:
205237
(__bridge id)kSecClassGenericPassword,
206238
(__bridge id)kSecClassInternetPassword,
@@ -272,15 +304,19 @@ - (NSString *)messageForError:(NSError *)error
272304
{
273305
#if !TARGET_OS_TV
274306
LAContext *context = [[LAContext alloc] init];
275-
276-
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:NULL]) {
307+
308+
NSError *evaluationError = nil;
309+
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&evaluationError]) {
277310
if (@available(iOS 11, macOS 10.13.2, *)) {
278311
if (context.biometryType == LABiometryTypeFaceID) {
279312
return resolve(@"Face ID");
280313
}
281314
}
282315
resolve(@"Touch ID");
283316
} else {
317+
if (evaluationError && evaluationError.code == LAErrorBiometryLockout) {
318+
return reject(nil, @"Biometry is locked", nil);
319+
}
284320
resolve(@(NO));
285321
}
286322
#else

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-native-sensitive-info",
3-
"version": "5.4.0",
3+
"version": "5.4.1",
44
"main": "RNSensitiveInfo.js",
55
"description": "react-native-sensitive-info manages all data stored in Android Shared Preferences and iOS Keychain. You can set, get and delete keys/values using simple methods.",
66
"scripts": {

0 commit comments

Comments
 (0)