Skip to content

Commit

Permalink
[local_auth] Avoid user confirmation on face unlock (flutter#2047)
Browse files Browse the repository at this point in the history
* Define a new parameter for signaling that the transaction is sensitive.
* Up the biometric version to beta01.
* Handle no device credential error.
  • Loading branch information
mehmetf authored and Michael Klimushyn committed Sep 10, 2019
1 parent 186cec7 commit 9448342
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 13 deletions.
6 changes: 6 additions & 0 deletions packages/local_auth/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
## 0.6.0

* Define a new parameter for signaling that the transaction is sensitive.
* Up the biometric version to beta01.
* Handle no device credential error.

## 0.5.3

* Add face id detection as well by not relying on FingerprintCompat.
Expand Down
2 changes: 1 addition & 1 deletion packages/local_auth/android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,6 @@ android {

dependencies {
api "androidx.core:core:1.1.0-beta01"
api "androidx.biometric:biometric:1.0.0-alpha04"
api "androidx.biometric:biometric:1.0.0-beta01"
api "androidx.fragment:fragment:1.1.0-alpha06"
}
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ public AuthenticationHelper(
.setTitle((String) call.argument("signInTitle"))
.setSubtitle((String) call.argument("fingerprintHint"))
.setNegativeButtonText((String) call.argument("cancelButton"))
.setConfirmationRequired((Boolean) call.argument("sensitiveTransaction"))
.build();
}

Expand All @@ -95,13 +96,11 @@ private void stop() {
@Override
public void onAuthenticationError(int errorCode, CharSequence errString) {
switch (errorCode) {
// TODO(mehmetf): Re-enable when biometric alpha05 is released.
// https://developer.android.com/jetpack/androidx/releases/biometric
// case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL:
// completionHandler.onError(
// "PasscodeNotSet",
// "Phone not secured by PIN, pattern or password, or SIM is currently locked.");
// break;
case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL:
completionHandler.onError(
"PasscodeNotSet",
"Phone not secured by PIN, pattern or password, or SIM is currently locked.");
break;
case BiometricPrompt.ERROR_NO_SPACE:
case BiometricPrompt.ERROR_NO_BIOMETRICS:
if (call.argument("useErrorDialogs")) {
Expand Down
22 changes: 18 additions & 4 deletions packages/local_auth/lib/local_auth.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
// found in the LICENSE file.

import 'dart:async';
import 'dart:io';

import 'package:flutter/services.dart';
import 'package:meta/meta.dart';
import 'package:platform/platform.dart';

import 'auth_strings.dart';
import 'error_codes.dart';
Expand All @@ -15,6 +15,13 @@ enum BiometricType { face, fingerprint, iris }

const MethodChannel _channel = MethodChannel('plugins.flutter.io/local_auth');

Platform _platform = const LocalPlatform();

@visibleForTesting
void setMockPathProviderPlatform(Platform platform) {
_platform = platform;
}

/// A Flutter plugin for authenticating the user identity locally.
class LocalAuthentication {
/// Authenticates the user with biometrics available on the device.
Expand Down Expand Up @@ -44,6 +51,11 @@ class LocalAuthentication {
/// Construct [AndroidAuthStrings] and [IOSAuthStrings] if you want to
/// customize messages in the dialogs.
///
/// Setting [sensitiveTransaction] to true enables platform specific
/// precautions. For instance, on face unlock, Android opens a confirmation
/// dialog after the face is recognized to make sure the user meant to unlock
/// their phone.
///
/// Throws an [PlatformException] if there were technical problems with local
/// authentication (e.g. lack of relevant hardware). This might throw
/// [PlatformException] with error code [otherOperatingSystem] on the iOS
Expand All @@ -54,23 +66,25 @@ class LocalAuthentication {
bool stickyAuth = false,
AndroidAuthMessages androidAuthStrings = const AndroidAuthMessages(),
IOSAuthMessages iOSAuthStrings = const IOSAuthMessages(),
bool sensitiveTransaction = true,
}) async {
assert(localizedReason != null);
final Map<String, Object> args = <String, Object>{
'localizedReason': localizedReason,
'useErrorDialogs': useErrorDialogs,
'stickyAuth': stickyAuth,
'sensitiveTransaction': sensitiveTransaction,
};
if (Platform.isIOS) {
if (_platform.isIOS) {
args.addAll(iOSAuthStrings.args);
} else if (Platform.isAndroid) {
} else if (_platform.isAndroid) {
args.addAll(androidAuthStrings.args);
} else {
throw PlatformException(
code: otherOperatingSystem,
message: 'Local authentication does not support non-Android/iOS '
'operating systems.',
details: 'Your operating system is ${Platform.operatingSystem}');
details: 'Your operating system is ${_platform.operatingSystem}');
}
return await _channel.invokeMethod<bool>(
'authenticateWithBiometrics', args);
Expand Down
7 changes: 6 additions & 1 deletion packages/local_auth/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ description: Flutter plugin for Android and iOS device authentication sensors
such as Fingerprint Reader and Touch ID.
author: Flutter Team <[email protected]>
homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth
version: 0.5.3
version: 0.6.0

flutter:
plugin:
Expand All @@ -16,6 +16,11 @@ dependencies:
sdk: flutter
meta: ^1.0.5
intl: ^0.15.1
platform: ^2.0.0

dev_dependencies:
flutter_test:
sdk: flutter

environment:
sdk: ">=2.0.0-dev.28.0 <3.0.0"
Expand Down
90 changes: 90 additions & 0 deletions packages/local_auth/test/local_auth_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
// Copyright 2019 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:async';

import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:local_auth/auth_strings.dart';
import 'package:local_auth/local_auth.dart';
import 'package:platform/platform.dart';

void main() {
TestWidgetsFlutterBinding.ensureInitialized();

group('LocalAuth', () {
const MethodChannel channel = MethodChannel(
'plugins.flutter.io/local_auth',
);

final List<MethodCall> log = <MethodCall>[];
LocalAuthentication localAuthentication;

setUp(() {
channel.setMockMethodCallHandler((MethodCall methodCall) {
log.add(methodCall);
return Future<dynamic>.value(true);
});
localAuthentication = LocalAuthentication();
log.clear();
});

test('authenticate with no args on Android.', () async {
setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android'));
await localAuthentication.authenticateWithBiometrics(
localizedReason: 'Needs secure');
expect(
log,
<Matcher>[
isMethodCall('authenticateWithBiometrics',
arguments: <String, dynamic>{
'localizedReason': 'Needs secure',
'useErrorDialogs': true,
'stickyAuth': false,
'sensitiveTransaction': true,
}..addAll(const AndroidAuthMessages().args)),
],
);
});

test('authenticate with no args on iOS.', () async {
setMockPathProviderPlatform(FakePlatform(operatingSystem: 'ios'));
await localAuthentication.authenticateWithBiometrics(
localizedReason: 'Needs secure');
expect(
log,
<Matcher>[
isMethodCall('authenticateWithBiometrics',
arguments: <String, dynamic>{
'localizedReason': 'Needs secure',
'useErrorDialogs': true,
'stickyAuth': false,
'sensitiveTransaction': true,
}..addAll(const IOSAuthMessages().args)),
],
);
});

test('authenticate with no sensitive transaction.', () async {
setMockPathProviderPlatform(FakePlatform(operatingSystem: 'android'));
await localAuthentication.authenticateWithBiometrics(
localizedReason: 'Insecure',
sensitiveTransaction: false,
useErrorDialogs: false,
);
expect(
log,
<Matcher>[
isMethodCall('authenticateWithBiometrics',
arguments: <String, dynamic>{
'localizedReason': 'Insecure',
'useErrorDialogs': false,
'stickyAuth': false,
'sensitiveTransaction': false,
}..addAll(const AndroidAuthMessages().args)),
],
);
});
});
}

0 comments on commit 9448342

Please sign in to comment.