-
Notifications
You must be signed in to change notification settings - Fork 477
/
TouchID.m
170 lines (139 loc) · 5.69 KB
/
TouchID.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#import "TouchID.h"
#import <React/RCTUtils.h>
#import "React/RCTConvert.h"
@implementation TouchID
RCT_EXPORT_MODULE();
RCT_EXPORT_METHOD(isSupported: (NSDictionary *)options
callback: (RCTResponseSenderBlock)callback)
{
LAContext *context = [[LAContext alloc] init];
NSError *error;
// Check to see if we have a passcode fallback
NSNumber *passcodeFallback = [NSNumber numberWithBool:true];
if (RCTNilIfNull([options objectForKey:@"passcodeFallback"]) != nil) {
passcodeFallback = [RCTConvert NSNumber:options[@"passcodeFallback"]];
}
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// No error found, proceed
callback(@[[NSNull null], [self getBiometryType:context]]);
} else if ([passcodeFallback boolValue] && [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
// No error
callback(@[[NSNull null], [self getBiometryType:context]]);
}
// Device does not support FaceID / TouchID / Pin OR there was an error!
else {
if (error) {
NSString *errorReason = [self getErrorReason:error];
NSLog(@"Authentication failed: %@", errorReason);
callback(@[RCTMakeError(errorReason, nil, nil), [self getBiometryType:context]]);
return;
}
callback(@[RCTMakeError(@"RCTTouchIDNotSupported", nil, nil)]);
return;
}
}
RCT_EXPORT_METHOD(authenticate: (NSString *)reason
options:(NSDictionary *)options
callback: (RCTResponseSenderBlock)callback)
{
NSNumber *passcodeFallback = [NSNumber numberWithBool:false];
LAContext *context = [[LAContext alloc] init];
NSError *error;
if (RCTNilIfNull([options objectForKey:@"fallbackLabel"]) != nil) {
NSString *fallbackLabel = [RCTConvert NSString:options[@"fallbackLabel"]];
context.localizedFallbackTitle = fallbackLabel;
}
if (RCTNilIfNull([options objectForKey:@"passcodeFallback"]) != nil) {
passcodeFallback = [RCTConvert NSNumber:options[@"passcodeFallback"]];
}
// Device has TouchID
if ([context canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
// Attempt Authentification
[context evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics
localizedReason:reason
reply:^(BOOL success, NSError *error)
{
[self handleAttemptToUseDeviceIDWithSuccess:success error:error callback:callback];
}];
// Device does not support TouchID but user wishes to use passcode fallback
} else if ([passcodeFallback boolValue] && [context canEvaluatePolicy:LAPolicyDeviceOwnerAuthentication error:&error]) {
// Attempt Authentification
[context evaluatePolicy:LAPolicyDeviceOwnerAuthentication
localizedReason:reason
reply:^(BOOL success, NSError *error)
{
[self handleAttemptToUseDeviceIDWithSuccess:success error:error callback:callback];
}];
}
else {
if (error) {
NSString *errorReason = [self getErrorReason:error];
NSLog(@"Authentication failed: %@", errorReason);
callback(@[RCTMakeError(errorReason, nil, nil), [self getBiometryType:context]]);
return;
}
callback(@[RCTMakeError(@"RCTTouchIDNotSupported", nil, nil)]);
return;
}
}
- (void)handleAttemptToUseDeviceIDWithSuccess:(BOOL)success error:(NSError *)error callback:(RCTResponseSenderBlock)callback {
if (success) { // Authentication Successful
callback(@[[NSNull null], @"Authenticated with Touch ID."]);
} else if (error) { // Authentication Error
NSString *errorReason = [self getErrorReason:error];
NSLog(@"Authentication failed: %@", errorReason);
callback(@[RCTMakeError(errorReason, nil, nil)]);
} else { // Authentication Failure
callback(@[RCTMakeError(@"LAErrorAuthenticationFailed", nil, nil)]);
}
}
- (NSString *)getErrorReason:(NSError *)error
{
NSString *errorReason;
switch (error.code) {
case LAErrorAuthenticationFailed:
errorReason = @"LAErrorAuthenticationFailed";
break;
case LAErrorUserCancel:
errorReason = @"LAErrorUserCancel";
break;
case LAErrorUserFallback:
errorReason = @"LAErrorUserFallback";
break;
case LAErrorSystemCancel:
errorReason = @"LAErrorSystemCancel";
break;
case LAErrorPasscodeNotSet:
errorReason = @"LAErrorPasscodeNotSet";
break;
case LAErrorTouchIDNotAvailable:
errorReason = @"LAErrorTouchIDNotAvailable";
break;
case LAErrorTouchIDNotEnrolled:
errorReason = @"LAErrorTouchIDNotEnrolled";
break;
case LAErrorTouchIDLockout:
errorReason = @"LAErrorTouchIDLockout";
break;
default:
errorReason = @"RCTTouchIDUnknownError";
break;
}
return errorReason;
}
- (NSString *)getBiometryType:(LAContext *)context
{
if (@available(iOS 11, *)) {
if (context.biometryType == LABiometryTypeFaceID) {
return @"FaceID";
}
else if (context.biometryType == LABiometryTypeTouchID) {
return @"TouchID";
}
else if (context.biometryType == LABiometryNone) {
return @"None";
}
}
return @"TouchID";
}
@end