EddyVerbruggen / cordova-plugin-touch-id

:nail_care: 👱‍♂️ Forget passwords, use a fingerprint scanner!
MIT License
214 stars 72 forks source link

FaceID dialog does not show up in rare cases #93

Open sflepp opened 4 years ago

sflepp commented 4 years ago

We have an issue that the Face ID dialog is not showing up in rare cases.

The issue seems to be that the function laContext evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics returns an error "User interaction is required" (code: -1004).

The problem is prevented by creating a dedicated instance of LAContext just for the above check. https://stackoverflow.com/questions/35094167/lacontext-evaluatepolicy-does-not-always-prompt-user

- (void) verifyFingerprintWithCustomPasswordFallback:(NSString*)callbackId withMessage:(NSString*)message andEnterPasswordLabel:(NSString*)enterPasswordLabel {

  if (NSClassFromString(@"LAContext") == NULL) {
    [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR]
                                callbackId:callbackId];
    return;
  }

  [self.commandDelegate runInBackground:^{
    NSError *error = nil;
    LAContext *laContext = [[LAContext alloc] init];

    if (![laContext canEvaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics error:&error]) {
      [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:[error localizedDescription]]
                                  callbackId:callbackId];
      return;
    }

    // if we add a 'verifyFingerprintWithOptions' method we can add stuff like this:
    // the nr of seconds you allow to reuse the last touchid device unlock (default 0, so never reuse)
//    laContext.touchIDAuthenticationAllowableReuseDuration = 30;

   // ################################################################################
   // ###### This seems to fix the problem: use this instance for further calls ######
    LAContext *laContextEvaluate = [[LAContext alloc] init];

    // this replaces the default 'Enter password' button label
    if (enterPasswordLabel != nil) {
      laContextEvaluate.localizedFallbackTitle = enterPasswordLabel;
    }

    [laContextEvaluate evaluatePolicy:LAPolicyDeviceOwnerAuthenticationWithBiometrics localizedReason:message reply:^(BOOL authOK, NSError *error) {
      if (authOK) {
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_OK]
                                    callbackId:callbackId];
      } else {
        // invoked when the scan failed 3 times in a row, the cancel button was pressed, or the 'enter password' button was pressed
        NSArray *errorKeys = @[@"code", @"localizedDescription"];
        [self.commandDelegate sendPluginResult:[CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR
                                                           messageAsDictionary:[error dictionaryWithValuesForKeys:errorKeys]]
                                    callbackId:callbackId];
      }
    }];
  }];
}

Another way would be to call evaluatePolicy twice, which also works but doesn't feel right.

Cubaza commented 4 years ago

Hi, I have the same error on iPhone with iOS 13. Have You solve this issue? Maybe You've implemented one of approaches which You mentioned here?

I'll be very glad if You can help me to implement this because I'm not iOS guy.