From c5c22a1b9ff29c63b6f341dee5c3ae68ec1e3700 Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Tue, 7 May 2024 15:00:28 +0200 Subject: [PATCH 1/6] NEVISACCESSAPP-5744: InitializationError handling improvement on Android platform --- .../client_provider/client_provider.dart | 26 ++++++++++++++++++- lib/domain/error/error_handler.dart | 2 +- lib/ui/app_state/operation_result_type.dart | 2 +- .../change_device_information_event.dart | 4 +-- .../result/navigation/result_parameter.dart | 5 ++++ lib/ui/screens/result/result_screen.dart | 21 +++++++++++---- 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/lib/domain/client_provider/client_provider.dart b/lib/domain/client_provider/client_provider.dart index f0f1bb4..9d663d9 100644 --- a/lib/domain/client_provider/client_provider.dart +++ b/lib/domain/client_provider/client_provider.dart @@ -1,6 +1,7 @@ // Copyright © 2022 Nevis Security AG. All rights reserved. import 'dart:async'; +import 'dart:io'; import 'package:flutter/foundation.dart'; import 'package:get_it/get_it.dart'; @@ -47,8 +48,31 @@ class ClientProviderImpl implements ClientProvider { onSuccess.call(); _operationTypeRepository.reset(); }).onError((error) { - debugPrint('Client initialization failed: ${error.runtimeType}.'); + debugPrint('Client initialization failed: ${error.description}.'); + + // The SDK removes all the data when a rooted device or tampering + // is detected + if (Platform.isAndroid && _isNonRootedDeviceTamperingError(error)) { + // On Android the application must be closed when a generic device + // protection error is received (i.e. it is a checksum, debugger, + // emulator or instrumentation guard error) + exit(-1); + } + _errorHandler.handle(error); }).execute(); } + + bool _isNonRootedDeviceTamperingError( + InitializationError initializationError, + ) { + // Return true if this is a tampering error different than rooted device + // error occurred (i.e. this is a checksum, debugger, emulator or + // instrumentation guard error). + return initializationError is InitializationDeviceProtectionError && + initializationError is! InitializationRootedError && + initializationError is! InitializationHardwareError && + initializationError is! InitializationNoDeviceLockError && + initializationError is! InitializationLockScreenHasChangedError; + } } diff --git a/lib/domain/error/error_handler.dart b/lib/domain/error/error_handler.dart index 5a22a66..896fc7e 100644 --- a/lib/domain/error/error_handler.dart +++ b/lib/domain/error/error_handler.dart @@ -68,7 +68,7 @@ class ErrorHandlerImpl extends ErrorHandler { MobileAuthenticationClientError error, ) { if (error is InitializationError) { - return ResultParameter.failure(description: error.description); + return ResultParameter.fatal(description: error.description); } else if (error is OperationFidoError) { return ResultParameter.failure(description: error.errorCode.description); } diff --git a/lib/ui/app_state/operation_result_type.dart b/lib/ui/app_state/operation_result_type.dart index ef4a786..48ae797 100644 --- a/lib/ui/app_state/operation_result_type.dart +++ b/lib/ui/app_state/operation_result_type.dart @@ -1,3 +1,3 @@ // Copyright © 2022 Nevis Security AG. All rights reserved. -enum OperationResultType { success, failure } +enum OperationResultType { success, failure, fatal } diff --git a/lib/ui/screens/change_device_information/change_device_information_event.dart b/lib/ui/screens/change_device_information/change_device_information_event.dart index 6cda13d..4a9141e 100644 --- a/lib/ui/screens/change_device_information/change_device_information_event.dart +++ b/lib/ui/screens/change_device_information/change_device_information_event.dart @@ -2,8 +2,8 @@ abstract class ChangeDeviceInformationEvent {} -class ChangeDeviceInformationCreatedEvent extends ChangeDeviceInformationEvent { -} +class ChangeDeviceInformationCreatedEvent + extends ChangeDeviceInformationEvent {} class ChangeConfirmedEvent extends ChangeDeviceInformationEvent { final String newName; diff --git a/lib/ui/screens/result/navigation/result_parameter.dart b/lib/ui/screens/result/navigation/result_parameter.dart index c5b6b0c..b4c16c4 100644 --- a/lib/ui/screens/result/navigation/result_parameter.dart +++ b/lib/ui/screens/result/navigation/result_parameter.dart @@ -17,4 +17,9 @@ class ResultParameter { this.errorType, this.description, }) : type = OperationResultType.failure; + + ResultParameter.fatal({ + this.errorType, + this.description, + }) : type = OperationResultType.fatal; } diff --git a/lib/ui/screens/result/result_screen.dart b/lib/ui/screens/result/result_screen.dart index c5cb305..5c6a2bc 100644 --- a/lib/ui/screens/result/result_screen.dart +++ b/lib/ui/screens/result/result_screen.dart @@ -1,5 +1,7 @@ // Copyright © 2022 Nevis Security AG. All rights reserved. +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -69,11 +71,19 @@ class ResultContent extends StatelessWidget { Button.outlined( text: localization.confirmButtonTitle, onPressed: () { - final event = NavigateToHomeEvent( - resultType: state.type, - operationType: state.operationType, - ); - context.read().add(event); + // On Android the application must be closed when a fatal result + // type is received. At this moment only initialization errors are + // treated as fatal results. + if (Platform.isAndroid && + state.type == OperationResultType.fatal) { + exit(-1); + } else { + final event = NavigateToHomeEvent( + resultType: state.type, + operationType: state.operationType, + ); + context.read().add(event); + } }, ), const SizedBox(height: 16.0), @@ -92,6 +102,7 @@ class ResultContent extends StatelessWidget { case OperationResultType.success: return localizations.operationSucceededResultTitle( state.operationType.resolve(localizations)); + case OperationResultType.fatal: case OperationResultType.failure: return localizations.operationFailedResultTitle( state.operationType.resolve(localizations)); From 63cad660b50b5e84e1c703d6e24d956d6a8227cd Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Wed, 8 May 2024 10:03:00 +0200 Subject: [PATCH 2/6] NEVISACCESSAPP-5744: Reverted formatting of change_device_information_event.dart file --- .../change_device_information_event.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ui/screens/change_device_information/change_device_information_event.dart b/lib/ui/screens/change_device_information/change_device_information_event.dart index 4a9141e..6cda13d 100644 --- a/lib/ui/screens/change_device_information/change_device_information_event.dart +++ b/lib/ui/screens/change_device_information/change_device_information_event.dart @@ -2,8 +2,8 @@ abstract class ChangeDeviceInformationEvent {} -class ChangeDeviceInformationCreatedEvent - extends ChangeDeviceInformationEvent {} +class ChangeDeviceInformationCreatedEvent extends ChangeDeviceInformationEvent { +} class ChangeConfirmedEvent extends ChangeDeviceInformationEvent { final String newName; From 65703884fe401cb31fc51eb04a349f159225c0d5 Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Fri, 10 May 2024 14:41:36 +0200 Subject: [PATCH 3/6] NEVISACCESSAPP-5744: Review fix. --- lib/domain/client_provider/client_provider.dart | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/domain/client_provider/client_provider.dart b/lib/domain/client_provider/client_provider.dart index 9d663d9..5cafb15 100644 --- a/lib/domain/client_provider/client_provider.dart +++ b/lib/domain/client_provider/client_provider.dart @@ -52,7 +52,7 @@ class ClientProviderImpl implements ClientProvider { // The SDK removes all the data when a rooted device or tampering // is detected - if (Platform.isAndroid && _isNonRootedDeviceTamperingError(error)) { + if (Platform.isAndroid && _isGenericDeviceProtectionError(error)) { // On Android the application must be closed when a generic device // protection error is received (i.e. it is a checksum, debugger, // emulator or instrumentation guard error) @@ -63,12 +63,12 @@ class ClientProviderImpl implements ClientProvider { }).execute(); } - bool _isNonRootedDeviceTamperingError( + bool _isGenericDeviceProtectionError( InitializationError initializationError, ) { - // Return true if this is a tampering error different than rooted device - // error occurred (i.e. this is a checksum, debugger, emulator or - // instrumentation guard error). + // Return true if this is a generic tampering error different than + // rooted device error occurred (i.e. this is a checksum, debugger, + // emulator or instrumentation guard error). return initializationError is InitializationDeviceProtectionError && initializationError is! InitializationRootedError && initializationError is! InitializationHardwareError && From b959ec2fc1d2ac1ad0af7e8ef1f6550d2d42330d Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Tue, 28 May 2024 08:24:28 +0200 Subject: [PATCH 4/6] NEVISACCESSAPP-5744: Fixed result screen displaying in case of fatal errors. - Also fixed and Analyzer issues. --- lib/ui/screens/result/result_screen.dart | 38 +++++++++++++----------- lib/ui/widgets/app_scaffold.dart | 4 +-- lib/util/localization_utils.dart | 2 +- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/lib/ui/screens/result/result_screen.dart b/lib/ui/screens/result/result_screen.dart index 5c6a2bc..058ef80 100644 --- a/lib/ui/screens/result/result_screen.dart +++ b/lib/ui/screens/result/result_screen.dart @@ -68,24 +68,26 @@ class ResultContent extends StatelessWidget { AppText.body(state.description!), ]), ), - Button.outlined( - text: localization.confirmButtonTitle, - onPressed: () { - // On Android the application must be closed when a fatal result - // type is received. At this moment only initialization errors are - // treated as fatal results. - if (Platform.isAndroid && - state.type == OperationResultType.fatal) { - exit(-1); - } else { - final event = NavigateToHomeEvent( - resultType: state.type, - operationType: state.operationType, - ); - context.read().add(event); - } - }, - ), + if (!Platform.isIOS || + state.type != OperationResultType.fatal) + Button.outlined( + text: localization.confirmButtonTitle, + onPressed: () { + // On Android the application must be closed when a fatal result + // type is received. At this moment only initialization errors are + // treated as fatal results. + if (Platform.isAndroid && + state.type == OperationResultType.fatal) { + exit(-1); + } else { + final event = NavigateToHomeEvent( + resultType: state.type, + operationType: state.operationType, + ); + context.read().add(event); + } + }, + ), const SizedBox(height: 16.0), ], )) diff --git a/lib/ui/widgets/app_scaffold.dart b/lib/ui/widgets/app_scaffold.dart index 3f665f9..548426f 100644 --- a/lib/ui/widgets/app_scaffold.dart +++ b/lib/ui/widgets/app_scaffold.dart @@ -45,8 +45,8 @@ class AppScaffoldContent extends StatelessWidget { } }, builder: (ctx, state) { - return WillPopScope( - onWillPop: () async => false, + return PopScope( + canPop: false, child: SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, diff --git a/lib/util/localization_utils.dart b/lib/util/localization_utils.dart index a9e4b10..1be1666 100644 --- a/lib/util/localization_utils.dart +++ b/lib/util/localization_utils.dart @@ -27,7 +27,7 @@ extension AuthenticatorLocalizationExtension on String { return localizations.authenticatorTitleDevicePasscode; } - return 'Unknown AAID: ${this}'; + return 'Unknown AAID: $this'; } } From 4caf7d646023d85a1d16f6b351073e4055f53ff7 Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Tue, 28 May 2024 08:59:52 +0200 Subject: [PATCH 5/6] NEVISACCESSAPP-5744: Reverting unnecessary changes due to false positive analyzer problems --- lib/ui/widgets/app_scaffold.dart | 4 ++-- lib/util/localization_utils.dart | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/ui/widgets/app_scaffold.dart b/lib/ui/widgets/app_scaffold.dart index 548426f..3f665f9 100644 --- a/lib/ui/widgets/app_scaffold.dart +++ b/lib/ui/widgets/app_scaffold.dart @@ -45,8 +45,8 @@ class AppScaffoldContent extends StatelessWidget { } }, builder: (ctx, state) { - return PopScope( - canPop: false, + return WillPopScope( + onWillPop: () async => false, child: SafeArea( child: Scaffold( resizeToAvoidBottomInset: false, diff --git a/lib/util/localization_utils.dart b/lib/util/localization_utils.dart index 1be1666..a9e4b10 100644 --- a/lib/util/localization_utils.dart +++ b/lib/util/localization_utils.dart @@ -27,7 +27,7 @@ extension AuthenticatorLocalizationExtension on String { return localizations.authenticatorTitleDevicePasscode; } - return 'Unknown AAID: $this'; + return 'Unknown AAID: ${this}'; } } From a2e2088b3dfb26e4ac974b5aca084e1a9c16f393 Mon Sep 17 00:00:00 2001 From: Laszlo Domonkos Date: Wed, 29 May 2024 09:22:49 +0200 Subject: [PATCH 6/6] NEVISACCESSAPP-5744: Review fixes. --- lib/ui/screens/result/result_screen.dart | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/ui/screens/result/result_screen.dart b/lib/ui/screens/result/result_screen.dart index 058ef80..7b054fd 100644 --- a/lib/ui/screens/result/result_screen.dart +++ b/lib/ui/screens/result/result_screen.dart @@ -68,16 +68,19 @@ class ResultContent extends StatelessWidget { AppText.body(state.description!), ]), ), - if (!Platform.isIOS || + // On Android platform the confirm button is always shown, + // on iOS platform it is hidden in case of fatal result type. + if (Platform.isAndroid || state.type != OperationResultType.fatal) Button.outlined( text: localization.confirmButtonTitle, onPressed: () { + // In case of fatal result type we can be sure the application + // is running on Android platform as this button is hidden on iOS. // On Android the application must be closed when a fatal result // type is received. At this moment only initialization errors are // treated as fatal results. - if (Platform.isAndroid && - state.type == OperationResultType.fatal) { + if (state.type == OperationResultType.fatal) { exit(-1); } else { final event = NavigateToHomeEvent(