From 6a6f7a20b0a2f9d0984386601d08c544d07e13b0 Mon Sep 17 00:00:00 2001 From: Frank Merkel <138444693+frankmer@users.noreply.github.com> Date: Fri, 23 Aug 2024 17:06:46 +0200 Subject: [PATCH] refactoring --- integration_test/add_tokens_test.dart | 2 +- integration_test/copy_to_clipboard_test.dart | 2 +- integration_test/rename_and_delete_test.dart | 2 +- integration_test/two_step_rollout_test.dart | 13 +- integration_test/views_test.dart | 9 +- .../container_credentials_repository.dart | 4 +- .../token_state_listener.dart | 2 +- lib/mains/main_customizer.dart | 4 +- lib/mains/main_netknights.dart | 2 +- .../enums/introduction_extension.dart | 2 +- lib/model/processor_result.dart | 65 +- lib/model/processor_result.freezed.dart | 463 +++++++ lib/model/push_request.dart | 2 +- .../riverpod_states/credentials_state.dart | 7 +- .../credentials_state.freezed.dart | 26 +- .../introduction_state.freezed.dart | 21 +- .../progress_state.freezed.dart | 28 +- lib/model/token_container.dart | 8 +- lib/model/token_container.freezed.dart | 136 +- lib/model/tokens/container_credentials.dart | 294 +++- .../tokens/container_credentials.freezed.dart | 1181 +++++++++++++++++ lib/model/tokens/container_credentials.g.dart | 139 +- lib/model/tokens/otp_token.dart | 5 +- .../mixins/token_import_processor.dart | 5 +- .../container_credentials_processor.dart | 48 +- .../home_widget_processor.dart | 87 +- .../home_widget_navigate_processor.dart | 96 +- ...navigation_scheme_processor_interface.dart | 3 +- .../scheme_processor_interface.dart | 14 +- .../free_otp_plus_qr_processor.dart | 2 + .../google_authenticator_qr_processor.dart | 4 +- .../otp_auth_processor.dart | 59 +- ...rivacyidea_authenticator_qr_processor.dart | 26 +- ...ken_import_scheme_processor_interface.dart | 9 +- .../aegis_import_file_processor.dart | 42 +- ...thenticator_pro_import_file_processor.dart | 40 +- .../free_otp_plus_import_file_processor.dart | 35 +- ...google_authenticator_qrfile_processor.dart | 2 + ...a_authenticator_import_file_processor.dart | 15 +- ...token_import_file_processor_interface.dart | 1 + .../two_fas_import_file_processor.dart | 15 +- ...cure_container_credentials_repository.dart | 21 +- lib/repo/secure_token_repository.dart | 2 +- .../application_customization.dart | 1 + lib/utils/home_widget_utils.dart | 2 +- lib/utils/identifiers.dart | 32 +- lib/utils/push_provider.dart | 2 +- .../app_constraints_notifier.dart | 0 .../app_constraints_notifier.g.dart | 10 +- .../application_customizer_provider.dart | 0 .../application_customizer_provider.g.dart | 0 .../credential_notifier.dart | 123 +- .../credential_notifier.g.dart | 2 +- .../sortable_notifier.dart | 2 +- .../token_container_notifier.dart | 2 +- .../token_notifier.dart | 142 +- .../token_notifier.g.dart | 2 +- .../state_providers/home_widget_provider.dart | 2 +- .../connectivity_provider.dart | 2 +- lib/utils/utils.dart | 68 +- .../add_token_manually_view.dart | 2 +- .../import_tokens_view.dart | 2 +- .../pages/import_encrypted_data_page.dart | 1 + .../pages/import_plain_tokens_page.dart | 2 +- .../pages/import_start_page.dart | 26 +- .../link_home_widget_view.dart | 2 +- .../connectivity_listener.dart | 2 +- .../delete_token_folder_action.dart | 2 +- .../token_folder_expandable.dart | 2 +- .../main_view_navigation_bar.dart | 2 +- .../qr_scanner_button.dart | 11 +- .../main_view_tokens_list_filtered.dart | 2 +- .../day_password_token_widget_tile.dart | 2 +- .../default_delete_action.dart | 2 +- .../default_edit_action.dart | 2 +- .../default_edit_action_dialog.dart | 2 +- .../default_lock_action.dart | 2 +- .../hotp_token_widget_tile.dart | 2 +- .../actions/edit_push_token_action.dart | 2 +- .../push_token_widgets/push_token_widget.dart | 34 +- .../rollout_failed_widget.dart | 4 +- .../totp_token_widget_tile.dart | 2 +- .../widgets/push_tokens_view_list.dart | 2 +- .../dialogs/select_tokens_dialog.dart | 6 +- .../dialogs/show_qr_code_dialog.dart | 2 +- .../settings_group_push_token.dart | 2 +- lib/views/settings_view/settings_view.dart | 2 +- .../update_firebase_token_dialog.dart | 2 +- lib/views/splash_screen/splash_screen.dart | 2 +- lib/widgets/app_wrapper.dart | 2 +- .../enter_passphrase_dialog.dart | 60 + .../dialog_widgets/push_request_dialog.dart | 2 +- lib/widgets/focused_item_as_overlay.dart | 2 +- lib/widgets/hideable_widget_.dart | 2 +- pubspec.lock | 12 +- pubspec.yaml | 1 + .../sortable_notifier_test.dart | 2 +- .../state_notifiers/token_notifier_test.dart | 10 +- 98 files changed, 3146 insertions(+), 410 deletions(-) create mode 100644 lib/model/processor_result.freezed.dart create mode 100644 lib/model/tokens/container_credentials.freezed.dart rename lib/utils/riverpod/riverpod_providers/{state_providers => generated_providers}/app_constraints_notifier.dart (100%) rename lib/utils/riverpod/riverpod_providers/{state_providers => generated_providers}/app_constraints_notifier.g.dart (79%) rename lib/utils/riverpod/riverpod_providers/{state_providers => generated_providers}/application_customizer_provider.dart (100%) rename lib/utils/riverpod/riverpod_providers/{state_providers => generated_providers}/application_customizer_provider.g.dart (100%) rename lib/utils/riverpod/riverpod_providers/{state_notifier_providers => generated_providers}/token_notifier.dart (91%) rename lib/utils/riverpod/riverpod_providers/{state_notifier_providers => generated_providers}/token_notifier.g.dart (98%) create mode 100644 lib/widgets/dialog_widgets/enter_passphrase_dialog.dart diff --git a/integration_test/add_tokens_test.dart b/integration_test/add_tokens_test.dart index ac30480f9..23707b2ac 100644 --- a/integration_test/add_tokens_test.dart +++ b/integration_test/add_tokens_test.dart @@ -17,7 +17,7 @@ import 'package:privacyidea_authenticator/utils/customization/application_custom import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view.dart'; import 'package:privacyidea_authenticator/views/add_token_manually_view/add_token_manually_view_widgets/labeled_dropdown_button.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/app_bar_item.dart'; diff --git a/integration_test/copy_to_clipboard_test.dart b/integration_test/copy_to_clipboard_test.dart index 7576f8ffb..5812957b0 100644 --- a/integration_test/copy_to_clipboard_test.dart +++ b/integration_test/copy_to_clipboard_test.dart @@ -15,7 +15,7 @@ import 'package:privacyidea_authenticator/model/version.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../test/tests_app_wrapper.dart'; import '../test/tests_app_wrapper.mocks.dart'; diff --git a/integration_test/rename_and_delete_test.dart b/integration_test/rename_and_delete_test.dart index 09028f7a9..bef7e398c 100644 --- a/integration_test/rename_and_delete_test.dart +++ b/integration_test/rename_and_delete_test.dart @@ -16,7 +16,7 @@ import 'package:privacyidea_authenticator/model/version.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/actions/edit_hotp_token_action.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget.dart'; diff --git a/integration_test/two_step_rollout_test.dart b/integration_test/two_step_rollout_test.dart index 406e590d1..3b29e2a87 100644 --- a/integration_test/two_step_rollout_test.dart +++ b/integration_test/two_step_rollout_test.dart @@ -15,7 +15,8 @@ import 'package:privacyidea_authenticator/model/version.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/utils.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart'; import 'package:privacyidea_authenticator/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart'; @@ -67,8 +68,9 @@ void main() { Future _addTwoStepHotpTokenTest(WidgetTester tester) async { await pumpUntilFindNWidgets(tester, find.byType(MainView), 1, const Duration(seconds: 10)); - globalRef!.read(tokenProvider.notifier).handleQrCode( - 'otpauth://hotp/OATH0001DBD0?secret=AALIBQJMOGEE7SAVEZ5D3K2ADO7MVFQD&counter=1&digits=6&issuer=privacyIDEA&2step_salt=8&2step_output=20&2step_difficulty=10000'); + const qrCode = + 'otpauth://hotp/OATH0001DBD0?secret=AALIBQJMOGEE7SAVEZ5D3K2ADO7MVFQD&counter=1&digits=6&issuer=privacyIDEA&2step_salt=8&2step_output=20&2step_difficulty=10000'; + await scanQrCode(globalRef!, qrCode); Logger.info('Finding phone part dialog'); await pumpUntilFindNWidgets(tester, find.text(AppLocalizationsEn().phonePart), 1, const Duration(seconds: 20)); expect(find.text(AppLocalizationsEn().phonePart), findsOneWidget); @@ -89,8 +91,9 @@ Future _addTwoStepHotpTokenTest(WidgetTester tester) async { Future _addTwoStepTotpTokenTest(WidgetTester tester) async { await pumpUntilFindNWidgets(tester, find.byType(MainView), 1, const Duration(seconds: 10)); - globalRef!.read(tokenProvider.notifier).handleQrCode( - 'otpauth://totp/TOTP00009D5F?secret=NZ4OPONKAAGDFN2QHV26ZWYVTLFER4C6&period=30&digits=6&issuer=privacyIDEA&2step_salt=8&2step_output=20&2step_difficulty=10000'); + const qrCode = + 'otpauth://totp/TOTP00009D5F?secret=NZ4OPONKAAGDFN2QHV26ZWYVTLFER4C6&period=30&digits=6&issuer=privacyIDEA&2step_salt=8&2step_output=20&2step_difficulty=10000'; + await scanQrCode(globalRef!, qrCode); Logger.info('Finding phone part dialog'); await pumpUntilFindNWidgets(tester, find.text(AppLocalizationsEn().phonePart), 1, const Duration(seconds: 20)); expect(find.text(AppLocalizationsEn().phonePart), findsOneWidget); diff --git a/integration_test/views_test.dart b/integration_test/views_test.dart index 2d102df75..0ba04af63 100644 --- a/integration_test/views_test.dart +++ b/integration_test/views_test.dart @@ -22,9 +22,10 @@ import 'package:privacyidea_authenticator/utils/push_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'package:privacyidea_authenticator/utils/rsa_utils.dart'; import 'package:privacyidea_authenticator/model/version.dart'; +import 'package:privacyidea_authenticator/utils/utils.dart'; import 'package:privacyidea_authenticator/views/settings_view/settings_view_widgets/settings_groups.dart'; import '../test/tests_app_wrapper.dart'; @@ -166,8 +167,10 @@ Future _settingsViewTest(WidgetTester tester) async { expect(find.text(AppLocalizationsEn().language), findsOneWidget); expect(find.text(AppLocalizationsEn().errorLogTitle), findsOneWidget); expect(find.byType(SettingsGroup), findsNWidgets(6)); - globalRef!.read(tokenProvider.notifier).handleQrCode( - 'otpauth://pipush/label?url=http%3A%2F%2Fwww.example.com&ttl=10&issuer=issuer&enrollment_credential=enrollmentCredentials&v=1&serial=serial&serial=serial&sslverify=0'); + const qrCode = + 'otpauth://pipush/label?url=http%3A%2F%2Fwww.example.com&ttl=10&issuer=issuer&enrollment_credential=enrollmentCredentials&v=1&serial=serial&serial=serial&sslverify=0'; + await scanQrCode(globalRef!, qrCode); + await pumpUntilFindNWidgets(tester, find.text(AppLocalizationsEn().pushToken), 1, const Duration(minutes: 5)); expect(find.text(AppLocalizationsEn().pushToken), findsOneWidget); expect(find.byType(SettingsGroup), findsNWidgets(6)); diff --git a/lib/interfaces/repo/container_credentials_repository.dart b/lib/interfaces/repo/container_credentials_repository.dart index 33d833a82..08a3e4ad6 100644 --- a/lib/interfaces/repo/container_credentials_repository.dart +++ b/lib/interfaces/repo/container_credentials_repository.dart @@ -24,7 +24,7 @@ abstract class ContainerCredentialsRepository { Future saveCredential(ContainerCredential credential); Future saveCredentialsState(CredentialsState credentialsState); Future loadCredentialsState(); - Future loadCredential(String id); + Future loadCredential(String serial); Future deleteAllCredentials(); - Future deleteCredential(String id); + Future deleteCredential(String serial); } diff --git a/lib/interfaces/riverpod/state_listeners/state_notifier_provider_listeners/token_state_listener.dart b/lib/interfaces/riverpod/state_listeners/state_notifier_provider_listeners/token_state_listener.dart index 41d025663..98eac1c13 100644 --- a/lib/interfaces/riverpod/state_listeners/state_notifier_provider_listeners/token_state_listener.dart +++ b/lib/interfaces/riverpod/state_listeners/state_notifier_provider_listeners/token_state_listener.dart @@ -19,7 +19,7 @@ */ import '../../../../model/riverpod_states/token_state.dart'; -import '../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../buildless_listener.dart'; abstract class TokenStateListener extends BuildlessListener { diff --git a/lib/mains/main_customizer.dart b/lib/mains/main_customizer.dart index 83948ab2e..a0a952932 100644 --- a/lib/mains/main_customizer.dart +++ b/lib/mains/main_customizer.dart @@ -28,9 +28,9 @@ import '../l10n/app_localizations.dart'; import '../model/enums/app_feature.dart'; import '../model/riverpod_states/settings_state.dart'; import '../utils/globals.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/application_customizer_provider.dart'; import '../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import '../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; -import '../utils/riverpod/riverpod_providers/state_providers/application_customizer_provider.dart'; import '../views/add_token_manually_view/add_token_manually_view.dart'; import '../views/feedback_view/feedback_view.dart'; import '../views/import_tokens_view/import_tokens_view.dart'; diff --git a/lib/mains/main_netknights.dart b/lib/mains/main_netknights.dart index 71fb53703..c6d7c69ac 100644 --- a/lib/mains/main_netknights.dart +++ b/lib/mains/main_netknights.dart @@ -33,7 +33,7 @@ import '../utils/globals.dart'; import '../utils/home_widget_utils.dart'; import '../utils/logger.dart'; import '../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import '../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; import '../views/add_token_manually_view/add_token_manually_view.dart'; import '../views/feedback_view/feedback_view.dart'; import '../views/import_tokens_view/import_tokens_view.dart'; diff --git a/lib/model/extensions/enums/introduction_extension.dart b/lib/model/extensions/enums/introduction_extension.dart index 0836e7c89..856d9abbe 100644 --- a/lib/model/extensions/enums/introduction_extension.dart +++ b/lib/model/extensions/enums/introduction_extension.dart @@ -3,7 +3,7 @@ import '../../riverpod_states/settings_state.dart'; import '../../../l10n/app_localizations.dart'; import '../../../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../enums/introduction.dart'; import '../../riverpod_states/introduction_state.dart'; diff --git a/lib/model/processor_result.dart b/lib/model/processor_result.dart index 6f78b073a..a10c0d392 100644 --- a/lib/model/processor_result.dart +++ b/lib/model/processor_result.dart @@ -17,29 +17,62 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -abstract class ProcessorResult { - const ProcessorResult(); - factory ProcessorResult.success(T data) => ProcessorResultSuccess(data); - factory ProcessorResult.failed(String errorMessage) => ProcessorResultFailed(errorMessage); +import 'package:flutter/material.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:privacyidea_authenticator/utils/identifiers.dart'; + +import '../l10n/app_localizations.dart'; +import '../utils/globals.dart'; +import '../utils/logger.dart'; +import '../utils/riverpod/riverpod_providers/state_providers/status_message_provider.dart'; +import '../utils/view_utils.dart'; + +part 'processor_result.freezed.dart'; + +@freezed +abstract class ProcessorResult with _$ProcessorResult { + const ProcessorResult._(); + factory ProcessorResult.success( + T resultData, { + required TypeMatcher? resultHandlerType, + }) = ProcessorResultSuccess; + factory ProcessorResult.failed( + String message, { + required TypeMatcher? resultHandlerType, + }) = ProcessorResultFailed; + bool get isSuccess => this is ProcessorResultSuccess; + bool get isFailed => this is ProcessorResultFailed; ProcessorResultSuccess? get asSuccess => this is ProcessorResultSuccess ? this as ProcessorResultSuccess : null; ProcessorResultFailed? get asFailed => this is ProcessorResultFailed ? this as ProcessorResultFailed : null; } -class ProcessorResultSuccess extends ProcessorResult { - final T resultData; - const ProcessorResultSuccess(this.resultData); +extension ListProcessorResult on List> { + List> get successResults => where((element) => element.isSuccess).map((e) => e.asSuccess!).toList(); + List> get failedResults => where((element) => !element.isSuccess).map((e) => e.asFailed!).toList(); - @override - String toString() { - return 'ProcessorResultSuccess(data: $resultData)'; + List getData() { + final results = toList(); + if (results.isEmpty) { + showMessage(message: 'No data found in QR code.', duration: const Duration(seconds: 3)); + Logger.warning('No data found in QR code.', name: 'token_notifier.dart#_getData'); + return []; + } + final failedResults = results.whereType().toList(); + // add postframe callback to show the message after the current frame + + WidgetsBinding.instance.addPostFrameCallback((_) async { + for (var failedResult in failedResults) { + globalRef?.read(statusMessageProvider.notifier).state = (AppLocalizations.of((await globalContext))!.malformedData, failedResult.message); + } + }); + + final successData = results.where((result) => result.isSuccess).map((e) => e.asSuccess!.resultData).toList(); + return successData; } } -class ProcessorResultFailed extends ProcessorResult { - final String message; - const ProcessorResultFailed(this.message); - - @override - String toString() => '$runtimeType(message: $message)'; +mixin ResultHandler { + Future handleProcessorResult(ProcessorResult result, Map args); + Future handleProcessorResults(List results, Map args); } diff --git a/lib/model/processor_result.freezed.dart b/lib/model/processor_result.freezed.dart new file mode 100644 index 000000000..327c3355e --- /dev/null +++ b/lib/model/processor_result.freezed.dart @@ -0,0 +1,463 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'processor_result.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +/// @nodoc +mixin _$ProcessorResult { + TypeMatcher? get resultHandlerType => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function( + T resultData, TypeMatcher? resultHandlerType) + success, + required TResult Function( + String message, TypeMatcher? resultHandlerType) + failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult? Function( + String message, TypeMatcher? resultHandlerType)? + failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult Function( + String message, TypeMatcher? resultHandlerType)? + failed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(ProcessorResultSuccess value) success, + required TResult Function(ProcessorResultFailed value) failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ProcessorResultSuccess value)? success, + TResult? Function(ProcessorResultFailed value)? failed, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ProcessorResultSuccess value)? success, + TResult Function(ProcessorResultFailed value)? failed, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ProcessorResultCopyWith> get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ProcessorResultCopyWith { + factory $ProcessorResultCopyWith( + ProcessorResult value, $Res Function(ProcessorResult) then) = + _$ProcessorResultCopyWithImpl>; + @useResult + $Res call({TypeMatcher? resultHandlerType}); +} + +/// @nodoc +class _$ProcessorResultCopyWithImpl> + implements $ProcessorResultCopyWith { + _$ProcessorResultCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? resultHandlerType = freezed, + }) { + return _then(_value.copyWith( + resultHandlerType: freezed == resultHandlerType + ? _value.resultHandlerType + : resultHandlerType // ignore: cast_nullable_to_non_nullable + as TypeMatcher?, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ProcessorResultSuccessImplCopyWith + implements $ProcessorResultCopyWith { + factory _$$ProcessorResultSuccessImplCopyWith( + _$ProcessorResultSuccessImpl value, + $Res Function(_$ProcessorResultSuccessImpl) then) = + __$$ProcessorResultSuccessImplCopyWithImpl; + @override + @useResult + $Res call({T resultData, TypeMatcher? resultHandlerType}); +} + +/// @nodoc +class __$$ProcessorResultSuccessImplCopyWithImpl + extends _$ProcessorResultCopyWithImpl> + implements _$$ProcessorResultSuccessImplCopyWith { + __$$ProcessorResultSuccessImplCopyWithImpl( + _$ProcessorResultSuccessImpl _value, + $Res Function(_$ProcessorResultSuccessImpl) _then) + : super(_value, _then); + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? resultData = freezed, + Object? resultHandlerType = freezed, + }) { + return _then(_$ProcessorResultSuccessImpl( + freezed == resultData + ? _value.resultData + : resultData // ignore: cast_nullable_to_non_nullable + as T, + resultHandlerType: freezed == resultHandlerType + ? _value.resultHandlerType + : resultHandlerType // ignore: cast_nullable_to_non_nullable + as TypeMatcher?, + )); + } +} + +/// @nodoc + +class _$ProcessorResultSuccessImpl extends ProcessorResultSuccess { + _$ProcessorResultSuccessImpl(this.resultData, + {required this.resultHandlerType}) + : super._(); + + @override + final T resultData; + @override + final TypeMatcher? resultHandlerType; + + @override + String toString() { + return 'ProcessorResult<$T>.success(resultData: $resultData, resultHandlerType: $resultHandlerType)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProcessorResultSuccessImpl && + const DeepCollectionEquality() + .equals(other.resultData, resultData) && + (identical(other.resultHandlerType, resultHandlerType) || + other.resultHandlerType == resultHandlerType)); + } + + @override + int get hashCode => Object.hash(runtimeType, + const DeepCollectionEquality().hash(resultData), resultHandlerType); + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProcessorResultSuccessImplCopyWith> + get copyWith => __$$ProcessorResultSuccessImplCopyWithImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + T resultData, TypeMatcher? resultHandlerType) + success, + required TResult Function( + String message, TypeMatcher? resultHandlerType) + failed, + }) { + return success(resultData, resultHandlerType); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult? Function( + String message, TypeMatcher? resultHandlerType)? + failed, + }) { + return success?.call(resultData, resultHandlerType); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult Function( + String message, TypeMatcher? resultHandlerType)? + failed, + required TResult orElse(), + }) { + if (success != null) { + return success(resultData, resultHandlerType); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(ProcessorResultSuccess value) success, + required TResult Function(ProcessorResultFailed value) failed, + }) { + return success(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ProcessorResultSuccess value)? success, + TResult? Function(ProcessorResultFailed value)? failed, + }) { + return success?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ProcessorResultSuccess value)? success, + TResult Function(ProcessorResultFailed value)? failed, + required TResult orElse(), + }) { + if (success != null) { + return success(this); + } + return orElse(); + } +} + +abstract class ProcessorResultSuccess extends ProcessorResult { + factory ProcessorResultSuccess(final T resultData, + {required final TypeMatcher? resultHandlerType}) = + _$ProcessorResultSuccessImpl; + ProcessorResultSuccess._() : super._(); + + T get resultData; + @override + TypeMatcher? get resultHandlerType; + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProcessorResultSuccessImplCopyWith> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ProcessorResultFailedImplCopyWith + implements $ProcessorResultCopyWith { + factory _$$ProcessorResultFailedImplCopyWith( + _$ProcessorResultFailedImpl value, + $Res Function(_$ProcessorResultFailedImpl) then) = + __$$ProcessorResultFailedImplCopyWithImpl; + @override + @useResult + $Res call({String message, TypeMatcher? resultHandlerType}); +} + +/// @nodoc +class __$$ProcessorResultFailedImplCopyWithImpl + extends _$ProcessorResultCopyWithImpl> + implements _$$ProcessorResultFailedImplCopyWith { + __$$ProcessorResultFailedImplCopyWithImpl( + _$ProcessorResultFailedImpl _value, + $Res Function(_$ProcessorResultFailedImpl) _then) + : super(_value, _then); + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? message = null, + Object? resultHandlerType = freezed, + }) { + return _then(_$ProcessorResultFailedImpl( + null == message + ? _value.message + : message // ignore: cast_nullable_to_non_nullable + as String, + resultHandlerType: freezed == resultHandlerType + ? _value.resultHandlerType + : resultHandlerType // ignore: cast_nullable_to_non_nullable + as TypeMatcher?, + )); + } +} + +/// @nodoc + +class _$ProcessorResultFailedImpl extends ProcessorResultFailed { + _$ProcessorResultFailedImpl(this.message, {required this.resultHandlerType}) + : super._(); + + @override + final String message; + @override + final TypeMatcher? resultHandlerType; + + @override + String toString() { + return 'ProcessorResult<$T>.failed(message: $message, resultHandlerType: $resultHandlerType)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ProcessorResultFailedImpl && + (identical(other.message, message) || other.message == message) && + (identical(other.resultHandlerType, resultHandlerType) || + other.resultHandlerType == resultHandlerType)); + } + + @override + int get hashCode => Object.hash(runtimeType, message, resultHandlerType); + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ProcessorResultFailedImplCopyWith> + get copyWith => __$$ProcessorResultFailedImplCopyWithImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + T resultData, TypeMatcher? resultHandlerType) + success, + required TResult Function( + String message, TypeMatcher? resultHandlerType) + failed, + }) { + return failed(message, resultHandlerType); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult? Function( + String message, TypeMatcher? resultHandlerType)? + failed, + }) { + return failed?.call(message, resultHandlerType); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + T resultData, TypeMatcher? resultHandlerType)? + success, + TResult Function( + String message, TypeMatcher? resultHandlerType)? + failed, + required TResult orElse(), + }) { + if (failed != null) { + return failed(message, resultHandlerType); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(ProcessorResultSuccess value) success, + required TResult Function(ProcessorResultFailed value) failed, + }) { + return failed(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ProcessorResultSuccess value)? success, + TResult? Function(ProcessorResultFailed value)? failed, + }) { + return failed?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ProcessorResultSuccess value)? success, + TResult Function(ProcessorResultFailed value)? failed, + required TResult orElse(), + }) { + if (failed != null) { + return failed(this); + } + return orElse(); + } +} + +abstract class ProcessorResultFailed extends ProcessorResult { + factory ProcessorResultFailed(final String message, + {required final TypeMatcher? resultHandlerType}) = + _$ProcessorResultFailedImpl; + ProcessorResultFailed._() : super._(); + + String get message; + @override + TypeMatcher? get resultHandlerType; + + /// Create a copy of ProcessorResult + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ProcessorResultFailedImplCopyWith> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/model/push_request.dart b/lib/model/push_request.dart index 8291f8412..eccd5d8ca 100644 --- a/lib/model/push_request.dart +++ b/lib/model/push_request.dart @@ -25,7 +25,7 @@ import 'package:json_annotation/json_annotation.dart'; import '../utils/globals.dart'; import '../utils/identifiers.dart'; import '../utils/logger.dart'; -import '../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../utils/rsa_utils.dart'; import 'tokens/push_token.dart'; diff --git a/lib/model/riverpod_states/credentials_state.dart b/lib/model/riverpod_states/credentials_state.dart index 624874442..52e82a763 100644 --- a/lib/model/riverpod_states/credentials_state.dart +++ b/lib/model/riverpod_states/credentials_state.dart @@ -27,18 +27,13 @@ import '../tokens/container_credentials.dart'; part 'credentials_state.freezed.dart'; part 'credentials_state.g.dart'; -@Freezed() +@freezed class CredentialsState with _$CredentialsState { const CredentialsState._(); const factory CredentialsState({ required List credentials, }) = _CredentialsState; - @override - String toString() { - return 'CredentialsState{credentials: $credentials}'; - } - ContainerCredential? credentialsOf(String containerSerial) => credentials.firstWhereOrNull((credential) => credential.serial == containerSerial); static CredentialsState fromJsonStringList(List jsonStrings) { final credentials = jsonStrings.map((jsonString) => ContainerCredential.fromJson(jsonDecode(jsonString))).toList(); diff --git a/lib/model/riverpod_states/credentials_state.freezed.dart b/lib/model/riverpod_states/credentials_state.freezed.dart index 47aaf1de5..09deac54c 100644 --- a/lib/model/riverpod_states/credentials_state.freezed.dart +++ b/lib/model/riverpod_states/credentials_state.freezed.dart @@ -23,8 +23,12 @@ mixin _$CredentialsState { List get credentials => throw _privateConstructorUsedError; + /// Serializes this CredentialsState to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of CredentialsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $CredentialsStateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -48,6 +52,8 @@ class _$CredentialsStateCopyWithImpl<$Res, $Val extends CredentialsState> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of CredentialsState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -81,6 +87,8 @@ class __$$CredentialsStateImplCopyWithImpl<$Res> $Res Function(_$CredentialsStateImpl) _then) : super(_value, _then); + /// Create a copy of CredentialsState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -114,6 +122,11 @@ class _$CredentialsStateImpl extends _CredentialsState { return EqualUnmodifiableListView(_credentials); } + @override + String toString() { + return 'CredentialsState(credentials: $credentials)'; + } + @override bool operator ==(Object other) { return identical(this, other) || @@ -123,12 +136,14 @@ class _$CredentialsStateImpl extends _CredentialsState { .equals(other._credentials, _credentials)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, const DeepCollectionEquality().hash(_credentials)); - @JsonKey(ignore: true) + /// Create a copy of CredentialsState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$CredentialsStateImplCopyWith<_$CredentialsStateImpl> get copyWith => @@ -154,8 +169,11 @@ abstract class _CredentialsState extends CredentialsState { @override List get credentials; + + /// Create a copy of CredentialsState + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$CredentialsStateImplCopyWith<_$CredentialsStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/model/riverpod_states/introduction_state.freezed.dart b/lib/model/riverpod_states/introduction_state.freezed.dart index ba708259d..df478fd59 100644 --- a/lib/model/riverpod_states/introduction_state.freezed.dart +++ b/lib/model/riverpod_states/introduction_state.freezed.dart @@ -23,8 +23,12 @@ mixin _$IntroductionState { Set get completedIntroductions => throw _privateConstructorUsedError; + /// Serializes this IntroductionState to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of IntroductionState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $IntroductionStateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -48,6 +52,8 @@ class _$IntroductionStateCopyWithImpl<$Res, $Val extends IntroductionState> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of IntroductionState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -81,6 +87,8 @@ class __$$IntroductionStateImplCopyWithImpl<$Res> $Res Function(_$IntroductionStateImpl) _then) : super(_value, _then); + /// Create a copy of IntroductionState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -130,12 +138,14 @@ class _$IntroductionStateImpl extends _IntroductionState { other._completedIntroductions, _completedIntroductions)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash(runtimeType, const DeepCollectionEquality().hash(_completedIntroductions)); - @JsonKey(ignore: true) + /// Create a copy of IntroductionState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$IntroductionStateImplCopyWith<_$IntroductionStateImpl> get copyWith => @@ -161,8 +171,11 @@ abstract class _IntroductionState extends IntroductionState { @override Set get completedIntroductions; + + /// Create a copy of IntroductionState + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$IntroductionStateImplCopyWith<_$IntroductionStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/model/riverpod_states/progress_state.freezed.dart b/lib/model/riverpod_states/progress_state.freezed.dart index 7bedbe0db..ae8d6890e 100644 --- a/lib/model/riverpod_states/progress_state.freezed.dart +++ b/lib/model/riverpod_states/progress_state.freezed.dart @@ -57,7 +57,9 @@ mixin _$ProgressState { }) => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $ProgressStateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -81,6 +83,8 @@ class _$ProgressStateCopyWithImpl<$Res, $Val extends ProgressState> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -121,6 +125,8 @@ class __$$ProgressStateUninitializedImplCopyWithImpl<$Res> $Res Function(_$ProgressStateUninitializedImpl) _then) : super(_value, _then); + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -170,7 +176,9 @@ class _$ProgressStateUninitializedImpl extends ProgressStateUninitialized { @override int get hashCode => Object.hash(runtimeType, max, value); - @JsonKey(ignore: true) + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ProgressStateUninitializedImplCopyWith<_$ProgressStateUninitializedImpl> @@ -249,8 +257,11 @@ abstract class ProgressStateUninitialized extends ProgressState { int get max; @override int get value; + + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ProgressStateUninitializedImplCopyWith<_$ProgressStateUninitializedImpl> get copyWith => throw _privateConstructorUsedError; } @@ -274,6 +285,8 @@ class __$$ProgressStateImplCopyWithImpl<$Res> _$ProgressStateImpl _value, $Res Function(_$ProgressStateImpl) _then) : super(_value, _then); + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -323,7 +336,9 @@ class _$ProgressStateImpl extends _ProgressState { @override int get hashCode => Object.hash(runtimeType, max, value); - @JsonKey(ignore: true) + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$ProgressStateImplCopyWith<_$ProgressStateImpl> get copyWith => @@ -401,8 +416,11 @@ abstract class _ProgressState extends ProgressState { int get max; @override int get value; + + /// Create a copy of ProgressState + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$ProgressStateImplCopyWith<_$ProgressStateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/model/token_container.dart b/lib/model/token_container.dart index 3894e3581..76181abdc 100644 --- a/lib/model/token_container.dart +++ b/lib/model/token_container.dart @@ -57,7 +57,7 @@ sealed class TokenContainer with _$TokenContainer { const factory TokenContainer.uninitialized({ // Base fields @Default('PrivacyIDEA') String serverName, - @Default(null) DateTime? lastSyncAt, + DateTime? lastSyncAt, @Default('none') String serial, @Default('Uninitialized') String description, @Default([]) List syncedTokenTemplates, @@ -77,7 +77,7 @@ sealed class TokenContainer with _$TokenContainer { const factory TokenContainer.modified({ // Base fields @Default('PrivacyIDEA') String serverName, - @Default(null) DateTime? lastSyncAt, + DateTime? lastSyncAt, required String serial, required String description, required List syncedTokenTemplates, @@ -88,7 +88,7 @@ sealed class TokenContainer with _$TokenContainer { const factory TokenContainer.unsynced({ // Base fields @Default('PrivacyIDEA') String serverName, - @Default(null) DateTime? lastSyncAt, + DateTime? lastSyncAt, required String serial, required String description, required List syncedTokenTemplates, @@ -110,7 +110,7 @@ sealed class TokenContainer with _$TokenContainer { const factory TokenContainer.error({ // Base fields @Default('PrivacyIDEA') String serverName, - @Default(null) DateTime? lastSyncAt, + DateTime? lastSyncAt, @Default('none') String serial, @Default('Error') String description, @Default([]) List syncedTokenTemplates, diff --git a/lib/model/token_container.freezed.dart b/lib/model/token_container.freezed.dart index 0df17a59d..b52533a13 100644 --- a/lib/model/token_container.freezed.dart +++ b/lib/model/token_container.freezed.dart @@ -246,8 +246,13 @@ mixin _$TokenContainer { required TResult orElse(), }) => throw _privateConstructorUsedError; + + /// Serializes this TokenContainer to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $TokenContainerCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -277,6 +282,8 @@ class _$TokenContainerCopyWithImpl<$Res, $Val extends TokenContainer> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -344,6 +351,8 @@ class __$$TokenContainerUninitializedImplCopyWithImpl<$Res> $Res Function(_$TokenContainerUninitializedImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -389,7 +398,7 @@ class _$TokenContainerUninitializedImpl extends TokenContainerUninitialized with DiagnosticableTreeMixin { const _$TokenContainerUninitializedImpl( {this.serverName = 'PrivacyIDEA', - this.lastSyncAt = null, + this.lastSyncAt, this.serial = 'none', this.description = 'Uninitialized', final List syncedTokenTemplates = const [], @@ -409,7 +418,6 @@ class _$TokenContainerUninitializedImpl extends TokenContainerUninitialized @JsonKey() final String serverName; @override - @JsonKey() final DateTime? lastSyncAt; @override @JsonKey() @@ -476,7 +484,7 @@ class _$TokenContainerUninitializedImpl extends TokenContainerUninitialized .equals(other._localTokenTemplates, _localTokenTemplates)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -487,7 +495,9 @@ class _$TokenContainerUninitializedImpl extends TokenContainerUninitialized const DeepCollectionEquality().hash(_syncedTokenTemplates), const DeepCollectionEquality().hash(_localTokenTemplates)); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerUninitializedImplCopyWith<_$TokenContainerUninitializedImpl> @@ -743,7 +753,8 @@ abstract class TokenContainerUninitialized extends TokenContainer { factory TokenContainerUninitialized.fromJson(Map json) = _$TokenContainerUninitializedImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime? get lastSyncAt; @@ -755,8 +766,11 @@ abstract class TokenContainerUninitialized extends TokenContainer { List get syncedTokenTemplates; @override List get localTokenTemplates; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerUninitializedImplCopyWith<_$TokenContainerUninitializedImpl> get copyWith => throw _privateConstructorUsedError; } @@ -786,6 +800,8 @@ class __$$TokenContainerSyncedImplCopyWithImpl<$Res> $Res Function(_$TokenContainerSyncedImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -912,7 +928,7 @@ class _$TokenContainerSyncedImpl extends TokenContainerSynced .equals(other._localTokenTemplates, _localTokenTemplates)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -923,7 +939,9 @@ class _$TokenContainerSyncedImpl extends TokenContainerSynced const DeepCollectionEquality().hash(_syncedTokenTemplates), const DeepCollectionEquality().hash(_localTokenTemplates)); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerSyncedImplCopyWith<_$TokenContainerSyncedImpl> @@ -1180,7 +1198,8 @@ abstract class TokenContainerSynced extends TokenContainer { factory TokenContainerSynced.fromJson(Map json) = _$TokenContainerSyncedImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime get lastSyncAt; @@ -1192,8 +1211,11 @@ abstract class TokenContainerSynced extends TokenContainer { List get syncedTokenTemplates; @override List get localTokenTemplates; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerSyncedImplCopyWith<_$TokenContainerSyncedImpl> get copyWith => throw _privateConstructorUsedError; } @@ -1226,6 +1248,8 @@ class __$$TokenContainerModifiedImplCopyWithImpl<$Res> $Res Function(_$TokenContainerModifiedImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -1276,7 +1300,7 @@ class _$TokenContainerModifiedImpl extends TokenContainerModified with DiagnosticableTreeMixin { const _$TokenContainerModifiedImpl( {this.serverName = 'PrivacyIDEA', - this.lastSyncAt = null, + this.lastSyncAt, required this.serial, required this.description, required final List syncedTokenTemplates, @@ -1296,7 +1320,6 @@ class _$TokenContainerModifiedImpl extends TokenContainerModified @JsonKey() final String serverName; @override - @JsonKey() final DateTime? lastSyncAt; @override final String serial; @@ -1366,7 +1389,7 @@ class _$TokenContainerModifiedImpl extends TokenContainerModified other.lastModifiedAt == lastModifiedAt)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -1378,7 +1401,9 @@ class _$TokenContainerModifiedImpl extends TokenContainerModified const DeepCollectionEquality().hash(_localTokenTemplates), lastModifiedAt); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerModifiedImplCopyWith<_$TokenContainerModifiedImpl> @@ -1634,7 +1659,8 @@ abstract class TokenContainerModified extends TokenContainer { factory TokenContainerModified.fromJson(Map json) = _$TokenContainerModifiedImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime? get lastSyncAt; @@ -1647,8 +1673,11 @@ abstract class TokenContainerModified extends TokenContainer { @override List get localTokenTemplates; // Base fields end DateTime get lastModifiedAt; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerModifiedImplCopyWith<_$TokenContainerModifiedImpl> get copyWith => throw _privateConstructorUsedError; } @@ -1681,6 +1710,8 @@ class __$$TokenContainerUnsyncedImplCopyWithImpl<$Res> $Res Function(_$TokenContainerUnsyncedImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -1731,7 +1762,7 @@ class _$TokenContainerUnsyncedImpl extends TokenContainerUnsynced with DiagnosticableTreeMixin { const _$TokenContainerUnsyncedImpl( {this.serverName = 'PrivacyIDEA', - this.lastSyncAt = null, + this.lastSyncAt, required this.serial, required this.description, required final List syncedTokenTemplates, @@ -1751,7 +1782,6 @@ class _$TokenContainerUnsyncedImpl extends TokenContainerUnsynced @JsonKey() final String serverName; @override - @JsonKey() final DateTime? lastSyncAt; @override final String serial; @@ -1820,7 +1850,7 @@ class _$TokenContainerUnsyncedImpl extends TokenContainerUnsynced (identical(other.message, message) || other.message == message)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -1832,7 +1862,9 @@ class _$TokenContainerUnsyncedImpl extends TokenContainerUnsynced const DeepCollectionEquality().hash(_localTokenTemplates), message); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerUnsyncedImplCopyWith<_$TokenContainerUnsyncedImpl> @@ -2088,7 +2120,8 @@ abstract class TokenContainerUnsynced extends TokenContainer { factory TokenContainerUnsynced.fromJson(Map json) = _$TokenContainerUnsyncedImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime? get lastSyncAt; @@ -2101,8 +2134,11 @@ abstract class TokenContainerUnsynced extends TokenContainer { @override List get localTokenTemplates; // Base fields end String? get message; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerUnsyncedImplCopyWith<_$TokenContainerUnsyncedImpl> get copyWith => throw _privateConstructorUsedError; } @@ -2135,6 +2171,8 @@ class __$$TokenContainerNotFoundImplCopyWithImpl<$Res> $Res Function(_$TokenContainerNotFoundImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -2273,7 +2311,7 @@ class _$TokenContainerNotFoundImpl extends TokenContainerNotFound (identical(other.message, message) || other.message == message)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -2285,7 +2323,9 @@ class _$TokenContainerNotFoundImpl extends TokenContainerNotFound const DeepCollectionEquality().hash(_localTokenTemplates), message); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerNotFoundImplCopyWith<_$TokenContainerNotFoundImpl> @@ -2541,7 +2581,8 @@ abstract class TokenContainerNotFound extends TokenContainer { factory TokenContainerNotFound.fromJson(Map json) = _$TokenContainerNotFoundImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime? get lastSyncAt; @@ -2554,8 +2595,11 @@ abstract class TokenContainerNotFound extends TokenContainer { @override List get localTokenTemplates; // Base fields end String get message; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerNotFoundImplCopyWith<_$TokenContainerNotFoundImpl> get copyWith => throw _privateConstructorUsedError; } @@ -2586,6 +2630,8 @@ class __$$TokenContainerErrorImplCopyWithImpl<$Res> $Res Function(_$TokenContainerErrorImpl) _then) : super(_value, _then); + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -2636,7 +2682,7 @@ class _$TokenContainerErrorImpl extends TokenContainerError with DiagnosticableTreeMixin { const _$TokenContainerErrorImpl( {this.serverName = 'PrivacyIDEA', - this.lastSyncAt = null, + this.lastSyncAt, this.serial = 'none', this.description = 'Error', final List syncedTokenTemplates = const [], @@ -2656,7 +2702,6 @@ class _$TokenContainerErrorImpl extends TokenContainerError @JsonKey() final String serverName; @override - @JsonKey() final DateTime? lastSyncAt; @override @JsonKey() @@ -2729,7 +2774,7 @@ class _$TokenContainerErrorImpl extends TokenContainerError const DeepCollectionEquality().equals(other.error, error)); } - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) @override int get hashCode => Object.hash( runtimeType, @@ -2741,7 +2786,9 @@ class _$TokenContainerErrorImpl extends TokenContainerError const DeepCollectionEquality().hash(_localTokenTemplates), const DeepCollectionEquality().hash(error)); - @JsonKey(ignore: true) + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenContainerErrorImplCopyWith<_$TokenContainerErrorImpl> get copyWith => @@ -2997,7 +3044,8 @@ abstract class TokenContainerError extends TokenContainer { factory TokenContainerError.fromJson(Map json) = _$TokenContainerErrorImpl.fromJson; - @override // Base fields +// Base fields + @override String get serverName; @override DateTime? get lastSyncAt; @@ -3010,8 +3058,11 @@ abstract class TokenContainerError extends TokenContainer { @override List get localTokenTemplates; // Base fields end dynamic get error; + + /// Create a copy of TokenContainer + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenContainerErrorImplCopyWith<_$TokenContainerErrorImpl> get copyWith => throw _privateConstructorUsedError; } @@ -3024,8 +3075,12 @@ TokenTemplate _$TokenTemplateFromJson(Map json) { mixin _$TokenTemplate { Map get data => throw _privateConstructorUsedError; + /// Serializes this TokenTemplate to a JSON map. Map toJson() => throw _privateConstructorUsedError; - @JsonKey(ignore: true) + + /// Create a copy of TokenTemplate + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) $TokenTemplateCopyWith get copyWith => throw _privateConstructorUsedError; } @@ -3049,6 +3104,8 @@ class _$TokenTemplateCopyWithImpl<$Res, $Val extends TokenTemplate> // ignore: unused_field final $Res Function($Val) _then; + /// Create a copy of TokenTemplate + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -3082,6 +3139,8 @@ class __$$TokenTemplateImplCopyWithImpl<$Res> _$TokenTemplateImpl _value, $Res Function(_$TokenTemplateImpl) _then) : super(_value, _then); + /// Create a copy of TokenTemplate + /// with the given fields replaced by the non-null parameter values. @pragma('vm:prefer-inline') @override $Res call({ @@ -3127,7 +3186,9 @@ class _$TokenTemplateImpl extends _TokenTemplate with DiagnosticableTreeMixin { ..add(DiagnosticsProperty('data', data)); } - @JsonKey(ignore: true) + /// Create a copy of TokenTemplate + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) @override @pragma('vm:prefer-inline') _$$TokenTemplateImplCopyWith<_$TokenTemplateImpl> get copyWith => @@ -3151,8 +3212,11 @@ abstract class _TokenTemplate extends TokenTemplate { @override Map get data; + + /// Create a copy of TokenTemplate + /// with the given fields replaced by the non-null parameter values. @override - @JsonKey(ignore: true) + @JsonKey(includeFromJson: false, includeToJson: false) _$$TokenTemplateImplCopyWith<_$TokenTemplateImpl> get copyWith => throw _privateConstructorUsedError; } diff --git a/lib/model/tokens/container_credentials.dart b/lib/model/tokens/container_credentials.dart index d2f32b358..a45c62209 100644 --- a/lib/model/tokens/container_credentials.dart +++ b/lib/model/tokens/container_credentials.dart @@ -1,3 +1,5 @@ +// ignore_for_file: constant_identifier_names + /* * privacyIDEA Authenticator * @@ -17,22 +19,294 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import 'package:json_annotation/json_annotation.dart'; -import 'push_token.dart'; +import 'dart:typed_data'; + +import 'package:basic_utils/basic_utils.dart'; +import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:privacyidea_authenticator/model/enums/algorithms.dart'; +import 'package:privacyidea_authenticator/utils/identifiers.dart'; + +import '../../utils/logger.dart'; +part 'container_credentials.freezed.dart'; part 'container_credentials.g.dart'; -@JsonSerializable() -class ContainerCredential extends PushToken { - ContainerCredential({required super.serial, required super.id}); +// issuer=privacyIDEA +// &serial=SMPH00134123 +// &nonce=887197025f5fa59b50f33c15196eb97ee651a5d1 +// &time=2024-08-21T07%3A43%3A07.086670%2B00%3A00 +// &url="http://127.0.0.1:5000/container/register/finalize" +// &key_algorithm=secp384r1 +// &hash_algorithm=SHA256 +// &passphrase=Enter%20your%20passphrase + +@freezed +class ContainerCredential with _$ContainerCredential { + static const eccUtils = EccUtils(); + const ContainerCredential._(); + factory ContainerCredential.fromUriMap(Map uriMap) { + validateMap(uriMap, { + URI_ISSUER: const TypeMatcher(), + URI_NONCE: const TypeMatcher(), + URI_TIMESTAMP: const TypeMatcher(), + URI_FINALIZATION_URL: const TypeMatcher(), + URI_SERIAL: const TypeMatcher(), + URI_KEY_ALGORITHM: const TypeMatcher(), + URI_HASH_ALGORITHM: const TypeMatcher(), + }); + return ContainerCredential.unfinalized( + issuer: uriMap[URI_ISSUER], + nonce: uriMap[URI_NONCE], + timestamp: DateTime.parse(uriMap[URI_TIMESTAMP]), + finalizationUrl: Uri.parse(uriMap[URI_FINALIZATION_URL]), + serial: uriMap[URI_SERIAL], + ecKeyAlgorithm: EcKeyAlgorithm.values.byCurveName(uriMap[URI_KEY_ALGORITHM]), + hashAlgorithm: Algorithms.values.byName(uriMap[URI_HASH_ALGORITHM]), + ); + } + + const factory ContainerCredential.unfinalized({ + required String issuer, + required String nonce, + required DateTime timestamp, + required Uri finalizationUrl, + required String serial, + required EcKeyAlgorithm ecKeyAlgorithm, + required Algorithms hashAlgorithm, + @Default(ContainerCredentialState.uninitialized) ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey, + }) = ContainerCredentialUnfinalized; - factory ContainerCredential.fromUriMap(Map uriMap) => throw UnimplementedError(); // PushToken.fromUriMap(uriMap); + const factory ContainerCredential.finalized({ + required String issuer, + required String nonce, + required DateTime timestamp, + required Uri finalizationUrl, + required String serial, + required EcKeyAlgorithm ecKeyAlgorithm, + required Algorithms hashAlgorithm, + @Default(ContainerCredentialState.finalized) ContainerCredentialState state, + String? passphrase, + required String publicServerKey, + required String publicClientKey, + required String privateClientKey, + }) = ContainerCredentialFinalized; + ContainerCredentialFinalized? finalize({ + ECPublicKey? publicServerKey, + AsymmetricKeyPair? clientKeyPair, + }) { + if (this is ContainerCredentialFinalized) return this as ContainerCredentialFinalized; + if (publicServerKey == null && this.publicServerKey == null) { + Logger.warning('Unable to finalize without public server key'); + return null; + } + assert(publicServerKey != null || this.publicServerKey != null, 'Unable to finalize without public server key'); + if (clientKeyPair == null && (publicClientKey == null || privateClientKey == null)) { + Logger.warning('Unable to finalize without client key pair'); + return null; + } + return ContainerCredentialFinalized( + issuer: issuer, + nonce: nonce, + timestamp: timestamp, + finalizationUrl: finalizationUrl, + serial: serial, + ecKeyAlgorithm: ecKeyAlgorithm, + hashAlgorithm: hashAlgorithm, + passphrase: passphrase, + state: ContainerCredentialState.finalized, + publicServerKey: this.publicServerKey ?? eccUtils.serializeECPublicKey(publicServerKey!), + publicClientKey: publicClientKey ?? eccUtils.serializeECPublicKey(clientKeyPair!.publicKey), + privateClientKey: privateClientKey ?? eccUtils.serializeECPrivateKey(clientKeyPair!.privateKey), + ); + } + + ECPublicKey? get ecPublicServerKey => publicServerKey == null ? null : eccUtils.deserializeECPublicKey(publicServerKey!); + ContainerCredential withPublicServerKey(ECPublicKey publicServerKey) => copyWith(publicServerKey: eccUtils.serializeECPublicKey(publicServerKey)); + ECPublicKey? get ecPublicClientKey => publicClientKey == null ? null : eccUtils.deserializeECPublicKey(publicClientKey!); + ECPrivateKey? get ecPrivateClientKey => privateClientKey == null ? null : eccUtils.deserializeECPrivateKey(privateClientKey!); + ContainerCredential withClientKeyPair(AsymmetricKeyPair keyPair) => copyWith( + publicClientKey: eccUtils.serializeECPublicKey(keyPair.publicKey), + privateClientKey: eccUtils.serializeECPrivateKey(keyPair.privateKey), + ); factory ContainerCredential.fromJson(Map json) => _$ContainerCredentialFromJson(json); - @override - Map toJson() => _$ContainerCredentialToJson(this); - @override - String toString() => 'ContainerCredential{serial: $serial, id: $id}'; + // // Sign with private client key + // String signMessage(String message) { + // final signer = Signer(hashAlgorithm.name); + // signer.init(true, PrivateKey(ecPrivateClientKey!.d, ecPrivateClientKey!.parameters)); + // return signer.signMessage(message); + // }; +} + +enum ContainerCredentialState { + uninitialized, + generatingKeyPair, + generatingKeyPairFailed, + sendingPublicKey, + sendingPublicKeyFailed, + parsingResponse, + parsingResponseFailed, + finalized, +} + +/// The following curves are supported: + +enum EcKeyAlgorithm { + brainpoolp160r1, + brainpoolp160t1, + brainpoolp192r1, + brainpoolp192t1, + brainpoolp224r1, + brainpoolp224t1, + brainpoolp256r1, + brainpoolp256t1, + brainpoolp320r1, + brainpoolp320t1, + brainpoolp384r1, + brainpoolp384t1, + brainpoolp512r1, + brainpoolp512t1, + GostR3410_2001_CryptoPro_A, + GostR3410_2001_CryptoPro_B, + GostR3410_2001_CryptoPro_C, + GostR3410_2001_CryptoPro_XchA, + GostR3410_2001_CryptoPro_XchB, + prime192v1, + prime192v2, + prime192v3, + prime239v1, + prime239v2, + prime239v3, + prime256v1, + secp112r1, + secp112r2, + secp128r1, + secp128r2, + secp160k1, + secp160r1, + secp160r2, + secp192k1, + secp192r1, + secp224k1, + secp224r1, + secp256k1, + secp256r1, + secp384r1, + secp521r1, +} + +extension EcKeyAlgorithmList on List { + EcKeyAlgorithm byCurveName(String domainName) => switch (domainName) { + 'brainpoolp160r1' => EcKeyAlgorithm.brainpoolp160r1, + 'brainpoolp160t1' => EcKeyAlgorithm.brainpoolp160t1, + 'brainpoolp192r1' => EcKeyAlgorithm.brainpoolp192r1, + 'brainpoolp192t1' => EcKeyAlgorithm.brainpoolp192t1, + 'brainpoolp224r1' => EcKeyAlgorithm.brainpoolp224r1, + 'brainpoolp224t1' => EcKeyAlgorithm.brainpoolp224t1, + 'brainpoolp256r1' => EcKeyAlgorithm.brainpoolp256r1, + 'brainpoolp256t1' => EcKeyAlgorithm.brainpoolp256t1, + 'brainpoolp320r1' => EcKeyAlgorithm.brainpoolp320r1, + 'brainpoolp320t1' => EcKeyAlgorithm.brainpoolp320t1, + 'brainpoolp384r1' => EcKeyAlgorithm.brainpoolp384r1, + 'brainpoolp384t1' => EcKeyAlgorithm.brainpoolp384t1, + 'brainpoolp512r1' => EcKeyAlgorithm.brainpoolp512r1, + 'brainpoolp512t1' => EcKeyAlgorithm.brainpoolp512t1, + 'GostR3410-2001-CryptoPro-A' => EcKeyAlgorithm.GostR3410_2001_CryptoPro_A, + 'GostR3410-2001-CryptoPro-B' => EcKeyAlgorithm.GostR3410_2001_CryptoPro_B, + 'GostR3410-2001-CryptoPro-C' => EcKeyAlgorithm.GostR3410_2001_CryptoPro_C, + 'GostR3410-2001-CryptoPro-XchA' => EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchA, + 'GostR3410-2001-CryptoPro-XchB' => EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchB, + 'prime192v1' => EcKeyAlgorithm.prime192v1, + 'prime192v2' => EcKeyAlgorithm.prime192v2, + 'prime192v3' => EcKeyAlgorithm.prime192v3, + 'prime239v1' => EcKeyAlgorithm.prime239v1, + 'prime239v2' => EcKeyAlgorithm.prime239v2, + 'prime239v3' => EcKeyAlgorithm.prime239v3, + 'prime256v1' => EcKeyAlgorithm.prime256v1, + 'secp112r1' => EcKeyAlgorithm.secp112r1, + 'secp112r2' => EcKeyAlgorithm.secp112r2, + 'secp128r1' => EcKeyAlgorithm.secp128r1, + 'secp128r2' => EcKeyAlgorithm.secp128r2, + 'secp160k1' => EcKeyAlgorithm.secp160k1, + 'secp160r1' => EcKeyAlgorithm.secp160r1, + 'secp160r2' => EcKeyAlgorithm.secp160r2, + 'secp192k1' => EcKeyAlgorithm.secp192k1, + 'secp192r1' => EcKeyAlgorithm.secp192r1, + 'secp224k1' => EcKeyAlgorithm.secp224k1, + 'secp224r1' => EcKeyAlgorithm.secp224r1, + 'secp256k1' => EcKeyAlgorithm.secp256k1, + 'secp256r1' => EcKeyAlgorithm.secp256r1, + 'secp384r1' => EcKeyAlgorithm.secp384r1, + 'secp521r1' => EcKeyAlgorithm.secp521r1, + _ => throw ArgumentError('Unknown domain name: $domainName'), + }; +} + +extension EcKeyAlgorithmX on EcKeyAlgorithm { + String get curveName => switch (this) { + EcKeyAlgorithm.brainpoolp160r1 => 'brainpoolp160r1', + EcKeyAlgorithm.brainpoolp160t1 => 'brainpoolp160t1', + EcKeyAlgorithm.brainpoolp192r1 => 'brainpoolp192r1', + EcKeyAlgorithm.brainpoolp192t1 => 'brainpoolp192t1', + EcKeyAlgorithm.brainpoolp224r1 => 'brainpoolp224r1', + EcKeyAlgorithm.brainpoolp224t1 => 'brainpoolp224t1', + EcKeyAlgorithm.brainpoolp256r1 => 'brainpoolp256r1', + EcKeyAlgorithm.brainpoolp256t1 => 'brainpoolp256t1', + EcKeyAlgorithm.brainpoolp320r1 => 'brainpoolp320r1', + EcKeyAlgorithm.brainpoolp320t1 => 'brainpoolp320t1', + EcKeyAlgorithm.brainpoolp384r1 => 'brainpoolp384r1', + EcKeyAlgorithm.brainpoolp384t1 => 'brainpoolp384t1', + EcKeyAlgorithm.brainpoolp512r1 => 'brainpoolp512r1', + EcKeyAlgorithm.brainpoolp512t1 => 'brainpoolp512t1', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_A => 'GostR3410-2001-CryptoPro-A', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_B => 'GostR3410-2001-CryptoPro-B', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_C => 'GostR3410-2001-CryptoPro-C', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchA => 'GostR3410-2001-CryptoPro-XchA', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchB => 'GostR3410-2001-CryptoPro-XchB', + EcKeyAlgorithm.prime192v1 => 'prime192v1', + EcKeyAlgorithm.prime192v2 => 'prime192v2', + EcKeyAlgorithm.prime192v3 => 'prime192v3', + EcKeyAlgorithm.prime239v1 => 'prime239v1', + EcKeyAlgorithm.prime239v2 => 'prime239v2', + EcKeyAlgorithm.prime239v3 => 'prime239v3', + EcKeyAlgorithm.prime256v1 => 'prime256v1', + EcKeyAlgorithm.secp112r1 => 'secp112r1', + EcKeyAlgorithm.secp112r2 => 'secp112r2', + EcKeyAlgorithm.secp128r1 => 'secp128r1', + EcKeyAlgorithm.secp128r2 => 'secp128r2', + EcKeyAlgorithm.secp160k1 => 'secp160k1', + EcKeyAlgorithm.secp160r1 => 'secp160r1', + EcKeyAlgorithm.secp160r2 => 'secp160r2', + EcKeyAlgorithm.secp192k1 => 'secp192k1', + EcKeyAlgorithm.secp192r1 => 'secp192r1', + EcKeyAlgorithm.secp224k1 => 'secp224k1', + EcKeyAlgorithm.secp224r1 => 'secp224r1', + EcKeyAlgorithm.secp256k1 => 'secp256k1', + EcKeyAlgorithm.secp256r1 => 'secp256r1', + EcKeyAlgorithm.secp384r1 => 'secp384r1', + EcKeyAlgorithm.secp521r1 => 'secp521r1', + }; +} + +class EccUtils { + final String algorithmName = 'EC'; + + const EccUtils(); + + String serializeECPublicKey(ECPublicKey publicKey) => CryptoUtils.encodeEcPublicKeyToPem(publicKey); + ECPublicKey deserializeECPublicKey(String ecPublicKey) => CryptoUtils.ecPublicKeyFromPem(ecPublicKey); + String serializeECPrivateKey(ECPrivateKey ecPrivateKey) => CryptoUtils.encodeEcPrivateKeyToPem(ecPrivateKey); + ECPrivateKey deserializeECPrivateKey(String ecPrivateKey) => CryptoUtils.ecPrivateKeyFromPem(ecPrivateKey); + + String trySignWithPrivateKey(ECPrivateKey privateKey, String message) { + final ecSignature = CryptoUtils.ecSign(privateKey, Uint8List.fromList(message.codeUnits)); + String signatureBase64 = CryptoUtils.ecSignatureToBase64(ecSignature); + return signatureBase64; + } } diff --git a/lib/model/tokens/container_credentials.freezed.dart b/lib/model/tokens/container_credentials.freezed.dart new file mode 100644 index 000000000..7f142b19d --- /dev/null +++ b/lib/model/tokens/container_credentials.freezed.dart @@ -0,0 +1,1181 @@ +// coverage:ignore-file +// GENERATED CODE - DO NOT MODIFY BY HAND +// ignore_for_file: type=lint +// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark + +part of 'container_credentials.dart'; + +// ************************************************************************** +// FreezedGenerator +// ************************************************************************** + +T _$identity(T value) => value; + +final _privateConstructorUsedError = UnsupportedError( + 'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more information: https://github.com/rrousselGit/freezed#adding-getters-and-methods-to-our-models'); + +ContainerCredential _$ContainerCredentialFromJson(Map json) { + switch (json['runtimeType']) { + case 'unfinalized': + return ContainerCredentialUnfinalized.fromJson(json); + case 'finalized': + return ContainerCredentialFinalized.fromJson(json); + + default: + throw CheckedFromJsonException(json, 'runtimeType', 'ContainerCredential', + 'Invalid union type "${json['runtimeType']}"!'); + } +} + +/// @nodoc +mixin _$ContainerCredential { + String get issuer => throw _privateConstructorUsedError; + String get nonce => throw _privateConstructorUsedError; + DateTime get timestamp => throw _privateConstructorUsedError; + Uri get finalizationUrl => throw _privateConstructorUsedError; + String get serial => throw _privateConstructorUsedError; + EcKeyAlgorithm get ecKeyAlgorithm => throw _privateConstructorUsedError; + Algorithms get hashAlgorithm => throw _privateConstructorUsedError; + ContainerCredentialState get state => throw _privateConstructorUsedError; + String? get passphrase => throw _privateConstructorUsedError; + String? get publicServerKey => throw _privateConstructorUsedError; + String? get publicClientKey => throw _privateConstructorUsedError; + String? get privateClientKey => throw _privateConstructorUsedError; + @optionalTypeArgs + TResult when({ + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey) + unfinalized, + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey) + finalized, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult map({ + required TResult Function(ContainerCredentialUnfinalized value) unfinalized, + required TResult Function(ContainerCredentialFinalized value) finalized, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult? Function(ContainerCredentialFinalized value)? finalized, + }) => + throw _privateConstructorUsedError; + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult Function(ContainerCredentialFinalized value)? finalized, + required TResult orElse(), + }) => + throw _privateConstructorUsedError; + + /// Serializes this ContainerCredential to a JSON map. + Map toJson() => throw _privateConstructorUsedError; + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + $ContainerCredentialCopyWith get copyWith => + throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class $ContainerCredentialCopyWith<$Res> { + factory $ContainerCredentialCopyWith( + ContainerCredential value, $Res Function(ContainerCredential) then) = + _$ContainerCredentialCopyWithImpl<$Res, ContainerCredential>; + @useResult + $Res call( + {String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey}); +} + +/// @nodoc +class _$ContainerCredentialCopyWithImpl<$Res, $Val extends ContainerCredential> + implements $ContainerCredentialCopyWith<$Res> { + _$ContainerCredentialCopyWithImpl(this._value, this._then); + + // ignore: unused_field + final $Val _value; + // ignore: unused_field + final $Res Function($Val) _then; + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? issuer = null, + Object? nonce = null, + Object? timestamp = null, + Object? finalizationUrl = null, + Object? serial = null, + Object? ecKeyAlgorithm = null, + Object? hashAlgorithm = null, + Object? state = null, + Object? passphrase = freezed, + Object? publicServerKey = null, + Object? publicClientKey = null, + Object? privateClientKey = null, + }) { + return _then(_value.copyWith( + issuer: null == issuer + ? _value.issuer + : issuer // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + timestamp: null == timestamp + ? _value.timestamp + : timestamp // ignore: cast_nullable_to_non_nullable + as DateTime, + finalizationUrl: null == finalizationUrl + ? _value.finalizationUrl + : finalizationUrl // ignore: cast_nullable_to_non_nullable + as Uri, + serial: null == serial + ? _value.serial + : serial // ignore: cast_nullable_to_non_nullable + as String, + ecKeyAlgorithm: null == ecKeyAlgorithm + ? _value.ecKeyAlgorithm + : ecKeyAlgorithm // ignore: cast_nullable_to_non_nullable + as EcKeyAlgorithm, + hashAlgorithm: null == hashAlgorithm + ? _value.hashAlgorithm + : hashAlgorithm // ignore: cast_nullable_to_non_nullable + as Algorithms, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as ContainerCredentialState, + passphrase: freezed == passphrase + ? _value.passphrase + : passphrase // ignore: cast_nullable_to_non_nullable + as String?, + publicServerKey: null == publicServerKey + ? _value.publicServerKey! + : publicServerKey // ignore: cast_nullable_to_non_nullable + as String, + publicClientKey: null == publicClientKey + ? _value.publicClientKey! + : publicClientKey // ignore: cast_nullable_to_non_nullable + as String, + privateClientKey: null == privateClientKey + ? _value.privateClientKey! + : privateClientKey // ignore: cast_nullable_to_non_nullable + as String, + ) as $Val); + } +} + +/// @nodoc +abstract class _$$ContainerCredentialUnfinalizedImplCopyWith<$Res> + implements $ContainerCredentialCopyWith<$Res> { + factory _$$ContainerCredentialUnfinalizedImplCopyWith( + _$ContainerCredentialUnfinalizedImpl value, + $Res Function(_$ContainerCredentialUnfinalizedImpl) then) = + __$$ContainerCredentialUnfinalizedImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey}); +} + +/// @nodoc +class __$$ContainerCredentialUnfinalizedImplCopyWithImpl<$Res> + extends _$ContainerCredentialCopyWithImpl<$Res, + _$ContainerCredentialUnfinalizedImpl> + implements _$$ContainerCredentialUnfinalizedImplCopyWith<$Res> { + __$$ContainerCredentialUnfinalizedImplCopyWithImpl( + _$ContainerCredentialUnfinalizedImpl _value, + $Res Function(_$ContainerCredentialUnfinalizedImpl) _then) + : super(_value, _then); + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? issuer = null, + Object? nonce = null, + Object? timestamp = null, + Object? finalizationUrl = null, + Object? serial = null, + Object? ecKeyAlgorithm = null, + Object? hashAlgorithm = null, + Object? state = null, + Object? passphrase = freezed, + Object? publicServerKey = freezed, + Object? publicClientKey = freezed, + Object? privateClientKey = freezed, + }) { + return _then(_$ContainerCredentialUnfinalizedImpl( + issuer: null == issuer + ? _value.issuer + : issuer // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + timestamp: null == timestamp + ? _value.timestamp + : timestamp // ignore: cast_nullable_to_non_nullable + as DateTime, + finalizationUrl: null == finalizationUrl + ? _value.finalizationUrl + : finalizationUrl // ignore: cast_nullable_to_non_nullable + as Uri, + serial: null == serial + ? _value.serial + : serial // ignore: cast_nullable_to_non_nullable + as String, + ecKeyAlgorithm: null == ecKeyAlgorithm + ? _value.ecKeyAlgorithm + : ecKeyAlgorithm // ignore: cast_nullable_to_non_nullable + as EcKeyAlgorithm, + hashAlgorithm: null == hashAlgorithm + ? _value.hashAlgorithm + : hashAlgorithm // ignore: cast_nullable_to_non_nullable + as Algorithms, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as ContainerCredentialState, + passphrase: freezed == passphrase + ? _value.passphrase + : passphrase // ignore: cast_nullable_to_non_nullable + as String?, + publicServerKey: freezed == publicServerKey + ? _value.publicServerKey + : publicServerKey // ignore: cast_nullable_to_non_nullable + as String?, + publicClientKey: freezed == publicClientKey + ? _value.publicClientKey + : publicClientKey // ignore: cast_nullable_to_non_nullable + as String?, + privateClientKey: freezed == privateClientKey + ? _value.privateClientKey + : privateClientKey // ignore: cast_nullable_to_non_nullable + as String?, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ContainerCredentialUnfinalizedImpl + extends ContainerCredentialUnfinalized { + const _$ContainerCredentialUnfinalizedImpl( + {required this.issuer, + required this.nonce, + required this.timestamp, + required this.finalizationUrl, + required this.serial, + required this.ecKeyAlgorithm, + required this.hashAlgorithm, + this.state = ContainerCredentialState.uninitialized, + this.passphrase, + this.publicServerKey, + this.publicClientKey, + this.privateClientKey, + final String? $type}) + : $type = $type ?? 'unfinalized', + super._(); + + factory _$ContainerCredentialUnfinalizedImpl.fromJson( + Map json) => + _$$ContainerCredentialUnfinalizedImplFromJson(json); + + @override + final String issuer; + @override + final String nonce; + @override + final DateTime timestamp; + @override + final Uri finalizationUrl; + @override + final String serial; + @override + final EcKeyAlgorithm ecKeyAlgorithm; + @override + final Algorithms hashAlgorithm; + @override + @JsonKey() + final ContainerCredentialState state; + @override + final String? passphrase; + @override + final String? publicServerKey; + @override + final String? publicClientKey; + @override + final String? privateClientKey; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'ContainerCredential.unfinalized(issuer: $issuer, nonce: $nonce, timestamp: $timestamp, finalizationUrl: $finalizationUrl, serial: $serial, ecKeyAlgorithm: $ecKeyAlgorithm, hashAlgorithm: $hashAlgorithm, state: $state, passphrase: $passphrase, publicServerKey: $publicServerKey, publicClientKey: $publicClientKey, privateClientKey: $privateClientKey)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ContainerCredentialUnfinalizedImpl && + (identical(other.issuer, issuer) || other.issuer == issuer) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.timestamp, timestamp) || + other.timestamp == timestamp) && + (identical(other.finalizationUrl, finalizationUrl) || + other.finalizationUrl == finalizationUrl) && + (identical(other.serial, serial) || other.serial == serial) && + (identical(other.ecKeyAlgorithm, ecKeyAlgorithm) || + other.ecKeyAlgorithm == ecKeyAlgorithm) && + (identical(other.hashAlgorithm, hashAlgorithm) || + other.hashAlgorithm == hashAlgorithm) && + (identical(other.state, state) || other.state == state) && + (identical(other.passphrase, passphrase) || + other.passphrase == passphrase) && + (identical(other.publicServerKey, publicServerKey) || + other.publicServerKey == publicServerKey) && + (identical(other.publicClientKey, publicClientKey) || + other.publicClientKey == publicClientKey) && + (identical(other.privateClientKey, privateClientKey) || + other.privateClientKey == privateClientKey)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ContainerCredentialUnfinalizedImplCopyWith< + _$ContainerCredentialUnfinalizedImpl> + get copyWith => __$$ContainerCredentialUnfinalizedImplCopyWithImpl< + _$ContainerCredentialUnfinalizedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey) + unfinalized, + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey) + finalized, + }) { + return unfinalized( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + }) { + return unfinalized?.call( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + required TResult orElse(), + }) { + if (unfinalized != null) { + return unfinalized( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(ContainerCredentialUnfinalized value) unfinalized, + required TResult Function(ContainerCredentialFinalized value) finalized, + }) { + return unfinalized(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult? Function(ContainerCredentialFinalized value)? finalized, + }) { + return unfinalized?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult Function(ContainerCredentialFinalized value)? finalized, + required TResult orElse(), + }) { + if (unfinalized != null) { + return unfinalized(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$ContainerCredentialUnfinalizedImplToJson( + this, + ); + } +} + +abstract class ContainerCredentialUnfinalized extends ContainerCredential { + const factory ContainerCredentialUnfinalized( + {required final String issuer, + required final String nonce, + required final DateTime timestamp, + required final Uri finalizationUrl, + required final String serial, + required final EcKeyAlgorithm ecKeyAlgorithm, + required final Algorithms hashAlgorithm, + final ContainerCredentialState state, + final String? passphrase, + final String? publicServerKey, + final String? publicClientKey, + final String? privateClientKey}) = _$ContainerCredentialUnfinalizedImpl; + const ContainerCredentialUnfinalized._() : super._(); + + factory ContainerCredentialUnfinalized.fromJson(Map json) = + _$ContainerCredentialUnfinalizedImpl.fromJson; + + @override + String get issuer; + @override + String get nonce; + @override + DateTime get timestamp; + @override + Uri get finalizationUrl; + @override + String get serial; + @override + EcKeyAlgorithm get ecKeyAlgorithm; + @override + Algorithms get hashAlgorithm; + @override + ContainerCredentialState get state; + @override + String? get passphrase; + @override + String? get publicServerKey; + @override + String? get publicClientKey; + @override + String? get privateClientKey; + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ContainerCredentialUnfinalizedImplCopyWith< + _$ContainerCredentialUnfinalizedImpl> + get copyWith => throw _privateConstructorUsedError; +} + +/// @nodoc +abstract class _$$ContainerCredentialFinalizedImplCopyWith<$Res> + implements $ContainerCredentialCopyWith<$Res> { + factory _$$ContainerCredentialFinalizedImplCopyWith( + _$ContainerCredentialFinalizedImpl value, + $Res Function(_$ContainerCredentialFinalizedImpl) then) = + __$$ContainerCredentialFinalizedImplCopyWithImpl<$Res>; + @override + @useResult + $Res call( + {String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey}); +} + +/// @nodoc +class __$$ContainerCredentialFinalizedImplCopyWithImpl<$Res> + extends _$ContainerCredentialCopyWithImpl<$Res, + _$ContainerCredentialFinalizedImpl> + implements _$$ContainerCredentialFinalizedImplCopyWith<$Res> { + __$$ContainerCredentialFinalizedImplCopyWithImpl( + _$ContainerCredentialFinalizedImpl _value, + $Res Function(_$ContainerCredentialFinalizedImpl) _then) + : super(_value, _then); + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @pragma('vm:prefer-inline') + @override + $Res call({ + Object? issuer = null, + Object? nonce = null, + Object? timestamp = null, + Object? finalizationUrl = null, + Object? serial = null, + Object? ecKeyAlgorithm = null, + Object? hashAlgorithm = null, + Object? state = null, + Object? passphrase = freezed, + Object? publicServerKey = null, + Object? publicClientKey = null, + Object? privateClientKey = null, + }) { + return _then(_$ContainerCredentialFinalizedImpl( + issuer: null == issuer + ? _value.issuer + : issuer // ignore: cast_nullable_to_non_nullable + as String, + nonce: null == nonce + ? _value.nonce + : nonce // ignore: cast_nullable_to_non_nullable + as String, + timestamp: null == timestamp + ? _value.timestamp + : timestamp // ignore: cast_nullable_to_non_nullable + as DateTime, + finalizationUrl: null == finalizationUrl + ? _value.finalizationUrl + : finalizationUrl // ignore: cast_nullable_to_non_nullable + as Uri, + serial: null == serial + ? _value.serial + : serial // ignore: cast_nullable_to_non_nullable + as String, + ecKeyAlgorithm: null == ecKeyAlgorithm + ? _value.ecKeyAlgorithm + : ecKeyAlgorithm // ignore: cast_nullable_to_non_nullable + as EcKeyAlgorithm, + hashAlgorithm: null == hashAlgorithm + ? _value.hashAlgorithm + : hashAlgorithm // ignore: cast_nullable_to_non_nullable + as Algorithms, + state: null == state + ? _value.state + : state // ignore: cast_nullable_to_non_nullable + as ContainerCredentialState, + passphrase: freezed == passphrase + ? _value.passphrase + : passphrase // ignore: cast_nullable_to_non_nullable + as String?, + publicServerKey: null == publicServerKey + ? _value.publicServerKey + : publicServerKey // ignore: cast_nullable_to_non_nullable + as String, + publicClientKey: null == publicClientKey + ? _value.publicClientKey + : publicClientKey // ignore: cast_nullable_to_non_nullable + as String, + privateClientKey: null == privateClientKey + ? _value.privateClientKey + : privateClientKey // ignore: cast_nullable_to_non_nullable + as String, + )); + } +} + +/// @nodoc +@JsonSerializable() +class _$ContainerCredentialFinalizedImpl extends ContainerCredentialFinalized { + const _$ContainerCredentialFinalizedImpl( + {required this.issuer, + required this.nonce, + required this.timestamp, + required this.finalizationUrl, + required this.serial, + required this.ecKeyAlgorithm, + required this.hashAlgorithm, + this.state = ContainerCredentialState.finalized, + this.passphrase, + required this.publicServerKey, + required this.publicClientKey, + required this.privateClientKey, + final String? $type}) + : $type = $type ?? 'finalized', + super._(); + + factory _$ContainerCredentialFinalizedImpl.fromJson( + Map json) => + _$$ContainerCredentialFinalizedImplFromJson(json); + + @override + final String issuer; + @override + final String nonce; + @override + final DateTime timestamp; + @override + final Uri finalizationUrl; + @override + final String serial; + @override + final EcKeyAlgorithm ecKeyAlgorithm; + @override + final Algorithms hashAlgorithm; + @override + @JsonKey() + final ContainerCredentialState state; + @override + final String? passphrase; + @override + final String publicServerKey; + @override + final String publicClientKey; + @override + final String privateClientKey; + + @JsonKey(name: 'runtimeType') + final String $type; + + @override + String toString() { + return 'ContainerCredential.finalized(issuer: $issuer, nonce: $nonce, timestamp: $timestamp, finalizationUrl: $finalizationUrl, serial: $serial, ecKeyAlgorithm: $ecKeyAlgorithm, hashAlgorithm: $hashAlgorithm, state: $state, passphrase: $passphrase, publicServerKey: $publicServerKey, publicClientKey: $publicClientKey, privateClientKey: $privateClientKey)'; + } + + @override + bool operator ==(Object other) { + return identical(this, other) || + (other.runtimeType == runtimeType && + other is _$ContainerCredentialFinalizedImpl && + (identical(other.issuer, issuer) || other.issuer == issuer) && + (identical(other.nonce, nonce) || other.nonce == nonce) && + (identical(other.timestamp, timestamp) || + other.timestamp == timestamp) && + (identical(other.finalizationUrl, finalizationUrl) || + other.finalizationUrl == finalizationUrl) && + (identical(other.serial, serial) || other.serial == serial) && + (identical(other.ecKeyAlgorithm, ecKeyAlgorithm) || + other.ecKeyAlgorithm == ecKeyAlgorithm) && + (identical(other.hashAlgorithm, hashAlgorithm) || + other.hashAlgorithm == hashAlgorithm) && + (identical(other.state, state) || other.state == state) && + (identical(other.passphrase, passphrase) || + other.passphrase == passphrase) && + (identical(other.publicServerKey, publicServerKey) || + other.publicServerKey == publicServerKey) && + (identical(other.publicClientKey, publicClientKey) || + other.publicClientKey == publicClientKey) && + (identical(other.privateClientKey, privateClientKey) || + other.privateClientKey == privateClientKey)); + } + + @JsonKey(includeFromJson: false, includeToJson: false) + @override + int get hashCode => Object.hash( + runtimeType, + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @JsonKey(includeFromJson: false, includeToJson: false) + @override + @pragma('vm:prefer-inline') + _$$ContainerCredentialFinalizedImplCopyWith< + _$ContainerCredentialFinalizedImpl> + get copyWith => __$$ContainerCredentialFinalizedImplCopyWithImpl< + _$ContainerCredentialFinalizedImpl>(this, _$identity); + + @override + @optionalTypeArgs + TResult when({ + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey) + unfinalized, + required TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey) + finalized, + }) { + return finalized( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + + @override + @optionalTypeArgs + TResult? whenOrNull({ + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult? Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + }) { + return finalized?.call( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + + @override + @optionalTypeArgs + TResult maybeWhen({ + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String? publicServerKey, + String? publicClientKey, + String? privateClientKey)? + unfinalized, + TResult Function( + String issuer, + String nonce, + DateTime timestamp, + Uri finalizationUrl, + String serial, + EcKeyAlgorithm ecKeyAlgorithm, + Algorithms hashAlgorithm, + ContainerCredentialState state, + String? passphrase, + String publicServerKey, + String publicClientKey, + String privateClientKey)? + finalized, + required TResult orElse(), + }) { + if (finalized != null) { + return finalized( + issuer, + nonce, + timestamp, + finalizationUrl, + serial, + ecKeyAlgorithm, + hashAlgorithm, + state, + passphrase, + publicServerKey, + publicClientKey, + privateClientKey); + } + return orElse(); + } + + @override + @optionalTypeArgs + TResult map({ + required TResult Function(ContainerCredentialUnfinalized value) unfinalized, + required TResult Function(ContainerCredentialFinalized value) finalized, + }) { + return finalized(this); + } + + @override + @optionalTypeArgs + TResult? mapOrNull({ + TResult? Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult? Function(ContainerCredentialFinalized value)? finalized, + }) { + return finalized?.call(this); + } + + @override + @optionalTypeArgs + TResult maybeMap({ + TResult Function(ContainerCredentialUnfinalized value)? unfinalized, + TResult Function(ContainerCredentialFinalized value)? finalized, + required TResult orElse(), + }) { + if (finalized != null) { + return finalized(this); + } + return orElse(); + } + + @override + Map toJson() { + return _$$ContainerCredentialFinalizedImplToJson( + this, + ); + } +} + +abstract class ContainerCredentialFinalized extends ContainerCredential { + const factory ContainerCredentialFinalized( + {required final String issuer, + required final String nonce, + required final DateTime timestamp, + required final Uri finalizationUrl, + required final String serial, + required final EcKeyAlgorithm ecKeyAlgorithm, + required final Algorithms hashAlgorithm, + final ContainerCredentialState state, + final String? passphrase, + required final String publicServerKey, + required final String publicClientKey, + required final String privateClientKey}) = + _$ContainerCredentialFinalizedImpl; + const ContainerCredentialFinalized._() : super._(); + + factory ContainerCredentialFinalized.fromJson(Map json) = + _$ContainerCredentialFinalizedImpl.fromJson; + + @override + String get issuer; + @override + String get nonce; + @override + DateTime get timestamp; + @override + Uri get finalizationUrl; + @override + String get serial; + @override + EcKeyAlgorithm get ecKeyAlgorithm; + @override + Algorithms get hashAlgorithm; + @override + ContainerCredentialState get state; + @override + String? get passphrase; + @override + String get publicServerKey; + @override + String get publicClientKey; + @override + String get privateClientKey; + + /// Create a copy of ContainerCredential + /// with the given fields replaced by the non-null parameter values. + @override + @JsonKey(includeFromJson: false, includeToJson: false) + _$$ContainerCredentialFinalizedImplCopyWith< + _$ContainerCredentialFinalizedImpl> + get copyWith => throw _privateConstructorUsedError; +} diff --git a/lib/model/tokens/container_credentials.g.dart b/lib/model/tokens/container_credentials.g.dart index 25b4f76c1..1b5666295 100644 --- a/lib/model/tokens/container_credentials.g.dart +++ b/lib/model/tokens/container_credentials.g.dart @@ -6,15 +6,142 @@ part of 'container_credentials.dart'; // JsonSerializableGenerator // ************************************************************************** -ContainerCredential _$ContainerCredentialFromJson(Map json) => - ContainerCredential( +_$ContainerCredentialUnfinalizedImpl + _$$ContainerCredentialUnfinalizedImplFromJson(Map json) => + _$ContainerCredentialUnfinalizedImpl( + issuer: json['issuer'] as String, + nonce: json['nonce'] as String, + timestamp: DateTime.parse(json['timestamp'] as String), + finalizationUrl: Uri.parse(json['finalizationUrl'] as String), + serial: json['serial'] as String, + ecKeyAlgorithm: + $enumDecode(_$EcKeyAlgorithmEnumMap, json['ecKeyAlgorithm']), + hashAlgorithm: + $enumDecode(_$AlgorithmsEnumMap, json['hashAlgorithm']), + state: $enumDecodeNullable( + _$ContainerCredentialStateEnumMap, json['state']) ?? + ContainerCredentialState.uninitialized, + passphrase: json['passphrase'] as String?, + publicServerKey: json['publicServerKey'] as String?, + publicClientKey: json['publicClientKey'] as String?, + privateClientKey: json['privateClientKey'] as String?, + $type: json['runtimeType'] as String?, + ); + +Map _$$ContainerCredentialUnfinalizedImplToJson( + _$ContainerCredentialUnfinalizedImpl instance) => + { + 'issuer': instance.issuer, + 'nonce': instance.nonce, + 'timestamp': instance.timestamp.toIso8601String(), + 'finalizationUrl': instance.finalizationUrl.toString(), + 'serial': instance.serial, + 'ecKeyAlgorithm': _$EcKeyAlgorithmEnumMap[instance.ecKeyAlgorithm]!, + 'hashAlgorithm': _$AlgorithmsEnumMap[instance.hashAlgorithm]!, + 'state': _$ContainerCredentialStateEnumMap[instance.state]!, + 'passphrase': instance.passphrase, + 'publicServerKey': instance.publicServerKey, + 'publicClientKey': instance.publicClientKey, + 'privateClientKey': instance.privateClientKey, + 'runtimeType': instance.$type, + }; + +const _$EcKeyAlgorithmEnumMap = { + EcKeyAlgorithm.brainpoolp160r1: 'brainpoolp160r1', + EcKeyAlgorithm.brainpoolp160t1: 'brainpoolp160t1', + EcKeyAlgorithm.brainpoolp192r1: 'brainpoolp192r1', + EcKeyAlgorithm.brainpoolp192t1: 'brainpoolp192t1', + EcKeyAlgorithm.brainpoolp224r1: 'brainpoolp224r1', + EcKeyAlgorithm.brainpoolp224t1: 'brainpoolp224t1', + EcKeyAlgorithm.brainpoolp256r1: 'brainpoolp256r1', + EcKeyAlgorithm.brainpoolp256t1: 'brainpoolp256t1', + EcKeyAlgorithm.brainpoolp320r1: 'brainpoolp320r1', + EcKeyAlgorithm.brainpoolp320t1: 'brainpoolp320t1', + EcKeyAlgorithm.brainpoolp384r1: 'brainpoolp384r1', + EcKeyAlgorithm.brainpoolp384t1: 'brainpoolp384t1', + EcKeyAlgorithm.brainpoolp512r1: 'brainpoolp512r1', + EcKeyAlgorithm.brainpoolp512t1: 'brainpoolp512t1', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_A: 'GostR3410_2001_CryptoPro_A', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_B: 'GostR3410_2001_CryptoPro_B', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_C: 'GostR3410_2001_CryptoPro_C', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchA: 'GostR3410_2001_CryptoPro_XchA', + EcKeyAlgorithm.GostR3410_2001_CryptoPro_XchB: 'GostR3410_2001_CryptoPro_XchB', + EcKeyAlgorithm.prime192v1: 'prime192v1', + EcKeyAlgorithm.prime192v2: 'prime192v2', + EcKeyAlgorithm.prime192v3: 'prime192v3', + EcKeyAlgorithm.prime239v1: 'prime239v1', + EcKeyAlgorithm.prime239v2: 'prime239v2', + EcKeyAlgorithm.prime239v3: 'prime239v3', + EcKeyAlgorithm.prime256v1: 'prime256v1', + EcKeyAlgorithm.secp112r1: 'secp112r1', + EcKeyAlgorithm.secp112r2: 'secp112r2', + EcKeyAlgorithm.secp128r1: 'secp128r1', + EcKeyAlgorithm.secp128r2: 'secp128r2', + EcKeyAlgorithm.secp160k1: 'secp160k1', + EcKeyAlgorithm.secp160r1: 'secp160r1', + EcKeyAlgorithm.secp160r2: 'secp160r2', + EcKeyAlgorithm.secp192k1: 'secp192k1', + EcKeyAlgorithm.secp192r1: 'secp192r1', + EcKeyAlgorithm.secp224k1: 'secp224k1', + EcKeyAlgorithm.secp224r1: 'secp224r1', + EcKeyAlgorithm.secp256k1: 'secp256k1', + EcKeyAlgorithm.secp256r1: 'secp256r1', + EcKeyAlgorithm.secp384r1: 'secp384r1', + EcKeyAlgorithm.secp521r1: 'secp521r1', +}; + +const _$AlgorithmsEnumMap = { + Algorithms.SHA1: 'SHA1', + Algorithms.SHA256: 'SHA256', + Algorithms.SHA512: 'SHA512', +}; + +const _$ContainerCredentialStateEnumMap = { + ContainerCredentialState.uninitialized: 'uninitialized', + ContainerCredentialState.generatingKeyPair: 'generatingKeyPair', + ContainerCredentialState.generatingKeyPairFailed: 'generatingKeyPairFailed', + ContainerCredentialState.sendingPublicKey: 'sendingPublicKey', + ContainerCredentialState.sendingPublicKeyFailed: 'sendingPublicKeyFailed', + ContainerCredentialState.parsingResponse: 'parsingResponse', + ContainerCredentialState.parsingResponseFailed: 'parsingResponseFailed', + ContainerCredentialState.finalized: 'finalized', +}; + +_$ContainerCredentialFinalizedImpl _$$ContainerCredentialFinalizedImplFromJson( + Map json) => + _$ContainerCredentialFinalizedImpl( + issuer: json['issuer'] as String, + nonce: json['nonce'] as String, + timestamp: DateTime.parse(json['timestamp'] as String), + finalizationUrl: Uri.parse(json['finalizationUrl'] as String), serial: json['serial'] as String, - id: json['id'] as String, + ecKeyAlgorithm: + $enumDecode(_$EcKeyAlgorithmEnumMap, json['ecKeyAlgorithm']), + hashAlgorithm: $enumDecode(_$AlgorithmsEnumMap, json['hashAlgorithm']), + state: $enumDecodeNullable( + _$ContainerCredentialStateEnumMap, json['state']) ?? + ContainerCredentialState.finalized, + passphrase: json['passphrase'] as String?, + publicServerKey: json['publicServerKey'] as String, + publicClientKey: json['publicClientKey'] as String, + privateClientKey: json['privateClientKey'] as String, + $type: json['runtimeType'] as String?, ); -Map _$ContainerCredentialToJson( - ContainerCredential instance) => +Map _$$ContainerCredentialFinalizedImplToJson( + _$ContainerCredentialFinalizedImpl instance) => { - 'id': instance.id, + 'issuer': instance.issuer, + 'nonce': instance.nonce, + 'timestamp': instance.timestamp.toIso8601String(), + 'finalizationUrl': instance.finalizationUrl.toString(), 'serial': instance.serial, + 'ecKeyAlgorithm': _$EcKeyAlgorithmEnumMap[instance.ecKeyAlgorithm]!, + 'hashAlgorithm': _$AlgorithmsEnumMap[instance.hashAlgorithm]!, + 'state': _$ContainerCredentialStateEnumMap[instance.state]!, + 'passphrase': instance.passphrase, + 'publicServerKey': instance.publicServerKey, + 'publicClientKey': instance.publicClientKey, + 'privateClientKey': instance.privateClientKey, + 'runtimeType': instance.$type, }; diff --git a/lib/model/tokens/otp_token.dart b/lib/model/tokens/otp_token.dart index 6d2879ebf..305af46e6 100644 --- a/lib/model/tokens/otp_token.dart +++ b/lib/model/tokens/otp_token.dart @@ -17,12 +17,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import '../enums/encodings.dart'; -import '../extensions/enums/encodings_extension.dart'; import '../../utils/identifiers.dart'; - import '../../utils/logger.dart'; import '../enums/algorithms.dart'; +import '../enums/encodings.dart'; +import '../extensions/enums/encodings_extension.dart'; import '../token_import/token_origin_data.dart'; import 'token.dart'; diff --git a/lib/processors/mixins/token_import_processor.dart b/lib/processors/mixins/token_import_processor.dart index ed816a78a..22307d3be 100644 --- a/lib/processors/mixins/token_import_processor.dart +++ b/lib/processors/mixins/token_import_processor.dart @@ -19,14 +19,17 @@ */ import '../../model/processor_result.dart'; import '../../model/tokens/token.dart'; +import '../../utils/identifiers.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart'; import '../token_import_file_processor/token_import_file_processor_interface.dart'; mixin TokenImportProcessor { + static const resultHandlerType = TypeMatcher(); static Set implementations = { const GoogleAuthenticatorQrProcessor(), ...TokenImportFileProcessor.implementations, }; - Future>> processTokenMigrate(T data, {V args}); + Future>?> processTokenMigrate(T data, {V args}); } diff --git a/lib/processors/scheme_processors/container_credentials_processor.dart b/lib/processors/scheme_processors/container_credentials_processor.dart index 166449b82..9a5c2d093 100644 --- a/lib/processors/scheme_processors/container_credentials_processor.dart +++ b/lib/processors/scheme_processors/container_credentials_processor.dart @@ -17,26 +17,58 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart'; + +import '../../model/processor_result.dart'; +import '../../utils/identifiers.dart'; import 'scheme_processor_interface.dart'; -import '../../utils/globals.dart'; import '../../utils/logger.dart'; import '../../model/tokens/container_credentials.dart'; -import '../../utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart'; class ContainerCredentialsProcessor extends SchemeProcessor { + static const resultHandlerType = TypeMatcher(); + static const scheme = 'pia'; + // static const hosts = {'container': _container}; + @override - Set get supportedSchemes => {'container'}; // TODO: edit supportedSchemes to the real supported schemes - List get supportedHosts => ['credentials']; // TODO: edit supportedHosts to the real supported hosts + Set get supportedSchemes => {scheme}; const ContainerCredentialsProcessor(); @override - Future processUri(Uri uri, {bool fromInit = false}) async { - if (!supportedHosts.contains(uri.host) || !supportedSchemes.contains(uri.scheme)) { - return null; + Future>> processUri(Uri uri, {bool fromInit = false}) async { + if (!supportedSchemes.contains(uri.scheme)) { + Logger.error('Unsupported scheme', name: 'ContainerCredentialsProcessor'); + return []; } final credential = ContainerCredential.fromUriMap(uri.queryParameters); Logger.warning('Adding credential to container', name: 'ContainerCredentialsProcessor'); - globalRef?.read(credentialsNotifierProvider.notifier).addCredential(credential); + return [ + ProcessorResult.success( + credential, + resultHandlerType: resultHandlerType, + ) + ]; } + + // static Future>> _container(Uri uri) async { + // try { + // final credential = ContainerCredential.fromUriMap(uri.queryParameters); + // Logger.info('Processing URI ${uri.scheme} succeded', name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); + // return [ + // ProcessorResult.success( + // credential, + // resultHandlerType: resultHandlerType, + // ) + // ]; + // } catch (e) { + // Logger.error('Error while processing URI ${uri.scheme}', error: e, name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); + // return [ + // ProcessorResult.failed( + // 'Invalid URI', + // resultHandlerType: resultHandlerType, + // ) + // ]; + // } + // } } diff --git a/lib/processors/scheme_processors/home_widget_processor.dart b/lib/processors/scheme_processors/home_widget_processor.dart index 54a05f8b8..d84061fa9 100644 --- a/lib/processors/scheme_processors/home_widget_processor.dart +++ b/lib/processors/scheme_processors/home_widget_processor.dart @@ -17,6 +17,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import '../../model/processor_result.dart'; import '../../utils/home_widget_utils.dart'; import '../../utils/logger.dart'; import 'scheme_processor_interface.dart'; @@ -24,42 +25,96 @@ import 'scheme_processor_interface.dart'; class HomeWidgetProcessor implements SchemeProcessor { const HomeWidgetProcessor(); - static final Map Function(Uri)> _processors = { + static final Map>?> Function(Uri)> _processors = { 'show': _showProcessor, 'copy': _copyProcessor, 'action': _actionProcessor, }; @override - Future processUri(Uri uri, {bool fromInit = false}) async { - if (supportedSchemes.contains(uri.scheme) == false) return; - return _processors[uri.host]?.call(uri); + Future>?> processUri(Uri uri, {bool fromInit = false}) async { + if (supportedSchemes.contains(uri.scheme) == false) return []; + final processor = _processors[uri.host]; + if (processor == null) { + return [ + ProcessorResult.failed( + 'No processor found for host: ${uri.host}', + resultHandlerType: null, + ) + ]; + } + return processor.call(uri); } @override Set get supportedSchemes => {'homewidget'}; - static Future _showProcessor(Uri uri, {bool fromInit = false}) async { + static Future>?> _showProcessor(Uri uri, {bool fromInit = false}) async { Logger.warning('HomeWidgetProcessor: Processing uri show: $uri'); - if (uri.host != 'show') return; + if (uri.host != 'show') { + return [ + ProcessorResult.failed( + 'Invalid host: ${uri.host} for scheme: ${uri.scheme}', + resultHandlerType: null, + ) + ]; + } final widgetId = uri.queryParameters['widgetId']; - if (widgetId == null) return; - return HomeWidgetUtils().showOtp(widgetId); + if (widgetId == null) { + return [ + ProcessorResult.failed( + 'Missing widgetId', + resultHandlerType: null, + ) + ]; + } + HomeWidgetUtils().showOtp(widgetId); + return null; } - static Future _copyProcessor(Uri uri, {bool fromInit = false}) async { + static Future>?> _copyProcessor(Uri uri, {bool fromInit = false}) async { Logger.warning('HomeWidgetProcessor: Processing uri copy: $uri'); - if (uri.host != 'copy') return; + if (uri.host != 'copy') { + return [ + ProcessorResult.failed( + 'Invalid host: ${uri.host} for scheme: ${uri.scheme}', + resultHandlerType: null, + ) + ]; + } final widgetId = uri.queryParameters['widgetId']; - if (widgetId == null) return; - return HomeWidgetUtils().copyOtp(widgetId); + if (widgetId == null) { + return [ + ProcessorResult.failed( + 'Missing widgetId', + resultHandlerType: null, + ) + ]; + } + HomeWidgetUtils().copyOtp(widgetId); + return null; } - static Future _actionProcessor(Uri uri, {bool fromInit = false}) async { + static Future>?> _actionProcessor(Uri uri, {bool fromInit = false}) async { Logger.warning('HomeWidgetProcessor: Processing uri action: $uri'); - if (uri.host != 'action') return; + if (uri.host != 'action') { + return [ + ProcessorResult.failed( + 'Invalid host: ${uri.host} for scheme: ${uri.scheme}', + resultHandlerType: null, + ) + ]; + } final widgetId = uri.queryParameters['widgetId']; - if (widgetId == null) return; - return HomeWidgetUtils().performAction(widgetId); + if (widgetId == null) { + return [ + ProcessorResult.failed( + 'Missing widgetId', + resultHandlerType: null, + ) + ]; + } + HomeWidgetUtils().performAction(widgetId); + return null; } } diff --git a/lib/processors/scheme_processors/navigation_scheme_processors/home_widget_navigate_processor.dart b/lib/processors/scheme_processors/navigation_scheme_processors/home_widget_navigate_processor.dart index 33ef20c33..a29ded304 100644 --- a/lib/processors/scheme_processors/navigation_scheme_processors/home_widget_navigate_processor.dart +++ b/lib/processors/scheme_processors/navigation_scheme_processors/home_widget_navigate_processor.dart @@ -19,47 +19,70 @@ */ import 'package:flutter/material.dart'; +import '../../../model/processor_result.dart'; import '../../../utils/globals.dart'; import '../../../utils/home_widget_utils.dart'; +import '../../../utils/identifiers.dart'; import '../../../utils/logger.dart'; import '../../../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../views/link_home_widget_view/link_home_widget_view.dart'; import 'navigation_scheme_processor_interface.dart'; class HomeWidgetNavigateProcessor implements NavigationSchemeProcessor { + static const resultHandlerType = TypeMatcher(); HomeWidgetNavigateProcessor(); - static final Map Function(Uri, BuildContext, {bool fromInit})> _processors = { + static final Map>?> Function(Uri, BuildContext, {bool fromInit})> _processors = { 'link': _linkHomeWidgetProcessor, 'showlocked': _showLockedHomeWidgetProcessor, }; @override - Future processUri(Uri uri, {BuildContext? context, bool fromInit = false}) async { + Future>?> processUri(Uri uri, {BuildContext? context, bool fromInit = false}) async { if (context == null) { Logger.error( 'HomeWidgetNavigateProcessor: Cannot Navigate without context', error: Exception('context is null'), stackTrace: StackTrace.current, ); - return; + return [ + ProcessorResult.failed( + 'Cannot Navigate without context', + resultHandlerType: resultHandlerType, + ) + ]; } Logger.warning('HomeWidgetNavigateProcessor: Processing uri: $uri'); - return _processors[uri.host]?.call(uri, context, fromInit: fromInit); + final processor = _processors[uri.host]; + if (processor == null) { + Logger.warning('HomeWidgetNavigateProcessor: No processor found for host: ${uri.host}'); + return [ + ProcessorResult.failed( + 'No processor found for host: ${uri.host}', + resultHandlerType: resultHandlerType, + ) + ]; + } + return processor.call(uri, context, fromInit: fromInit); } @override Set get supportedSchemes => {'homewidgetnavigate'}; - static Future _linkHomeWidgetProcessor(Uri uri, BuildContext context, {bool fromInit = false}) async { + static Future>?> _linkHomeWidgetProcessor(Uri uri, BuildContext context, {bool fromInit = false}) async { if (uri.host != 'link') { Logger.warning('HomeWidgetNavigateProcessor: Invalid host for link: ${uri.host}'); - return; + return []; } if (uri.queryParameters['id'] == null) { - Logger.warning('HomeWidgetNavigateProcessor: Invalid query parameters for link: ${uri.queryParameters}'); - return; + Logger.warning('HomeWidgetNavigateProcessor: Missing id for link: ${uri.host}'); + return [ + ProcessorResult.failed( + 'Missing id for link: ${uri.host}', + resultHandlerType: resultHandlerType, + ) + ]; } if (fromInit) { Navigator.of(context).push( @@ -71,16 +94,22 @@ class HomeWidgetNavigateProcessor implements NavigationSchemeProcessor { MaterialPageRoute(builder: (context) => LinkHomeWidgetView(homeWidgetId: uri.queryParameters['id']!)), ); } + return null; } - static Future _showLockedHomeWidgetProcessor(Uri uri, BuildContext context, {bool fromInit = false}) async { + static Future>?> _showLockedHomeWidgetProcessor(Uri uri, BuildContext context, {bool fromInit = false}) async { if (uri.host != 'showlocked') { Logger.warning('Invalid host for showlocked: ${uri.host}', name: 'home_widget_processor.dart#_showLockedHomeWidgetProcessor'); - return; + return []; } if (uri.queryParameters['id'] == null) { Logger.warning('Invalid query parameters for showlocked: ${uri.queryParameters}', name: 'home_widget_processor.dart#_showLockedHomeWidgetProcessor'); - return; + return [ + ProcessorResult.failed( + 'Missing id for showlocked: ${uri.host}', + resultHandlerType: resultHandlerType, + ) + ]; } Logger.info('Showing otp of locked Token of homeWidget: ${uri.queryParameters['id']}', name: 'home_widget_processor.dart#_showLockedHomeWidgetProcessor'); Navigator.popUntil(context, (route) => route.isFirst); @@ -88,12 +117,22 @@ class HomeWidgetNavigateProcessor implements NavigationSchemeProcessor { final tokenId = await HomeWidgetUtils().getTokenIdOfWidgetId(uri.queryParameters['id']!); if (tokenId == null) { Logger.warning('Could not find token for widget id: ${uri.queryParameters['id']}', name: 'home_widget_processor.dart#_showLockedHomeWidgetProcessor'); - return; + return [ + ProcessorResult.failed( + 'Could not find token for widget id: ${uri.queryParameters['id}']}', + resultHandlerType: resultHandlerType, + ) + ]; } await Future.delayed(const Duration(milliseconds: 200)); if (globalRef == null) { Logger.warning('Could not find globalRef', name: 'home_widget_processor.dart#_showLockedHomeWidgetProcessor'); - return; + return [ + ProcessorResult.failed( + 'Could not find globalRef', + resultHandlerType: resultHandlerType, + ) + ]; } final showedToken = await globalRef!.read(tokenProvider.notifier).showTokenById(tokenId); @@ -103,5 +142,34 @@ class HomeWidgetNavigateProcessor implements NavigationSchemeProcessor { globalRef!.read(tokenFolderProvider.notifier).expandFolderById(folderId); } } + return null; + } +} + +class NavigationHandler with ResultHandler { + @override + Future handleProcessorResult(ProcessorResult result, Map args) async { + if (result is! ProcessorResult) return null; + if (result.isFailed) return null; + validateMap(args, {'context': const TypeMatcher()}); + final navigation = result.asSuccess!.resultData; + final BuildContext context = args['context']; + return await navigation(context); + } + + @override + Future?> handleProcessorResults(List results, Map args) async { + final successResults = results.whereType>().toList().successResults; + if (successResults.isEmpty) return null; + validateMap(args, {'context': const TypeMatcher()}); + List navigations = successResults.getData(); + final context = args['context']; + final retunValues = []; + for (final navigation in navigations) { + retunValues.add(await navigation(context)); + } + return retunValues; } } + +typedef Navigation = Future Function(BuildContext context); diff --git a/lib/processors/scheme_processors/navigation_scheme_processors/navigation_scheme_processor_interface.dart b/lib/processors/scheme_processors/navigation_scheme_processors/navigation_scheme_processor_interface.dart index e780e7db1..fc1b13164 100644 --- a/lib/processors/scheme_processors/navigation_scheme_processors/navigation_scheme_processor_interface.dart +++ b/lib/processors/scheme_processors/navigation_scheme_processors/navigation_scheme_processor_interface.dart @@ -19,6 +19,7 @@ */ import 'package:flutter/material.dart'; +import '../../../model/processor_result.dart'; import '../../../utils/globals.dart'; import '../../../utils/logger.dart'; import '../scheme_processor_interface.dart'; @@ -32,7 +33,7 @@ abstract class NavigationSchemeProcessor implements SchemeProcessor { }; @override - Future processUri(Uri uri, {BuildContext? context, bool fromInit = false}); + Future>?> processUri(Uri uri, {BuildContext? context, bool fromInit = false}); static Future processUriByAny(Uri uri, {BuildContext? context, required bool fromInit}) async { if (context == null) { diff --git a/lib/processors/scheme_processors/scheme_processor_interface.dart b/lib/processors/scheme_processors/scheme_processor_interface.dart index 2fe4be6d0..c2be871f8 100644 --- a/lib/processors/scheme_processors/scheme_processor_interface.dart +++ b/lib/processors/scheme_processors/scheme_processor_interface.dart @@ -17,6 +17,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import 'package:privacyidea_authenticator/model/processor_result.dart'; + +import '../../utils/logger.dart'; import 'container_credentials_processor.dart'; import 'home_widget_processor.dart'; import 'navigation_scheme_processors/navigation_scheme_processor_interface.dart'; @@ -26,7 +29,7 @@ import 'token_import_scheme_processors/token_import_scheme_processor_interface.d abstract class SchemeProcessor { const SchemeProcessor(); Set get supportedSchemes; - Future processUri(Uri uri, {bool fromInit = false}); + Future>?> processUri(Uri uri, {bool fromInit = false}); static final List implementations = [ const HomeWidgetProcessor(), @@ -34,12 +37,17 @@ abstract class SchemeProcessor { ...TokenImportSchemeProcessor.implementations, const ContainerCredentialsProcessor(), ]; - static Future processUriByAny(Uri uri, {bool fromInit = false}) async { + static Future>?> processUriByAny(Uri uri, {bool fromInit = false}) async { for (SchemeProcessor processor in implementations) { if (processor.supportedSchemes.contains(uri.scheme)) { - return await processor.processUri(uri); + Logger.info('Processing URI with processor: $processor', name: 'SchemeProcessor#processUriByAny'); + final result = await processor.processUri(uri, fromInit: fromInit); + if (result != null) { + return result; + } } } + Logger.warning('Unsupported scheme', name: 'SchemeProcessor#processUriByAny'); return null; } } diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor.dart index 8f1127437..e532c6279 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/free_otp_plus_qr_processor.dart @@ -25,6 +25,7 @@ import '../../../utils/token_import_origins.dart'; import 'otp_auth_processor.dart'; class FreeOtpPlusQrProcessor extends OtpAuthProcessor { + static get resultHandlerType => OtpAuthProcessor.resultHandlerType; const FreeOtpPlusQrProcessor(); @override @@ -41,6 +42,7 @@ class FreeOtpPlusQrProcessor extends OtpAuthProcessor { isPrivacyIdeaToken: false, data: uri.toString(), ), + resultHandlerType: resultHandlerType, ); }).toList(); return resultsWithOrigin; diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart index 7803d7224..6ac05a12f 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/google_authenticator_qr_processor.dart @@ -36,6 +36,7 @@ import 'otp_auth_processor.dart'; import 'token_import_scheme_processor_interface.dart'; class GoogleAuthenticatorQrProcessor extends TokenImportSchemeProcessor { + static get resultHandlerType => OtpAuthProcessor.resultHandlerType; const GoogleAuthenticatorQrProcessor(); static const OtpAuthProcessor otpAuthProcessor = OtpAuthProcessor(); @@ -123,7 +124,7 @@ class GoogleAuthenticatorQrProcessor extends TokenImportSchemeProcessor { error: e, stackTrace: StackTrace.current, ); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed(e.toString(), resultHandlerType: resultHandlerType)); continue; } } @@ -137,6 +138,7 @@ class GoogleAuthenticatorQrProcessor extends TokenImportSchemeProcessor { isPrivacyIdeaToken: false, data: base64.encode(decoded), ), + resultHandlerType: resultHandlerType, ); }).toList(); return resultsWithOrigin; diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart index 66136558c..aa8b10eb1 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/otp_auth_processor.dart @@ -42,13 +42,21 @@ import '../../../widgets/dialog_widgets/two_step_dialog.dart'; import 'token_import_scheme_processor_interface.dart'; class OtpAuthProcessor extends TokenImportSchemeProcessor { + static get resultHandlerType => TokenImportSchemeProcessor.resultHandlerType; const OtpAuthProcessor(); @override Set get supportedSchemes => {'otpauth'}; @override Future>> processUri(Uri uri, {bool fromInit = false}) async { - if (!supportedSchemes.contains(uri.scheme)) return [ProcessorResultFailed('The scheme [${uri.scheme}] not supported')]; + if (!supportedSchemes.contains(uri.scheme)) { + return [ + ProcessorResultFailed( + 'The scheme [${uri.scheme}] not supported', + resultHandlerType: resultHandlerType, + ) + ]; + } Logger.info('Try to handle otpAuth:', name: 'token_notifier.dart#addTokenFromOtpAuth'); Map uriMap; try { @@ -57,7 +65,12 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { if (e is LocalizedException) { Logger.warning('Error while parsing otpAuth.', name: 'token_notifier.dart#addTokenFromOtpAuth', error: e.unlocalizedMessage, stackTrace: s); final message = globalContextSync != null ? e.localizedMessage(AppLocalizations.of(globalContextSync!)!) : e.unlocalizedMessage; - return [ProcessorResult.failed(message)]; + return [ + ProcessorResult.failed( + message, + resultHandlerType: resultHandlerType, + ) + ]; } String? message; if (e is ArgumentError) { @@ -65,10 +78,20 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { message = '${e.message} - ${e.name}: ${e.invalidValue}'; } message ??= 'An error occurred while parsing the QR code.'; - return [ProcessorResult.failed(globalContextSync != null ? AppLocalizations.of(globalContextSync!)?.tokenDataParseError ?? message : message)]; + return [ + ProcessorResult.failed( + globalContextSync != null ? AppLocalizations.of(globalContextSync!)?.tokenDataParseError ?? message : message, + resultHandlerType: resultHandlerType, + ) + ]; } if (_is2StepURI(uri)) { - validateMap(uriMap, [URI_SECRET, URI_ITERATIONS, URI_OUTPUT_LENGTH_IN_BYTES, URI_SALT_LENGTH]); + validateMap(uriMap, { + URI_SECRET: TypeMatcher(), + URI_ITERATIONS: TypeMatcher(), + URI_OUTPUT_LENGTH_IN_BYTES: TypeMatcher(), + URI_SALT_LENGTH: TypeMatcher(), + }); final secret = uriMap[URI_SECRET] as Uint8List; // Calculate the whole secret. @@ -82,7 +105,12 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { ), )); if (twoStepSecret == null) { - return [const ProcessorResultFailed('The two step secret could not be generated, or was canceled.')]; + return [ + ProcessorResultFailed( + 'The two step secret could not be generated, or was canceled.', + resultHandlerType: resultHandlerType, + ) + ]; } uriMap[URI_SECRET] = twoStepSecret; } @@ -98,13 +126,28 @@ class OtpAuthProcessor extends TokenImportSchemeProcessor { ); } on FormatException catch (e) { Logger.warning('Error while parsing otpAuth.', name: 'token_notifier.dart#addTokenFromOtpAuth', error: e); - return [ProcessorResultFailed(e.message)]; + return [ + ProcessorResultFailed( + e.message, + resultHandlerType: resultHandlerType, + ) + ]; } catch (e, s) { Logger.warning('Error while parsing otpAuth.', name: 'token_notifier.dart#addTokenFromOtpAuth', error: e, stackTrace: s); // showMessage(message: 'An error occurred while parsing the QR code.', duration: const Duration(seconds: 3)); - return [const ProcessorResultFailed('An error occurred while parsing the QR code.')]; + return [ + ProcessorResultFailed( + 'An error occurred while parsing the QR code.', + resultHandlerType: resultHandlerType, + ) + ]; } - return [ProcessorResultSuccess(newToken)]; + return [ + ProcessorResultSuccess( + newToken, + resultHandlerType: resultHandlerType, + ) + ]; } } diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/privacyidea_authenticator_qr_processor.dart b/lib/processors/scheme_processors/token_import_scheme_processors/privacyidea_authenticator_qr_processor.dart index c49b97edb..685e0d670 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/privacyidea_authenticator_qr_processor.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/privacyidea_authenticator_qr_processor.dart @@ -24,6 +24,7 @@ import '../../../utils/logger.dart'; import 'token_import_scheme_processor_interface.dart'; class PrivacyIDEAAuthenticatorQrProcessor extends TokenImportSchemeProcessor { + static get resultHandlerType => TokenImportSchemeProcessor.resultHandlerType; const PrivacyIDEAAuthenticatorQrProcessor(); static const scheme = 'pia'; static const host = 'qrbackup'; @@ -32,19 +33,32 @@ class PrivacyIDEAAuthenticatorQrProcessor extends TokenImportSchemeProcessor { Set get supportedSchemes => {scheme}; @override - Future>> processUri(Uri uri, {bool fromInit = false}) async { - if (!supportedSchemes.contains(uri.scheme) || uri.host != host) { - Logger.warning('Unsupported scheme or host'); - return []; + Future>?> processUri(Uri uri, {bool fromInit = false}) async { + if (!supportedSchemes.contains(uri.scheme)) { + return null; + } + if (uri.host != host) { + Logger.warning('Unsupported scheme or host', name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); + return null; } Logger.info('Processing URI with scheme: ${uri.scheme}', name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); try { final token = TokenEncryption.fromExportUri(uri); Logger.info('Processing URI ${uri.scheme} succeded', name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); - return [ProcessorResult.success(token)]; + return [ + ProcessorResult.success( + token, + resultHandlerType: resultHandlerType, + ) + ]; } catch (e) { Logger.error('Error while processing URI ${uri.scheme}', error: e, name: 'PrivacyIDEAAuthenticatorQrProcessor#processUri'); - return [ProcessorResult.failed('Invalid URI')]; + return [ + ProcessorResult.failed( + 'Invalid URI', + resultHandlerType: resultHandlerType, + ) + ]; } } } diff --git a/lib/processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart b/lib/processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart index 615b38e81..5759107de 100644 --- a/lib/processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart +++ b/lib/processors/scheme_processors/token_import_scheme_processors/token_import_scheme_processor_interface.dart @@ -13,10 +13,12 @@ * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ + import '../../../model/processor_result.dart'; import '../../../model/tokens/token.dart'; import '../../mixins/token_import_processor.dart'; @@ -26,6 +28,7 @@ import 'otp_auth_processor.dart'; import 'privacyidea_authenticator_qr_processor.dart'; abstract class TokenImportSchemeProcessor with TokenImportProcessor implements SchemeProcessor { + static get resultHandlerType => TokenImportProcessor.resultHandlerType; const TokenImportSchemeProcessor(); static Set get allSupportedSchemes => { @@ -44,10 +47,10 @@ abstract class TokenImportSchemeProcessor with TokenImportProcessor i /// data: [Uri] uri /// args: [bool] fromInit - Future>> processTokenMigrate(Uri data, {bool args = false}) => processUri(data, fromInit: args); + Future>?> processTokenMigrate(Uri data, {bool args = false}) => processUri(data, fromInit: args); @override - Future>> processUri(Uri uri, {bool fromInit = false}); + Future>?> processUri(Uri uri, {bool fromInit = false}); static Future>?> processUriByAny(Uri uri) async { for (TokenImportSchemeProcessor processor in implementations) { @@ -55,6 +58,6 @@ abstract class TokenImportSchemeProcessor with TokenImportProcessor i return await processor.processUri(uri); } } - return null; + return []; } } diff --git a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart index 5939e0e10..ed6e4280b 100644 --- a/lib/processors/token_import_file_processor/aegis_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/aegis_import_file_processor.dart @@ -61,6 +61,8 @@ void _isolatedKdf(List args) { } class AegisImportFileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; + const AegisImportFileProcessor(); static const String AEGIS_TYPE = 'type'; @@ -163,7 +165,10 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { if (entry['type'] != 'totp' && entry['type'] != 'hotp') { // TODO: support other token types Logger.warning('Unsupported token type: ${entry['type']}', name: '_processPlain#OtpAuthImportFileProcessor'); - results.add(ProcessorResult.failed(localization?.unsupported('token type', entry['type']) ?? 'Unsupported token type: ${entry['type']}')); + results.add(ProcessorResult.failed( + localization?.unsupported('token type', entry['type']) ?? 'Unsupported token type: ${entry['type']}', + resultHandlerType: resultHandlerType, + )); continue; } Map info = entry['info']; @@ -184,12 +189,21 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { ), }; final token = Token.fromUriMap(entryUriMap); - results.add(ProcessorResult.success(token.copyWith(id: entry[AEGIS_ID]))); + results.add(ProcessorResult.success( + token.copyWith(id: entry[AEGIS_ID]), + resultHandlerType: resultHandlerType, + )); } on LocalizedException catch (e) { - results.add(ProcessorResult.failed(localization != null ? e.localizedMessage(localization) : e.unlocalizedMessage)); + results.add(ProcessorResult.failed( + localization != null ? e.localizedMessage(localization) : e.unlocalizedMessage, + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'AegisImportFileProcessor#_processPlain', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResult.failed(e.toString())); + results.add(ProcessorResult.failed( + e.toString(), + resultHandlerType: resultHandlerType, + )); } } return Future.value(results); @@ -204,7 +218,10 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { if (doesThrow(() => TokenTypes.values.byName((entry['type'] as String).toUpperCase()))) { // TODO: support other token types Logger.warning('Unsupported token type: ${entry['type']}', name: '_processPlain#OtpAuthImportFileProcessor'); - results.add(ProcessorResult.failed(localization?.unsupported('token type', entry['type']) ?? 'Unsupported token type: ${entry['type']}')); + results.add(ProcessorResult.failed( + localization?.unsupported('token type', entry['type']) ?? 'Unsupported token type: ${entry['type']}', + resultHandlerType: resultHandlerType, + )); continue; } Map info = entry['info']; @@ -224,12 +241,21 @@ class AegisImportFileProcessor extends TokenImportFileProcessor { data: jsonEncode(entry), ), }; - results.add(ProcessorResult.success(Token.fromUriMap(entryUriMap))); + results.add(ProcessorResult.success( + Token.fromUriMap(entryUriMap), + resultHandlerType: resultHandlerType, + )); } on LocalizedException catch (e) { - results.add(ProcessorResultFailed(localization != null ? e.localizedMessage(localization) : e.unlocalizedMessage)); + results.add(ProcessorResultFailed( + localization != null ? e.localizedMessage(localization) : e.unlocalizedMessage, + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'AegisImportFileProcessor#_processPlain', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed( + e.toString(), + resultHandlerType: resultHandlerType, + )); } } diff --git a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart index a7d7559b1..b9b55290e 100644 --- a/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/authenticator_pro_import_file_processor.dart @@ -45,6 +45,7 @@ import '../../utils/token_import_origins.dart'; import 'token_import_file_processor_interface.dart'; class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; static const String header = "AUTHENTICATORPRO"; static const String headerLegacy = "AuthenticatorPro"; @@ -160,7 +161,9 @@ class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { token: t.resultData, isPrivacyIdeaToken: false, data: t.resultData.origin!.data, - )); + ), + resultHandlerType: resultHandlerType, + ); }).toList(); } @@ -250,10 +253,16 @@ class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { final newResults = await const OtpAuthProcessor().processUri(uri); results.addAll(newResults); } on LocalizedException catch (e) { - results.add(ProcessorResultFailed(e.localizedMessage(AppLocalizations.of(await globalContext)!))); + results.add(ProcessorResultFailed( + e.localizedMessage(AppLocalizations.of(await globalContext)!), + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'authenticator_pro_import_file_processor#_processUriList', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed( + e.toString(), + resultHandlerType: resultHandlerType, + )); } } return results; @@ -280,15 +289,22 @@ class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { token: newResult.resultData, data: uri.toString(), ), + resultHandlerType: resultHandlerType, ), ); } } } on LocalizedException catch (e) { - results.add(ProcessorResultFailed(e.localizedMessage(AppLocalizations.of(await globalContext)!))); + results.add(ProcessorResultFailed( + e.localizedMessage(AppLocalizations.of(await globalContext)!), + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'authenticator_pro_import_file_processor#_processHtml', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed( + e.toString(), + resultHandlerType: resultHandlerType, + )); } return results; } @@ -321,12 +337,20 @@ class AuthenticatorProImportFileProcessor extends TokenImportFileProcessor { }; final token = Token.fromUriMap(uriMap); - result.add(ProcessorResultSuccess(token)); + result.add(ProcessorResultSuccess( + token, + resultHandlerType: resultHandlerType, + )); } on LocalizedException catch (e) { - result.add(ProcessorResultFailed(e.localizedMessage(AppLocalizations.of(await globalContext)!))); + result.add(ProcessorResultFailed( + e.localizedMessage(AppLocalizations.of(await globalContext)!), + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'authenticator_pro_import_file_processor#_processAuthPro', error: e, stackTrace: StackTrace.current); - result.add(ProcessorResultFailed(e.toString())); + result.add(ProcessorResultFailed(e.toString(), + resultHandlerType: resultHandlerType, + )); } } return result; diff --git a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart index 48b6d6b14..404dbfddc 100644 --- a/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/free_otp_plus_import_file_processor.dart @@ -38,6 +38,7 @@ import '../scheme_processors/token_import_scheme_processors/free_otp_plus_qr_pro import 'token_import_file_processor_interface.dart'; class FreeOtpPlusImportFileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; static const String _FREE_OTP_PLUS_ALGORITHM = 'algo'; // String: "MD5", "SHA1", "SHA256", "SHA512" static const String _FREE_OTP_PLUS_COUNTER = 'counter'; static const String _FREE_OTP_PLUS_DIGITS = 'digits'; @@ -88,17 +89,22 @@ class FreeOtpPlusImportFileProcessor extends TokenImportFileProcessor { results.addAll(await const FreeOtpPlusQrProcessor().processUri(uri)); } catch (e) { Logger.error('Failed to process line: $line', name: 'FreeOtpPlusFileProcessor#processFile', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed(e.toString(), + resultHandlerType: resultHandlerType, + )); } } return results.map((t) { if (t is! ProcessorResultSuccess) return t; - return ProcessorResultSuccess(TokenOriginSourceType.backupFile.addOriginToToken( - appName: TokenImportOrigins.freeOtpPlus.appName, - token: t.resultData, - isPrivacyIdeaToken: false, - data: t.resultData.origin!.data, - )); + return ProcessorResultSuccess( + TokenOriginSourceType.backupFile.addOriginToToken( + appName: TokenImportOrigins.freeOtpPlus.appName, + token: t.resultData, + isPrivacyIdeaToken: false, + data: t.resultData.origin!.data, + ), + resultHandlerType: resultHandlerType, + ); }).toList(); } @@ -116,12 +122,21 @@ class FreeOtpPlusImportFileProcessor extends TokenImportFileProcessor { Future> _processJsonToken(Map tokenJson) async { try { - return ProcessorResultSuccess(Token.fromUriMap(_jsonToUriMap(tokenJson))); + return ProcessorResultSuccess( + Token.fromUriMap(_jsonToUriMap(tokenJson)), + resultHandlerType: resultHandlerType, + ); } on LocalizedException catch (e) { - return ProcessorResultFailed(e.localizedMessage(AppLocalizations.of(await globalContext)!)); + return ProcessorResultFailed( + e.localizedMessage(AppLocalizations.of(await globalContext)!), + resultHandlerType: resultHandlerType, + ); } catch (e) { Logger.error('Failed to parse token.', name: 'FreeOtpPlusFileProcessor#_processJsonToken', error: e, stackTrace: StackTrace.current); - return ProcessorResultFailed(e.toString()); + return ProcessorResultFailed( + e.toString(), + resultHandlerType: resultHandlerType, + ); } } diff --git a/lib/processors/token_import_file_processor/google_authenticator_qrfile_processor.dart b/lib/processors/token_import_file_processor/google_authenticator_qrfile_processor.dart index 3c5554f6e..f3658c46d 100644 --- a/lib/processors/token_import_file_processor/google_authenticator_qrfile_processor.dart +++ b/lib/processors/token_import_file_processor/google_authenticator_qrfile_processor.dart @@ -38,6 +38,7 @@ import '../scheme_processors/token_import_scheme_processors/google_authenticator import 'token_import_file_processor_interface.dart'; class GoogleAuthenticatorQrfileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; const GoogleAuthenticatorQrfileProcessor(); @override Future fileIsValid(XFile file) async { @@ -115,6 +116,7 @@ class GoogleAuthenticatorQrfileProcessor extends TokenImportFileProcessor { isPrivacyIdeaToken: false, data: t.resultData.origin?.data ?? qrResult!.text, ), + resultHandlerType: resultHandlerType, ); }).toList(); return processorResults; diff --git a/lib/processors/token_import_file_processor/privacyidea_authenticator_import_file_processor.dart b/lib/processors/token_import_file_processor/privacyidea_authenticator_import_file_processor.dart index 46c64a6e7..9adf79b9b 100644 --- a/lib/processors/token_import_file_processor/privacyidea_authenticator_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/privacyidea_authenticator_import_file_processor.dart @@ -29,6 +29,7 @@ import 'token_import_file_processor_interface.dart'; import 'two_fas_import_file_processor.dart'; class PrivacyIDEAAuthenticatorImportFileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; const PrivacyIDEAAuthenticatorImportFileProcessor(); @override Future fileIsValid(XFile file) async { @@ -59,12 +60,22 @@ class PrivacyIDEAAuthenticatorImportFileProcessor extends TokenImportFileProcess } catch (e) { throw BadDecryptionPasswordException('Invalid password'); } - final results = tokens.map((token) => ProcessorResultSuccess(token)).toList(); + final results = tokens + .map((token) => ProcessorResult.success( + token, + resultHandlerType: resultHandlerType, + )) + .toList(); return results; } catch (e) { if (e is BadDecryptionPasswordException) rethrow; Logger.error('Failed to process file', name: 'PrivacyIDEAAuthenticatorImportFileProcessor#processFile', error: e, stackTrace: StackTrace.current); - return [ProcessorResultFailed(e.toString())]; + return [ + ProcessorResult.failed( + e.toString(), + resultHandlerType: resultHandlerType, + ) + ]; } } } diff --git a/lib/processors/token_import_file_processor/token_import_file_processor_interface.dart b/lib/processors/token_import_file_processor/token_import_file_processor_interface.dart index 5be6c4810..09fc782c9 100644 --- a/lib/processors/token_import_file_processor/token_import_file_processor_interface.dart +++ b/lib/processors/token_import_file_processor/token_import_file_processor_interface.dart @@ -27,6 +27,7 @@ import 'aegis_import_file_processor.dart'; import 'two_fas_import_file_processor.dart'; abstract class TokenImportFileProcessor with TokenImportProcessor { + static get resultHandlerType => TokenImportProcessor.resultHandlerType; const TokenImportFileProcessor(); @override diff --git a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart index 4a5be5458..1d2a06e16 100644 --- a/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart +++ b/lib/processors/token_import_file_processor/two_fas_import_file_processor.dart @@ -40,6 +40,7 @@ import '../../utils/token_import_origins.dart'; import 'token_import_file_processor_interface.dart'; class TwoFasAuthenticatorImportFileProcessor extends TokenImportFileProcessor { + static get resultHandlerType => TokenImportFileProcessor.resultHandlerType; const TwoFasAuthenticatorImportFileProcessor(); static const String TWOFAS_TYPE = 'tokenType'; static const String TWOFAS_ISSUER = 'name'; @@ -145,12 +146,20 @@ class TwoFasAuthenticatorImportFileProcessor extends TokenImportFileProcessor { final results = >[]; for (Map twoFasToken in tokensJsonList) { try { - results.add(ProcessorResultSuccess(Token.fromUriMap(_twoFasToUriMap(twoFasToken)))); + results.add(ProcessorResult.success( + Token.fromUriMap(_twoFasToUriMap(twoFasToken)), + resultHandlerType: resultHandlerType, + )); } on LocalizedException catch (e) { - results.add(ProcessorResultFailed(e.localizedMessage(AppLocalizations.of(await globalContext)!))); + results.add(ProcessorResultFailed( + e.localizedMessage(AppLocalizations.of(await globalContext)!), + resultHandlerType: resultHandlerType, + )); } catch (e) { Logger.error('Failed to parse token.', name: 'two_fas_import_file_processor.dart#_processPlainTokens', error: e, stackTrace: StackTrace.current); - results.add(ProcessorResultFailed(e.toString())); + results.add(ProcessorResultFailed(e.toString(), + resultHandlerType: resultHandlerType, + )); } } Logger.info('successfully imported ${results.length} tokens', name: 'two_fas_import_file_processor.dart#processPlainTokens'); diff --git a/lib/repo/secure_container_credentials_repository.dart b/lib/repo/secure_container_credentials_repository.dart index 9b74b5422..e912546ae 100644 --- a/lib/repo/secure_container_credentials_repository.dart +++ b/lib/repo/secure_container_credentials_repository.dart @@ -4,13 +4,14 @@ import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:mutex/mutex.dart'; import '../interfaces/repo/container_credentials_repository.dart'; +import '../model/enums/algorithms.dart'; import '../model/riverpod_states/credentials_state.dart'; import '../model/tokens/container_credentials.dart'; import '../utils/logger.dart'; class SecureContainerCredentialsRepository extends ContainerCredentialsRepository { String get containerCredentialsKey => 'containerCredentials'; - String _keyOfId(String id) => '$containerCredentialsKey.$id'; + String _keyOfSerial(String id) => '$containerCredentialsKey.$id'; final Mutex _m = Mutex(); Future _protect(Future Function() f) => _m.protect(f); final FlutterSecureStorage _storage = const FlutterSecureStorage(); @@ -27,9 +28,17 @@ class SecureContainerCredentialsRepository extends ContainerCredentialsRepositor Logger.warning('Loaded credentials: $credentialsJsonString', name: 'SecureContainerCredentialsRepository'); if (credentialsJsonString.isEmpty) { final credentialState = CredentialsState(credentials: [ - ContainerCredential( - id: '123', + ContainerCredential.finalized( serial: '123', + ecKeyAlgorithm: EcKeyAlgorithm.secp256k1, + hashAlgorithm: Algorithms.SHA256, + issuer: '', + nonce: '', + timestamp: DateTime.now(), + finalizationUrl: Uri(), + publicServerKey: '', + publicClientKey: '', + privateClientKey: '', ), ]); Logger.warning('Returning default credentials: $credentialState', name: 'SecureContainerCredentialsRepository'); @@ -51,7 +60,7 @@ class SecureContainerCredentialsRepository extends ContainerCredentialsRepositor @override Future deleteCredential(String id) async { - await _delete(_keyOfId(id)); + await _delete(_keyOfSerial(id)); return await loadCredentialsState(); } @@ -68,7 +77,7 @@ class SecureContainerCredentialsRepository extends ContainerCredentialsRepositor @override Future loadCredential(String id) async { - final credentialJsonString = await _read(_keyOfId(id)); + final credentialJsonString = await _read(_keyOfSerial(id)); if (credentialJsonString == null) return null; return ContainerCredential.fromJson(jsonDecode(credentialJsonString)); } @@ -76,7 +85,7 @@ class SecureContainerCredentialsRepository extends ContainerCredentialsRepositor @override Future saveCredential(ContainerCredential credential) async { final credentialJsonString = jsonEncode(credential.toJson()); - await _write(_keyOfId(credential.id), credentialJsonString); + await _write(_keyOfSerial(credential.serial), credentialJsonString); return await loadCredentialsState(); } } diff --git a/lib/repo/secure_token_repository.dart b/lib/repo/secure_token_repository.dart index bf256bfcc..1ff0aae19 100644 --- a/lib/repo/secure_token_repository.dart +++ b/lib/repo/secure_token_repository.dart @@ -34,7 +34,7 @@ import '../model/tokens/token.dart'; import '../utils/globals.dart'; import '../utils/identifiers.dart'; import '../utils/logger.dart'; -import '../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../utils/view_utils.dart'; import '../views/settings_view/settings_view_widgets/send_error_dialog.dart'; import '../widgets/dialog_widgets/default_dialog.dart'; diff --git a/lib/utils/customization/application_customization.dart b/lib/utils/customization/application_customization.dart index 03930bfb9..a54a8491f 100644 --- a/lib/utils/customization/application_customization.dart +++ b/lib/utils/customization/application_customization.dart @@ -21,6 +21,7 @@ import 'dart:convert'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; + import '../../../utils/customization/theme_customization.dart'; import '../../model/enums/app_feature.dart'; import '../../model/enums/image_file_type.dart'; diff --git a/lib/utils/home_widget_utils.dart b/lib/utils/home_widget_utils.dart index 5a4a330b0..8ed054344 100644 --- a/lib/utils/home_widget_utils.dart +++ b/lib/utils/home_widget_utils.dart @@ -50,7 +50,7 @@ import '../widgets/home_widgets/home_widget_otp.dart'; import '../widgets/home_widgets/home_widget_unlinked.dart'; import 'globals.dart'; import 'logger.dart'; -import 'riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'riverpod/riverpod_providers/state_providers/home_widget_provider.dart'; const appGroupId = 'group.authenticator_home_widget_group'; diff --git a/lib/utils/identifiers.dart b/lib/utils/identifiers.dart index 2925890b1..4dea2674f 100644 --- a/lib/utils/identifiers.dart +++ b/lib/utils/identifiers.dart @@ -27,6 +27,11 @@ const defaultCrashReportRecipient = 'app-crash@netknights.it'; // qr codes: const String URI_ID = 'URI_ID'; const String URI_SERIAL = 'URI_SERIAL'; +const String URI_NONCE = 'URI_NONCE'; +const String URI_TIMESTAMP = 'URI_TIMESTAMP'; +const String URI_FINALIZATION_URL = 'URI_FINALIZATION_URL'; +const String URI_KEY_ALGORITHM = 'URI_KEY_ALGORITHM'; +const String URI_HASH_ALGORITHM = 'URI_HASH_ALGORITHM'; const String URI_CONTAINER_SERIAL = 'URI_CONTAINER_SERIAL'; const String URI_TYPE = 'URI_TYPE'; const String URI_LABEL = 'URI_LABEL'; @@ -67,13 +72,30 @@ const String PUSH_REQUEST_SSL_VERIFY = 'sslverify'; // 6. const String PUSH_REQUEST_SIGNATURE = 'signature'; // 7. const String PUSH_REQUEST_ANSWERS = 'require_presence'; // 8. +// Container registration: +const String PUBLIC_SERVER_KEY = 'PUBLIC_SERVER_KEY'; + const String GLOBAL_SECURE_REPO_PREFIX = 'app_v3_'; -bool validateMap(Map map, List keys) { - for (String key in keys) { - if (!map.containsKey(key)) { - return false; +void validateMap(Map map, Map keys) { + for (String key in keys.keys) { + final type = keys[key]!; + if (!type.isTypeOf(map[key])) { + throw ArgumentError('Map does not contain required key "$key" of type $type'); } } - return true; +} + +class TypeMatcher { + const TypeMatcher(); + bool isTypeOf(dynamic value) => value is T; + + @override + String toString() => 'TypeMatcher<${T.runtimeType}>'; + + @override + bool operator ==(Object other) => other is TypeMatcher; + + @override + int get hashCode => toString().hashCode; } diff --git a/lib/utils/push_provider.dart b/lib/utils/push_provider.dart index 773084b6e..b9c53467e 100644 --- a/lib/utils/push_provider.dart +++ b/lib/utils/push_provider.dart @@ -38,7 +38,7 @@ import 'globals.dart'; import 'logger.dart'; import 'privacyidea_io_client.dart'; import 'riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import 'riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'riverpod/riverpod_providers/state_providers/status_message_provider.dart'; import 'rsa_utils.dart'; import 'utils.dart'; diff --git a/lib/utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart similarity index 100% rename from lib/utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart diff --git a/lib/utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.g.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.g.dart similarity index 79% rename from lib/utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.g.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.g.dart index bdb32253e..c96e565a8 100644 --- a/lib/utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.g.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.g.dart @@ -6,14 +6,18 @@ part of 'app_constraints_notifier.dart'; // RiverpodGenerator // ************************************************************************** -String _$appConstraintsNotifierHash() => r'6b6633ada94116eb933767ab1e29aeecf3e4397c'; +String _$appConstraintsNotifierHash() => + r'6b6633ada94116eb933767ab1e29aeecf3e4397c'; /// See also [AppConstraintsNotifier]. @ProviderFor(AppConstraintsNotifier) -final appConstraintsNotifierProvider = AutoDisposeNotifierProvider.internal( +final appConstraintsNotifierProvider = AutoDisposeNotifierProvider< + AppConstraintsNotifier, BoxConstraints?>.internal( AppConstraintsNotifier.new, name: r'appConstraintsNotifierProvider', - debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') ? null : _$appConstraintsNotifierHash, + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$appConstraintsNotifierHash, dependencies: null, allTransitiveDependencies: null, ); diff --git a/lib/utils/riverpod/riverpod_providers/state_providers/application_customizer_provider.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/application_customizer_provider.dart similarity index 100% rename from lib/utils/riverpod/riverpod_providers/state_providers/application_customizer_provider.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/application_customizer_provider.dart diff --git a/lib/utils/riverpod/riverpod_providers/state_providers/application_customizer_provider.g.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/application_customizer_provider.g.dart similarity index 100% rename from lib/utils/riverpod/riverpod_providers/state_providers/application_customizer_provider.g.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/application_customizer_provider.g.dart diff --git a/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart index 4b60bf66e..51e97b73e 100644 --- a/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart @@ -17,26 +17,37 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +import 'dart:convert'; + +import 'package:basic_utils/basic_utils.dart'; +import 'package:collection/collection.dart'; import 'package:mutex/mutex.dart'; +import 'package:privacyidea_authenticator/model/processor_result.dart'; +import 'package:privacyidea_authenticator/utils/globals.dart'; +import 'package:privacyidea_authenticator/utils/identifiers.dart'; +import 'package:privacyidea_authenticator/utils/privacyidea_io_client.dart'; import 'package:riverpod_annotation/riverpod_annotation.dart'; import '../../../../interfaces/repo/container_credentials_repository.dart'; import '../../../../model/riverpod_states/credentials_state.dart'; import '../../../../model/tokens/container_credentials.dart'; import '../../../../repo/secure_container_credentials_repository.dart'; +import '../../../../widgets/dialog_widgets/enter_passphrase_dialog.dart'; import '../../../logger.dart'; part 'credential_notifier.g.dart'; @Riverpod(keepAlive: true) -class CredentialsNotifier extends _$CredentialsNotifier { +class CredentialsNotifier extends _$CredentialsNotifier with ResultHandler { final _stateMutex = Mutex(); final _repoMutex = Mutex(); + late PrivacyideaIOClient _ioClient; late ContainerCredentialsRepository _repo; @override Future build() async { _repo = SecureContainerCredentialsRepository(); + _ioClient = const PrivacyideaIOClient(); Logger.warning('Building credentialsProvider', name: 'CredentialsNotifier'); return _repo.loadCredentialsState(); } @@ -52,40 +63,110 @@ class CredentialsNotifier extends _$CredentialsNotifier { Future addCredential(ContainerCredential credential) async { await _stateMutex.acquire(); - final newState = await _saveCredentialsToRepo(credential); + final newState = await _saveCredentialToRepo(credential); + state = AsyncValue.data(newState); + _stateMutex.release(); + return newState; + } + + Future addCredentials(List credentials) async { + await _stateMutex.acquire(); + final newCredentials = credentials.toList(); + final oldCredentials = (await future).credentials; + final combinedCredentials = []; + for (var oldCredential in oldCredentials) { + final newCredential = newCredentials.firstWhereOrNull((newCredential) => newCredential.serial == oldCredential.serial); + if (newCredential == null) { + combinedCredentials.add(oldCredential); + } else { + combinedCredentials.add(newCredential); + newCredentials.remove(newCredential); + } + } + combinedCredentials.addAll(newCredentials); + final newState = await _saveCredentialsStateToRepo(CredentialsState(credentials: combinedCredentials)); state = AsyncValue.data(newState); _stateMutex.release(); return newState; } - Future _saveCredentialsToRepo(ContainerCredential credential) async { + Future _saveCredentialToRepo(ContainerCredential credential) async { return await _repoMutex.protect(() async => await _repo.saveCredential(credential)); } -} -class MockContainerCredentialsRepository extends ContainerCredentialsRepository { - final state = CredentialsState(credentials: [ - ContainerCredential( - id: '123', - serial: '123', - ) - ]); + Future _saveCredentialsStateToRepo(CredentialsState credentialsState) async { + return await _repoMutex.protect(() async => await _repo.saveCredentialsState(credentialsState)); + } - @override - Future deleteAllCredentials() => Future.value(state); + Future handleCredentialResults(List> credentialResults) async { + final containerCredentials = credentialResults.getData(); + if (containerCredentials.isEmpty) { + return future; + } + final currentState = await future; + final stateCredentials = currentState.credentials; + final stateCredentialsSerials = stateCredentials.map((e) => e.serial); + final newCredentials = containerCredentials.where((element) => !stateCredentialsSerials.contains(element.serial)).toList(); + return addCredentials(newCredentials); + } - @override - Future deleteCredential(String id) => Future.value(state); + Future finalize(ContainerCredential credential) async { + await _stateMutex.acquire(); + if (credential is! ContainerCredentialUnfinalized) { + throw ArgumentError('Credential must not be finalized'); + } - @override - Future loadCredential(String id) => Future.value(state.credentials.firstOrNull); + final keyPair = CryptoUtils.generateEcKeyPair(curve: credential.ecKeyAlgorithm.curveName); - @override - Future loadCredentialsState() => Future.value(state); + credential = credential.withClientKeyPair(keyPair) as ContainerCredentialUnfinalized; + final ecPrivateClientKey = credential.ecPrivateClientKey!; + //POST /container/register/finalize + // Request: { + // 'container_serial': , + // 'public_client_key': , + // 'signature': )>, + // } + + final passphrase = credential.passphrase != null ? EnterPassphraseDialog.show(await globalContext) : null; + + final message = '${credential.nonce}' + '|${credential.timestamp}' + '|${credential.finalizationUrl}' + '|${credential.serial}' + '${passphrase != null ? '|$passphrase' : ''}'; + + final signature = const EccUtils().trySignWithPrivateKey(ecPrivateClientKey, message); + + final body = { + 'container_serial': credential.serial, + 'public_client_key': credential.publicClientKey, + 'signature': signature, + }; + + final response = await _ioClient.doPost(url: credential.finalizationUrl, body: body); + final Map responseJson; + final ContainerCredentialFinalized finalizedCredential; + try { + responseJson = jsonDecode(response.body); + validateMap(responseJson, {PUBLIC_SERVER_KEY: TypeMatcher()}); + final publicServerKey = const EccUtils().deserializeECPublicKey(responseJson[PUBLIC_SERVER_KEY]); + finalizedCredential = credential.finalize(publicServerKey: publicServerKey)!; + } catch (e) { + Logger.error('Failed to decode response body', error: e, name: 'CredentialsNotifier#finalize'); + return null; + } + return await addCredential(finalizedCredential); + } @override - Future saveCredential(ContainerCredential credential) => Future.value(state); + Future handleProcessorResult(ProcessorResult result, Map args) { + // TODO: implement handleResult + throw UnimplementedError(); + } @override - Future saveCredentialsState(CredentialsState credentialsState) => Future.value(state); + Future handleProcessorResults(List results, Map args) { + // TODO: implement handleResults + throw UnimplementedError(); + } } diff --git a/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.g.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.g.dart index 423e3cd42..97911d4b9 100644 --- a/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.g.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.g.dart @@ -7,7 +7,7 @@ part of 'credential_notifier.dart'; // ************************************************************************** String _$credentialsNotifierHash() => - r'459a5bf82645911570b3c7947743ff2f959fa751'; + r'f2f6e55487b59136bb7ce6aa3e05df96d3d8fd82'; /// See also [CredentialsNotifier]. @ProviderFor(CredentialsNotifier) diff --git a/lib/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart index eda7701e5..a3c21ff4f 100644 --- a/lib/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart @@ -26,7 +26,7 @@ import '../../../../model/mixins/sortable_mixin.dart'; import '../../../../model/token_folder.dart'; import '../../../../model/tokens/token.dart'; import 'token_folder_notifier.dart'; -import '../state_notifier_providers/token_notifier.dart'; +import 'token_notifier.dart'; part 'sortable_notifier.g.dart'; diff --git a/lib/utils/riverpod/riverpod_providers/generated_providers/token_container_notifier.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/token_container_notifier.dart index a60733c1a..1ac5ca1bb 100644 --- a/lib/utils/riverpod/riverpod_providers/generated_providers/token_container_notifier.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/token_container_notifier.dart @@ -29,7 +29,7 @@ import '../../../../repo/token_container_state_repositorys/hybrid_token_containe import '../../../../repo/token_container_state_repositorys/remote_token_container_state_repository.dart'; import '../../../../repo/token_container_state_repositorys/secure_token_container_state_repository.dart.dart'; import '../../../../model/tokens/container_credentials.dart'; -import '../state_notifier_providers/token_notifier.dart'; +import 'token_notifier.dart'; part 'token_container_notifier.g.dart'; diff --git a/lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart similarity index 91% rename from lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart index 533c97763..3b6749e30 100644 --- a/lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart @@ -57,7 +57,7 @@ import '../../../privacyidea_io_client.dart'; import '../../../rsa_utils.dart'; import '../../../utils.dart'; import '../../../view_utils.dart'; -import '../generated_providers/settings_notifier.dart'; +import 'settings_notifier.dart'; import '../state_providers/status_message_provider.dart'; part 'token_notifier.g.dart'; @@ -69,27 +69,8 @@ final tokenProvider = tokenNotifierProviderOf( repo: const SecureTokenRepository(), ); -// StateNotifierProvider( -// (ref) { -// Logger.info("New TokenNotifier created"); -// final newTokenNotifier = TokenNotifier(ref: ref); - -// ref.listen(deeplinkNotifierProvider, (previous, newLink) { -// newLink.whenData( -// (data) { -// Logger.info("Received new deeplink with data: $data", name: 'tokenProvider#deeplinkProvider'); -// newTokenNotifier.handleLink(data.uri); -// }, -// ); -// }); - -// return newTokenNotifier; -// }, -// name: 'tokenProvider', -// ); - @Riverpod(keepAlive: true) -class TokenNotifier extends _$TokenNotifier { +class TokenNotifier extends _$TokenNotifier with ResultHandler { static final Map _hidingTimers = {}; late final Future initState; // final StateNotifierProviderRef ref; @@ -257,7 +238,7 @@ class TokenNotifier extends _$TokenNotifier { return false; } _repoMutex.release(); - _handlePushTokensIfExist(); + handlePushTokensIfExist(); return true; } @@ -280,7 +261,7 @@ class TokenNotifier extends _$TokenNotifier { return failedTokens; } _repoMutex.release(); - _handlePushTokensIfExist(); + handlePushTokensIfExist(); return []; } @@ -303,7 +284,7 @@ class TokenNotifier extends _$TokenNotifier { return state; } _repoMutex.release(); - _handlePushTokensIfExist(); + handlePushTokensIfExist(); return newState; } @@ -384,17 +365,23 @@ class TokenNotifier extends _$TokenNotifier { /// Adds a new token and returns true if successful, false if not. Future addNewToken(Token token) async { final success = await _addOrReplaceToken(token); - await _handlePushTokensIfExist(); + await handlePushTokensIfExist(); return success; } + Future addNewTokens(List tokens) async { + final failedTokens = await _addOrReplaceTokens(tokens); + await handlePushTokensIfExist(); + return failedTokens.isEmpty; + } + /// Adds or replaces a token and returns true if successful, false if not. Future addOrReplaceToken(Token token) => _addOrReplaceToken(token); /// Adds new tokens and returns the tokens that could not be added. Future> addTokens(List tokens) async { final failedTokens = await _addOrReplaceTokens(tokens); - await _handlePushTokensIfExist(); + await handlePushTokensIfExist(); return failedTokens; } @@ -886,83 +873,58 @@ class TokenNotifier extends _$TokenNotifier { /////////////////////////////////////////////////////////////////////////////// /// Does not need to wait for updating functions because they doesn't depend on any state */ - /// The return value of a qrCode could be any object. In this case should be a String that is a valid URI. - /// If it is not a valid URI, the user will be informed. - Future handleQrCode(Object? qrCode) async { - Uri uri; - try { - qrCode as String; - uri = Uri.parse(qrCode); - } catch (_) { - showMessage(message: 'The scanned QR code is not a valid URI.', duration: const Duration(seconds: 3)); - Logger.warning('Scanned Data: $qrCode', error: 'Scanned QR code is not a valid URI.', name: 'token_notifier.dart#handleQrCode'); - return; - } - List tokens = await _tokensFromUri(uri); - tokens = tokens - .map( - (e) => e.copyWith( - origin: e.origin?.copyWith(source: TokenOriginSourceType.qrScan) ?? - TokenOriginSourceType.qrScan.toTokenOrigin(data: uri.toString(), isPrivacyIdeaToken: null), - ), - ) - .toList(); - - await _addOrReplaceTokens(tokens); - await _handlePushTokensIfExist(); + Future handleLink(Uri uri) async { + final tokenResults = await TokenImportSchemeProcessor.processUriByAny(uri); + if (tokenResults == null) return; + await handleProcessorResults(tokenResults, {'TokenOriginSourceType': TokenOriginSourceType.link}); } - Future handleLink(Uri uri) async { - List tokens = await _tokensFromUri(uri); - tokens = tokens - .map((e) => e.copyWith( - origin: e.origin?.copyWith(source: TokenOriginSourceType.link) ?? - TokenOriginSourceType.link.toTokenOrigin(data: uri.toString(), isPrivacyIdeaToken: null))) - .toList(); - await _addOrReplaceTokens(tokens); - await _handlePushTokensIfExist(); + @override + Future handleProcessorResult(ProcessorResult result, Map args) { + // TODO: implement handleResult + throw UnimplementedError(); } - Future> _tokensFromUri(Uri uri) async { - if (!TokenImportSchemeProcessor.allSupportedSchemes.contains(uri.scheme)) { - return Future.value([]); - } + @override + Future handleProcessorResults(List results, Map args) async { + final List> tokenResults = results.whereType>().toList(); + if (tokenResults.isEmpty) return null; + final List resultTokens = tokenResults.getData(); + final stateTokens = state.tokens; + List? tokensToKeep; + final selectedType = (args['TokenImportType'] as TokenImportType?) ?? TokenImportType.qrScan; + try { - final results = await TokenImportSchemeProcessor.processUriByAny(uri); - if (results == null || results.isEmpty) { - showMessage(message: 'The scanned QR code is not a valid URI.', duration: const Duration(seconds: 3)); - Logger.warning('Scanned Data: $uri', error: 'Scanned QR code is not a valid URI.', name: 'token_notifier.dart#handleQrCode'); - return []; - } - final failedResults = results.whereType().toList(); - for (var failedResult in failedResults) { - ref.read(statusMessageProvider.notifier).state = (AppLocalizations.of((await globalContext))!.malformedData, failedResult.message); - } - final successResults = results.whereType>().toList(); - if (successResults.isEmpty) { - return []; - } - if (successResults.length > 1 || state.tokens.any((e) => successResults.first.resultData.isSameTokenAs(e) == true)) { + if (resultTokens.length > 1 || stateTokens.any((e) => resultTokens.first.isSameTokenAs(e) == true)) { Navigator.of(globalNavigatorKey.currentContext!).popUntil((route) => route.isFirst); - final tokensToKeep = await Navigator.of(globalNavigatorKey.currentContext!).push>( + tokensToKeep = await Navigator.of(globalNavigatorKey.currentContext!).push>( MaterialPageRoute>( builder: (context) => ImportPlainTokensPage( titleName: AppLocalizations.of(context)!.importTokens, - processorResults: results, - selectedType: TokenImportType.qrScan, + processorResults: tokenResults, + selectedType: selectedType, ), ), ); - return tokensToKeep ?? []; + } else { + tokensToKeep = resultTokens; } - return successResults.map((e) => e.resultData).toList(); } catch (error, stackTrace) { Logger.error('Error while processing QR code.', name: 'token_notifier.dart#handleQrCode', error: error, stackTrace: stackTrace); - return []; + return null; } + if (tokensToKeep == null) return null; + tokensToKeep = tokensToKeep + .map((e) => e.copyWith( + origin: e.origin?.copyWith(source: TokenOriginSourceType.link) ?? + TokenOriginSourceType.link.toTokenOrigin(data: 'No Origindata available', isPrivacyIdeaToken: null))) + .toList(); + await handlePushTokensIfExist(); + await addNewTokens(tokensToKeep); + return null; } - /* ///////////////////////////////////////////////////////////////////////////// +/* ///////////////////////////////////////////////////////////////////////////// /////////////////////////// Helper Methods ///////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// */ @@ -980,7 +942,7 @@ class TokenNotifier extends _$TokenNotifier { } } - Future _handlePushTokensIfExist() async { + Future handlePushTokensIfExist() async { Logger.info('Handling push tokens if they exist.', name: 'token_notifier.dart#_handlePushTokensIfExist'); final pushTokens = state.pushTokens; if (pushTokens.isEmpty || state.pushTokens.isEmpty) { @@ -1012,11 +974,3 @@ class TokenNotifier extends _$TokenNotifier { _hidingTimers.clear(); } } - - - - - - - -// } diff --git a/lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.g.dart b/lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.g.dart similarity index 98% rename from lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.g.dart rename to lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.g.dart index 26ff19f6b..83c5c0f93 100644 --- a/lib/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.g.dart +++ b/lib/utils/riverpod/riverpod_providers/generated_providers/token_notifier.g.dart @@ -6,7 +6,7 @@ part of 'token_notifier.dart'; // RiverpodGenerator // ************************************************************************** -String _$tokenNotifierHash() => r'056041b8761574fb7ff5682ddee48012d15bb2ae'; +String _$tokenNotifierHash() => r'f367f6acf72448089aa9f5b45b2f1e1dba5d0097'; /// Copied from Dart SDK class _SystemHash { diff --git a/lib/utils/riverpod/riverpod_providers/state_providers/home_widget_provider.dart b/lib/utils/riverpod/riverpod_providers/state_providers/home_widget_provider.dart index 1abb5aad8..7a6dcfe16 100644 --- a/lib/utils/riverpod/riverpod_providers/state_providers/home_widget_provider.dart +++ b/lib/utils/riverpod/riverpod_providers/state_providers/home_widget_provider.dart @@ -22,7 +22,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../model/tokens/otp_token.dart'; import '../../../home_widget_utils.dart'; import '../../../logger.dart'; -import '../state_notifier_providers/token_notifier.dart'; +import '../generated_providers/token_notifier.dart'; final homeWidgetProvider = StateProvider>( (ref) { diff --git a/lib/utils/riverpod/riverpod_providers/stream_providers/connectivity_provider.dart b/lib/utils/riverpod/riverpod_providers/stream_providers/connectivity_provider.dart index 8415ae790..06803aa12 100644 --- a/lib/utils/riverpod/riverpod_providers/stream_providers/connectivity_provider.dart +++ b/lib/utils/riverpod/riverpod_providers/stream_providers/connectivity_provider.dart @@ -23,7 +23,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../globals.dart'; import '../../../logger.dart'; -import '../state_notifier_providers/token_notifier.dart'; +import '../generated_providers/token_notifier.dart'; import '../state_providers/status_message_provider.dart'; final connectivityProvider = StreamProvider>( diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 8883b2ff9..967230394 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -21,6 +21,7 @@ import 'dart:convert'; import 'dart:io'; +import 'package:collection/collection.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; @@ -29,16 +30,21 @@ import 'package:package_info_plus/package_info_plus.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:privacyidea_authenticator/mains/main_netknights.dart'; import 'package:privacyidea_authenticator/model/extensions/sortable_list.dart'; +import 'package:privacyidea_authenticator/processors/scheme_processors/scheme_processor_interface.dart'; +import 'package:privacyidea_authenticator/utils/identifiers.dart'; import 'package:privacyidea_authenticator/utils/logger.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart'; +import '../model/enums/token_origin_source_type.dart'; import '../model/mixins/sortable_mixin.dart'; +import '../model/processor_result.dart'; import '../model/token_folder.dart'; import '../model/tokens/token.dart'; import 'customization/application_customization.dart' show ApplicationCustomization; import 'riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'riverpod/riverpod_providers/state_providers/dragging_sortable_provider.dart'; +import 'view_utils.dart'; /// Inserts [char] at the position [pos] in the given String ([str]), /// and returns the resulting String. @@ -174,3 +180,63 @@ void dragSortableOnAccept({ }); }); } + +ByteData bigIntToByteData(BigInt bigInt) { + final data = ByteData((bigInt.bitLength / 8).ceil()); + + for (var i = 1; i <= data.lengthInBytes; i++) { + data.setUint8(data.lengthInBytes - i, bigInt.toUnsigned(8).toInt()); + bigInt = bigInt >> 8; + } + + return data; +} + +BigInt byteDataToBigInt(ByteData data) { + BigInt result = BigInt.zero; + for (var i = 0; i < data.lengthInBytes; i++) { + result = result << 8; + result = result | BigInt.from(data.getUint8(i)); + } + return result; +} + +Uint8List bigIntToBytes(BigInt bigInt) => bigIntToByteData(bigInt).buffer.asUint8List(); + +BigInt bytesToBigInt(Uint8List bytes) => byteDataToBigInt(ByteData.sublistView(bytes)); + +Future scanQrCode(List resultHandlerList, Object? qrCode) async { + Uri uri; + try { + uri = switch (qrCode.runtimeType) { + const (String) => Uri.parse(qrCode as String), + const (Uri) => qrCode as Uri, + _ => throw ArgumentError('Invalid type for qrCode: $qrCode'), + }; + } catch (e) { + showMessage(message: 'The scanned QR code is not a valid URI.', duration: const Duration(seconds: 3)); + Logger.warning('Scanned Data: $qrCode', error: 'Scanned QR code is not a valid URI: $e', name: 'utils.dart#scanQrCode'); + return; + } + final processorResults = await SchemeProcessor.processUriByAny(uri); + if (processorResults == null) return; + final resultHandlerTypeMap = , List>{}; + + for (var result in processorResults) { + final typeMatcher = result.resultHandlerType; + if (typeMatcher == null) continue; + if (resultHandlerTypeMap.containsKey(result.resultHandlerType)) { + resultHandlerTypeMap[typeMatcher]!.add(result); + } else { + resultHandlerTypeMap[typeMatcher] = [result]; + } + } + + for (var resultHandlerType in resultHandlerTypeMap.keys) { + final results = resultHandlerTypeMap[resultHandlerType]!; + final resultHandler = resultHandlerList.firstWhereOrNull((resultHandler) => resultHandlerType.isTypeOf(resultHandler)); + if (resultHandler != null) { + await resultHandler.handleProcessorResults(results, {'TokenOriginSourceType': TokenOriginSourceType.qrScan}); + } + } +} diff --git a/lib/views/add_token_manually_view/add_token_manually_view.dart b/lib/views/add_token_manually_view/add_token_manually_view.dart index bdaf397f8..6d837409e 100644 --- a/lib/views/add_token_manually_view/add_token_manually_view.dart +++ b/lib/views/add_token_manually_view/add_token_manually_view.dart @@ -33,7 +33,7 @@ import '../../model/extensions/enums/token_origin_source_type.dart'; import '../../model/tokens/token.dart'; import '../../utils/identifiers.dart'; import '../../utils/logger.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'add_token_manually_view_widgets/labeled_dropdown_button.dart'; class AddTokenManuallyView extends ConsumerStatefulWidget { diff --git a/lib/views/import_tokens_view/import_tokens_view.dart b/lib/views/import_tokens_view/import_tokens_view.dart index bc073b843..83959eccc 100644 --- a/lib/views/import_tokens_view/import_tokens_view.dart +++ b/lib/views/import_tokens_view/import_tokens_view.dart @@ -23,7 +23,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../l10n/app_localizations.dart'; import '../../model/token_import/token_import_origin.dart'; import '../../model/tokens/token.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../utils/token_import_origins.dart'; import '../view_interface.dart'; import 'pages/import_start_page.dart'; diff --git a/lib/views/import_tokens_view/pages/import_encrypted_data_page.dart b/lib/views/import_tokens_view/pages/import_encrypted_data_page.dart index ee73e5502..926f52979 100644 --- a/lib/views/import_tokens_view/pages/import_encrypted_data_page.dart +++ b/lib/views/import_tokens_view/pages/import_encrypted_data_page.dart @@ -134,6 +134,7 @@ class _ImportEncryptedDataPageState extends State { () async { try { final processorResults = await widget.processor.processTokenMigrate(widget.data, args: _passwordController.text); + if (processorResults == null) return; _pushImportPlainTokensPage(processorResults); } on BadDecryptionPasswordException catch (_) { setState(() { diff --git a/lib/views/import_tokens_view/pages/import_plain_tokens_page.dart b/lib/views/import_tokens_view/pages/import_plain_tokens_page.dart index e9256a404..9e254bb1b 100644 --- a/lib/views/import_tokens_view/pages/import_plain_tokens_page.dart +++ b/lib/views/import_tokens_view/pages/import_plain_tokens_page.dart @@ -26,7 +26,7 @@ import '../../../model/extensions/enums/token_import_type_extension.dart'; import '../../../model/processor_result.dart'; import '../../../model/token_import/token_import_entry.dart'; import '../../../model/tokens/token.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../import_tokens_view.dart'; import '../widgets/conflicted_import_tokens_list.dart'; import '../widgets/failed_imports_list.dart'; diff --git a/lib/views/import_tokens_view/pages/import_start_page.dart b/lib/views/import_tokens_view/pages/import_start_page.dart index b055bf613..42d72cc95 100644 --- a/lib/views/import_tokens_view/pages/import_start_page.dart +++ b/lib/views/import_tokens_view/pages/import_start_page.dart @@ -23,6 +23,8 @@ import 'package:file_selector/file_selector.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:path_provider/path_provider.dart'; +import 'package:privacyidea_authenticator/utils/identifiers.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'package:zxing2/qrcode.dart'; import 'package:zxing2/zxing2.dart'; @@ -228,6 +230,7 @@ class _ImportStartPageState extends ConsumerState { isPrivacyIdeaToken: false, data: t.resultData.origin?.data ?? fileString, ), + resultHandlerType: const TypeMatcher(), ); }).toList(); @@ -250,6 +253,11 @@ class _ImportStartPageState extends ConsumerState { return; } var results = await schemeProcessor.processUri(uri); + if (results == null || results.isEmpty) { + if (mounted == false) return; + setState(() => _errorText = localizations.invalidQrScan(widget.appName)); + return; + } results = results.map>((t) { if (t is! ProcessorResultSuccess) return t; return ProcessorResultSuccess( @@ -259,6 +267,7 @@ class _ImportStartPageState extends ConsumerState { token: t.resultData, data: t.resultData.origin?.data ?? uri.toString(), ), + resultHandlerType: const TypeMatcher(), ); }).toList(); Logger.info("QR code scanned successfully", name: "_scanQrCode#ImportStartPage"); @@ -340,19 +349,22 @@ class _ImportStartPageState extends ConsumerState { return; } var results = await schemeProcessor.processUri(uri); - if (results.isEmpty) { + if (results == null || results.isEmpty) { if (!mounted) return; setState(() => _errorText = localizations.invalidLink(widget.appName)); return; } results = results.map>((t) { if (t is! ProcessorResultSuccess) return t; - return ProcessorResultSuccess(TokenOriginSourceType.linkImport.addOriginToToken( - appName: widget.appName, - token: t.resultData, - isPrivacyIdeaToken: false, - data: _linkController.text, - )); + return ProcessorResultSuccess( + TokenOriginSourceType.linkImport.addOriginToToken( + appName: widget.appName, + token: t.resultData, + isPrivacyIdeaToken: false, + data: _linkController.text, + ), + resultHandlerType: const TypeMatcher(), + ); }).toList(); if (!mounted) return; setState(() => FocusScope.of(context).unfocus()); diff --git a/lib/views/link_home_widget_view/link_home_widget_view.dart b/lib/views/link_home_widget_view/link_home_widget_view.dart index d12ad2414..11a2e9820 100644 --- a/lib/views/link_home_widget_view/link_home_widget_view.dart +++ b/lib/views/link_home_widget_view/link_home_widget_view.dart @@ -24,7 +24,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../utils/customization/theme_extentions/extended_text_theme.dart'; import '../../utils/home_widget_utils.dart'; import '../../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../utils/utils.dart'; import '../view_interface.dart'; diff --git a/lib/views/main_view/main_view_widgets/connectivity_listener.dart b/lib/views/main_view/main_view_widgets/connectivity_listener.dart index 96d489594..da1eef86b 100644 --- a/lib/views/main_view/main_view_widgets/connectivity_listener.dart +++ b/lib/views/main_view/main_view_widgets/connectivity_listener.dart @@ -23,7 +23,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../l10n/app_localizations.dart'; import '../../../utils/logger.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../utils/riverpod/riverpod_providers/state_providers/status_message_provider.dart'; import '../../../utils/riverpod/riverpod_providers/stream_providers/connectivity_provider.dart'; diff --git a/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_actions.dart/delete_token_folder_action.dart b/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_actions.dart/delete_token_folder_action.dart index 5ba7758df..dfb16ed79 100644 --- a/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_actions.dart/delete_token_folder_action.dart +++ b/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_actions.dart/delete_token_folder_action.dart @@ -26,7 +26,7 @@ import '../../../../../utils/customization/theme_extentions/action_theme.dart'; import '../../../../../utils/globals.dart'; import '../../../../../utils/lock_auth.dart'; import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; class DeleteTokenFolderAction extends StatelessWidget { diff --git a/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_expandable.dart b/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_expandable.dart index 93bffbbd2..6524eb07c 100644 --- a/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_expandable.dart +++ b/lib/views/main_view/main_view_widgets/folder_widgets/token_folder_expandable.dart @@ -36,7 +36,7 @@ import '../../../../utils/globals.dart'; import '../../../../utils/lock_auth.dart'; import '../../../../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import '../../../../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../utils/riverpod/riverpod_providers/state_providers/dragging_sortable_provider.dart'; import '../../../../utils/utils.dart'; import '../../../../widgets/custom_trailing.dart'; diff --git a/lib/views/main_view/main_view_widgets/main_view_navigation_bar.dart b/lib/views/main_view/main_view_widgets/main_view_navigation_bar.dart index ef8f0d27f..115785088 100644 --- a/lib/views/main_view/main_view_widgets/main_view_navigation_bar.dart +++ b/lib/views/main_view/main_view_widgets/main_view_navigation_bar.dart @@ -23,7 +23,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../l10n/app_localizations.dart'; import '../../../model/enums/introduction.dart'; import '../../../utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; -import '../../../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; import '../../../widgets/focused_item_as_overlay.dart'; import '../../add_token_manually_view/add_token_manually_view.dart'; import '../../settings_view/settings_view.dart'; diff --git a/lib/views/main_view/main_view_widgets/main_view_navigation_buttons/qr_scanner_button.dart b/lib/views/main_view/main_view_widgets/main_view_navigation_buttons/qr_scanner_button.dart index 6c72becd3..c863381e5 100644 --- a/lib/views/main_view/main_view_widgets/main_view_navigation_buttons/qr_scanner_button.dart +++ b/lib/views/main_view/main_view_widgets/main_view_navigation_buttons/qr_scanner_button.dart @@ -20,10 +20,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:permission_handler/permission_handler.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/credential_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../l10n/app_localizations.dart'; +import '../../../../model/processor_result.dart'; import '../../../../utils/globals.dart'; -import '../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../utils/utils.dart'; import '../../../../utils/view_utils.dart'; import '../../../../widgets/dialog_widgets/default_dialog.dart'; import '../../../qr_scanner_view/qr_scanner_view.dart'; @@ -47,7 +50,11 @@ class QrScannerButton extends ConsumerWidget { /// Open the QR-code scanner and call `handleQrCode`, with the scanned code as the argument. Navigator.pushNamed(globalNavigatorKey.currentContext!, QRScannerView.routeName).then((qrCode) { - if (qrCode != null) ref.read(tokenProvider.notifier).handleQrCode(qrCode); + final resultHandlers = [ + ref.read(tokenProvider.notifier), + ref.read(credentialsNotifierProvider.notifier), + ]; + scanQrCode(resultHandlers, qrCode); }); }, tooltip: AppLocalizations.of(context)!.scanQrCode, diff --git a/lib/views/main_view/main_view_widgets/main_view_tokens_list_filtered.dart b/lib/views/main_view/main_view_widgets/main_view_tokens_list_filtered.dart index ed4c76819..f050de719 100644 --- a/lib/views/main_view/main_view_widgets/main_view_tokens_list_filtered.dart +++ b/lib/views/main_view/main_view_widgets/main_view_tokens_list_filtered.dart @@ -26,7 +26,7 @@ import '../../../model/token_folder.dart'; import '../../../model/tokens/token.dart'; import '../../../utils/logger.dart'; import '../../../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../utils/riverpod/riverpod_providers/state_providers/token_filter_provider.dart'; import 'folder_widgets/token_folder_expandable.dart'; import 'token_widgets/token_widget_builder.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/day_password_token_widgets/day_password_token_widget_tile.dart b/lib/views/main_view/main_view_widgets/token_widgets/day_password_token_widgets/day_password_token_widget_tile.dart index 43dd2f0b2..7373d8ae5 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/day_password_token_widgets/day_password_token_widget_tile.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/day_password_token_widgets/day_password_token_widget_tile.dart @@ -29,7 +29,7 @@ import '../../../../../model/enums/day_password_token_view_mode.dart'; import '../../../../../model/riverpod_states/settings_state.dart'; import '../../../../../model/tokens/day_password_token.dart'; import '../../../../../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../utils/utils.dart'; import '../../../../../widgets/custom_texts.dart'; import '../../../../../widgets/custom_trailing.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart index f8fc74b74..bc6943fed 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_delete_action.dart @@ -25,7 +25,7 @@ import '../../../../../model/tokens/token.dart'; import '../../../../../utils/customization/theme_extentions/action_theme.dart'; import '../../../../../utils/globals.dart'; import '../../../../../utils/lock_auth.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; import '../../loading_indicator.dart'; import '../token_action.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action.dart b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action.dart index 3efc4d557..85ba8ba2f 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action.dart @@ -29,7 +29,7 @@ import '../../../../../utils/globals.dart'; import '../../../../../utils/lock_auth.dart'; import '../../../../../utils/logger.dart'; import '../../../../../utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/focused_item_as_overlay.dart'; import '../token_action.dart'; import 'default_edit_action_dialog.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action_dialog.dart b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action_dialog.dart index 156cf6317..1569e4d87 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action_dialog.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_edit_action_dialog.dart @@ -26,7 +26,7 @@ import '../../../../../l10n/app_localizations.dart'; import '../../../../../model/tokens/token.dart'; import '../../../../../utils/globals.dart'; import '../../../../../utils/logger.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; class DefaultEditActionDialog extends ConsumerStatefulWidget { diff --git a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_lock_action.dart b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_lock_action.dart index b2b4ea986..0adfe03a5 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_lock_action.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/default_token_actions/default_lock_action.dart @@ -29,7 +29,7 @@ import '../../../../../utils/customization/theme_extentions/action_theme.dart'; import '../../../../../utils/lock_auth.dart'; import '../../../../../utils/logger.dart'; import '../../../../../utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/focused_item_as_overlay.dart'; import '../token_action.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart b/lib/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart index 5c71591f5..4ec8c0bf0 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/hotp_token_widgets/hotp_token_widget_tile.dart @@ -24,7 +24,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../../l10n/app_localizations.dart'; import '../../../../../model/tokens/hotp_token.dart'; import '../../../../../utils/globals.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../utils/utils.dart'; import '../../../../../widgets/custom_texts.dart'; import '../../../../../widgets/custom_trailing.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/actions/edit_push_token_action.dart b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/actions/edit_push_token_action.dart index 02b2e1c59..e2d2caa17 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/actions/edit_push_token_action.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/actions/edit_push_token_action.dart @@ -28,7 +28,7 @@ import '../../../../../../utils/customization/theme_extentions/action_theme.dart import '../../../../../../utils/globals.dart'; import '../../../../../../utils/lock_auth.dart'; import '../../../../../../utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; -import '../../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../../widgets/enable_text_edit_after_many_taps.dart'; import '../../../../../../widgets/focused_item_as_overlay.dart'; import '../../default_token_actions/default_edit_action_dialog.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/push_token_widget.dart b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/push_token_widget.dart index 889233aa5..23e28b70c 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/push_token_widget.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/push_token_widget.dart @@ -50,24 +50,22 @@ class PushTokenWidget extends TokenWidget { }); @override - TokenWidgetBase build(BuildContext context) { - return TokenWidgetBase( - key: Key(token.id), - token: token, - tile: PushTokenWidgetTile(token), - dragIcon: Icons.notifications, - editAction: EditPushTokenAction(token: token, key: Key('${token.id}editAction')), - stack: [ - if (!token.isRolledOut) - Positioned.fill( - child: ClipRect( - child: BackdropFilter( - filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), - child: rolloutFailed ? RolloutFailedWidget(token: token) : RolloutWidget(token: token), + TokenWidgetBase build(BuildContext context) => TokenWidgetBase( + key: Key(token.id), + token: token, + tile: PushTokenWidgetTile(token), + dragIcon: Icons.notifications, + editAction: EditPushTokenAction(token: token, key: Key('${token.id}editAction')), + stack: [ + if (!token.isRolledOut) + Positioned.fill( + child: ClipRect( + child: BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: rolloutFailed ? RolloutFailedWidget(token: token) : RolloutWidget(token: token), + ), ), ), - ), - ], - ); - } + ], + ); } diff --git a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart index 2ab5a9bde..bb970b040 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/push_token_widgets/rollout_failed_widget.dart @@ -24,8 +24,8 @@ import '../../../../../l10n/app_localizations.dart'; import '../../../../../model/extensions/enums/push_token_rollout_state_extension.dart'; import '../../../../../model/tokens/push_token.dart'; import '../../../../../utils/globals.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; import '../../../../../widgets/press_button.dart'; diff --git a/lib/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart b/lib/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart index e16729405..1c3544750 100644 --- a/lib/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart +++ b/lib/views/main_view/main_view_widgets/token_widgets/totp_token_widgets/totp_token_widget_tile.dart @@ -24,7 +24,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../../../../l10n/app_localizations.dart'; import '../../../../../model/tokens/totp_token.dart'; import '../../../../../utils/globals.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../utils/utils.dart'; import '../../../../../widgets/custom_texts.dart'; import '../../../../../widgets/custom_trailing.dart'; diff --git a/lib/views/push_token_view/widgets/push_tokens_view_list.dart b/lib/views/push_token_view/widgets/push_tokens_view_list.dart index 27b931378..28283625f 100644 --- a/lib/views/push_token_view/widgets/push_tokens_view_list.dart +++ b/lib/views/push_token_view/widgets/push_tokens_view_list.dart @@ -22,7 +22,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import '../../../model/mixins/sortable_mixin.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../utils/riverpod/riverpod_providers/state_providers/dragging_sortable_provider.dart'; import '../../../widgets/default_refresh_indicator.dart'; import '../../../widgets/drag_item_scroller.dart'; diff --git a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart index 52a1b959c..d14683d80 100644 --- a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart +++ b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/select_tokens_dialog.dart @@ -19,12 +19,12 @@ */ import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../../../../model/riverpod_states/token_state.dart'; import '../../../../../l10n/app_localizations.dart'; +import '../../../../../model/riverpod_states/token_state.dart'; import '../../../../../model/tokens/token.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; import '../../../../main_view/main_view_widgets/token_widgets/token_widget_builder.dart'; diff --git a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/show_qr_code_dialog.dart b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/show_qr_code_dialog.dart index 3de8e2f2a..eeef6e2c4 100644 --- a/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/show_qr_code_dialog.dart +++ b/lib/views/settings_view/settings_groups/import_export_tokens_widgets/dialogs/show_qr_code_dialog.dart @@ -28,7 +28,7 @@ import 'package:zxing2/qrcode.dart'; import '../../../../../l10n/app_localizations.dart'; import '../../../../../model/tokens/token.dart'; import '../../../../../utils/encryption/token_encryption.dart'; -import '../../../../../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../../../../../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; import '../../../../../widgets/dialog_widgets/default_dialog.dart'; class ShowQrCodeDialog extends ConsumerWidget { diff --git a/lib/views/settings_view/settings_groups/settings_group_push_token.dart b/lib/views/settings_view/settings_groups/settings_group_push_token.dart index 9afbd079c..e8915c967 100644 --- a/lib/views/settings_view/settings_groups/settings_group_push_token.dart +++ b/lib/views/settings_view/settings_groups/settings_group_push_token.dart @@ -24,7 +24,7 @@ import '../../../l10n/app_localizations.dart'; import '../../../model/riverpod_states/settings_state.dart'; import '../../../model/tokens/push_token.dart'; import '../../../utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../settings_view_widgets/settings_groups.dart'; import '../settings_view_widgets/update_firebase_token_dialog.dart'; diff --git a/lib/views/settings_view/settings_view.dart b/lib/views/settings_view/settings_view.dart index 74fe18c2f..bff4e741d 100644 --- a/lib/views/settings_view/settings_view.dart +++ b/lib/views/settings_view/settings_view.dart @@ -22,7 +22,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../l10n/app_localizations.dart'; import '../../model/tokens/push_token.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../widgets/push_request_listener.dart'; import '../view_interface.dart'; import 'settings_groups/settings_group_error_log.dart'; diff --git a/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart b/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart index f1a434ccf..679749edd 100644 --- a/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart +++ b/lib/views/settings_view/settings_view_widgets/update_firebase_token_dialog.dart @@ -25,7 +25,7 @@ import '../../../l10n/app_localizations.dart'; import '../../../model/tokens/push_token.dart'; import '../../../utils/globals.dart'; import '../../../utils/logger.dart'; -import '../../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../../utils/view_utils.dart'; import '../../../widgets/dialog_widgets/default_dialog.dart'; diff --git a/lib/views/splash_screen/splash_screen.dart b/lib/views/splash_screen/splash_screen.dart index 9911b5e15..9f4d79c30 100644 --- a/lib/views/splash_screen/splash_screen.dart +++ b/lib/views/splash_screen/splash_screen.dart @@ -26,7 +26,7 @@ import '../../utils/customization/application_customization.dart'; import '../../utils/home_widget_utils.dart'; import '../../utils/logger.dart'; import '../../utils/riverpod/riverpod_providers/generated_providers/introduction_provider.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../main_view/main_view.dart'; import '../view_interface.dart'; diff --git a/lib/widgets/app_wrapper.dart b/lib/widgets/app_wrapper.dart index e16b1b547..1259ca7e9 100644 --- a/lib/widgets/app_wrapper.dart +++ b/lib/widgets/app_wrapper.dart @@ -14,7 +14,7 @@ import '../utils/riverpod/riverpod_providers/generated_providers/deeplink_notifi import '../utils/riverpod/riverpod_providers/generated_providers/push_request_provider.dart'; import '../utils/riverpod/riverpod_providers/generated_providers/token_container_notifier.dart'; import '../utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import '../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../utils/riverpod/state_listeners/home_widget_deep_link_listener.dart'; import '../utils/riverpod/state_listeners/home_widget_token_state_listener.dart'; import '../utils/riverpod/state_listeners/navigation_deep_link_listener.dart'; diff --git a/lib/widgets/dialog_widgets/enter_passphrase_dialog.dart b/lib/widgets/dialog_widgets/enter_passphrase_dialog.dart new file mode 100644 index 000000000..f6534c7b1 --- /dev/null +++ b/lib/widgets/dialog_widgets/enter_passphrase_dialog.dart @@ -0,0 +1,60 @@ +/* + * privacyIDEA Authenticator + * + * Author: Frank Merkel + * + * Copyright (c) 2024 NetKnights GmbH + * + * Licensed under the Apache License, Version 2.0 (the 'License'); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an 'AS IS' BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import 'dart:ui'; + +import 'package:flutter/material.dart'; + +class EnterPassphraseDialog extends StatefulWidget { + static Future show(BuildContext context) => showDialog( + context: context, + builder: (context) => BackdropFilter( + filter: ImageFilter.blur(sigmaX: 5, sigmaY: 5), + child: const EnterPassphraseDialog(), + ), + ); + + const EnterPassphraseDialog({super.key}); + + @override + State createState() => _EnterPassphraseDialogState(); +} + +class _EnterPassphraseDialogState extends State { + String text = ''; + + @override + Widget build(BuildContext context) { + return AlertDialog( + title: const Text('Enter your passphrase'), + content: TextField( + decoration: const InputDecoration(hintText: 'Passphrase'), + onChanged: (value) => setState(() { + text = value; + }), + ), + actions: [ + TextButton( + onPressed: text.isNotEmpty ? () => Navigator.of(context).pop(text) : null, + child: const Text('OK'), + ), + ], + ); + } +} diff --git a/lib/widgets/dialog_widgets/push_request_dialog.dart b/lib/widgets/dialog_widgets/push_request_dialog.dart index 90a259e75..c4cb84092 100644 --- a/lib/widgets/dialog_widgets/push_request_dialog.dart +++ b/lib/widgets/dialog_widgets/push_request_dialog.dart @@ -12,7 +12,7 @@ import '../../utils/globals.dart'; import '../../utils/lock_auth.dart'; import '../../utils/logger.dart'; import '../../utils/riverpod/riverpod_providers/generated_providers/push_request_provider.dart'; -import '../../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../press_button.dart'; import 'default_dialog.dart'; diff --git a/lib/widgets/focused_item_as_overlay.dart b/lib/widgets/focused_item_as_overlay.dart index 2a6308a52..4b72ddc10 100644 --- a/lib/widgets/focused_item_as_overlay.dart +++ b/lib/widgets/focused_item_as_overlay.dart @@ -7,7 +7,7 @@ import 'package:flutter/material.dart'; import '../l10n/app_localizations.dart'; import '../utils/globals.dart'; import '../utils/logger.dart'; -import '../utils/riverpod/riverpod_providers/state_providers/app_constraints_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/app_constraints_notifier.dart'; import '../utils/utils.dart'; import 'pulse_icon.dart'; import 'tooltip_container.dart'; diff --git a/lib/widgets/hideable_widget_.dart b/lib/widgets/hideable_widget_.dart index 5bc05b080..bc546e8ea 100644 --- a/lib/widgets/hideable_widget_.dart +++ b/lib/widgets/hideable_widget_.dart @@ -3,7 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../l10n/app_localizations.dart'; import '../model/tokens/otp_token.dart'; -import '../utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import '../utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; class HideableWidget extends ConsumerWidget { final OTPToken token; diff --git a/pubspec.lock b/pubspec.lock index f6bf9af1f..c43101af6 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -118,6 +118,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.3" + basic_utils: + dependency: "direct main" + description: + name: basic_utils + sha256: "2064b21d3c41ed7654bc82cc476fd65542e04d60059b74d5eed490a4da08fc6c" + url: "https://pub.dev" + source: hosted + version: "5.7.0" boolean_selector: dependency: transitive description: @@ -1817,10 +1825,10 @@ packages: dependency: transitive description: name: vm_service - sha256: f652077d0bdf60abe4c1f6377448e8655008eef28f128bc023f7b5e8dfeb48fc + sha256: "5c5f338a667b4c644744b661f309fb8080bb94b18a7e91ef1dbd343bed00ed6d" url: "https://pub.dev" source: hosted - version: "14.2.4" + version: "14.2.5" watcher: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index be5e132c8..528428d20 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -95,6 +95,7 @@ dependencies: riverpod_annotation: ^2.3.5 freezed_annotation: ^2.4.4 async: ^2.11.0 + basic_utils: ^5.7.0 diff --git a/test/unit_test/state_notifiers/sortable_notifier_test.dart b/test/unit_test/state_notifiers/sortable_notifier_test.dart index 47e6ce7f1..f79010932 100644 --- a/test/unit_test/state_notifiers/sortable_notifier_test.dart +++ b/test/unit_test/state_notifiers/sortable_notifier_test.dart @@ -11,7 +11,7 @@ import 'package:privacyidea_authenticator/model/tokens/totp_token.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/sortable_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_folder_notifier.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import '../../tests_app_wrapper.mocks.dart'; diff --git a/test/unit_test/state_notifiers/token_notifier_test.dart b/test/unit_test/state_notifiers/token_notifier_test.dart index d24f30ead..dc79e9447 100644 --- a/test/unit_test/state_notifiers/token_notifier_test.dart +++ b/test/unit_test/state_notifiers/token_notifier_test.dart @@ -12,10 +12,11 @@ import 'package:privacyidea_authenticator/model/tokens/hotp_token.dart'; import 'package:privacyidea_authenticator/model/tokens/push_token.dart'; import 'package:privacyidea_authenticator/model/tokens/token.dart'; import 'package:privacyidea_authenticator/utils/privacyidea_io_client.dart'; -import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/state_notifier_providers/token_notifier.dart'; +import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/token_notifier.dart'; import 'package:privacyidea_authenticator/utils/logger.dart'; import 'package:privacyidea_authenticator/utils/riverpod/riverpod_providers/generated_providers/settings_notifier.dart'; import 'package:privacyidea_authenticator/utils/rsa_utils.dart'; +import 'package:privacyidea_authenticator/utils/utils.dart'; import '../../tests_app_wrapper.mocks.dart'; @@ -260,8 +261,9 @@ void _testTokenNotifier() { ioClient: const PrivacyideaIOClient(), firebaseUtils: mockFirebaseUtils, ); - final notifier = container.read(testProvider.notifier); - await notifier.handleQrCode('otpauth://totp/issuer2:label2?secret=secret2&issuer=issuer2&algorithm=SHA256&digits=6&period=30'); + final testNotifier = container.read(tokenProvider.notifier); + const qrCode = 'otpauth://totp/issuer2:label2?secret=secret2&issuer=issuer2&algorithm=SHA256&digits=6&period=30'; + await scanQrCode([testNotifier], qrCode); final state = container.read(testProvider); expect(state, isNotNull); after.last = after.last.copyWith(id: state.tokens.last.id); @@ -348,7 +350,7 @@ void _testTokenNotifier() { final notifier = container.read(testProvider.notifier); final initState = await notifier.initState; expect(initState.tokens, before); - await notifier.handleQrCode(otpAuth); + await scanQrCode([notifier], otpAuth); final tokenState = container.read(testProvider); expect(tokenState, isNotNull); expect(tokenState.tokens, after);