From 9cce216e9f0fc359fbca7462a42b57e7fd7e14df Mon Sep 17 00:00:00 2001 From: Dain Nilsson Date: Fri, 20 May 2022 17:19:39 +0200 Subject: [PATCH] Refactor AppFailurePage. --- lib/app/views/app_failure_page.dart | 83 +++++++++++++++++++++ lib/app/views/app_failure_screen.dart | 50 ------------- lib/fido/views/fido_screen.dart | 46 +----------- lib/management/views/management_screen.dart | 14 +++- lib/oath/views/oath_screen.dart | 7 +- 5 files changed, 102 insertions(+), 98 deletions(-) create mode 100755 lib/app/views/app_failure_page.dart delete mode 100755 lib/app/views/app_failure_screen.dart diff --git a/lib/app/views/app_failure_page.dart b/lib/app/views/app_failure_page.dart new file mode 100755 index 00000000..aa4120eb --- /dev/null +++ b/lib/app/views/app_failure_page.dart @@ -0,0 +1,83 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter_riverpod/flutter_riverpod.dart'; + +import '../../desktop/models.dart'; +import '../../desktop/state.dart'; +import '../../theme.dart'; +import '../message.dart'; +import 'graphics.dart'; +import 'message_page.dart'; + +class AppFailurePage extends ConsumerWidget { + final Widget? title; + final Object cause; + const AppFailurePage({this.title, required this.cause, super.key}) : super(); + + @override + Widget build(BuildContext context, WidgetRef ref) { + final reason = cause; + + Widget? graphic = const Icon(Icons.error); + String? header = 'An error has occured'; + String? message = reason.toString(); + List actions = []; + + if (reason is RpcError) { + if (reason.status == 'connection-error') { + switch (reason.body['connection']) { + case 'ccid': + header = 'Failed to open smart card connection'; + if (Platform.isMacOS) { + message = 'Try to remove and re-insert your YubiKey.'; + } else if (Platform.isLinux) { + message = 'Make sure pcscd is running.'; + } else { + message = 'Make sure your smart card service is functioning.'; + } + break; + case 'fido': + if (Platform.isWindows && + !ref.watch(rpcStateProvider.select((state) => state.isAdmin))) { + graphic = noPermission; + header = null; + message = 'WebAuthn management requires elevated privileges.'; + actions = [ + OutlinedButton.icon( + label: const Text('Unlock'), + icon: const Icon(Icons.lock_open), + style: AppTheme.primaryOutlinedButtonStyle(context), + onPressed: () async { + final controller = showMessage( + context, 'Elevating permissions...', + duration: const Duration(seconds: 30)); + try { + if (await ref.read(rpcProvider).elevate()) { + ref.refresh(rpcProvider); + } else { + showMessage(context, 'Permission denied'); + } + } finally { + controller.close(); + } + }), + ]; + } + break; + default: + header = 'Failed to open connection'; + message = 'Try to remove and re-insert your YubiKey.'; + } + } + } + + return MessagePage( + title: title, + graphic: graphic, + header: header, + message: message, + actions: actions, + ); + } +} diff --git a/lib/app/views/app_failure_screen.dart b/lib/app/views/app_failure_screen.dart deleted file mode 100755 index a9bb756b..00000000 --- a/lib/app/views/app_failure_screen.dart +++ /dev/null @@ -1,50 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:yubico_authenticator/desktop/models.dart'; - -class AppFailureScreen extends StatelessWidget { - final Object reason; - const AppFailureScreen(this.reason, {super.key}) : super(); - - @override - Widget build(BuildContext context) { - final cause = reason; - if (cause is RpcError) { - if (cause.status == 'connection-error' && - cause.body['connection'] == 'ccid') { - var msg = 'Failed to open smart card connection'; - if (Platform.isMacOS) { - msg += '\nTry to remove and re-insert your YubiKey to regain access.'; - } else if (Platform.isLinux) { - msg += '\nMake sure pcscd is running.'; - } - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - msg, - textAlign: TextAlign.center, - ), - ], - ), - ); - } - } - - return Center( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - Text( - cause.toString(), - textAlign: TextAlign.center, - ), - ], - ), - ); - } -} diff --git a/lib/fido/views/fido_screen.dart b/lib/fido/views/fido_screen.dart index 8352144f..f9702398 100755 --- a/lib/fido/views/fido_screen.dart +++ b/lib/fido/views/fido_screen.dart @@ -1,19 +1,12 @@ -import 'dart:io'; - import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; -import '../../app/message.dart'; import '../../app/models.dart'; -import '../../app/views/app_failure_screen.dart'; +import '../../app/views/app_failure_page.dart'; import '../../app/views/app_loading_screen.dart'; import '../../app/views/app_page.dart'; -import '../../app/views/graphics.dart'; import '../../app/views/message_page.dart'; -import '../../desktop/models.dart'; -import '../../desktop/state.dart'; import '../../management/models.dart'; -import '../../theme.dart'; import '../state.dart'; import 'locked_page.dart'; import 'unlocked_page.dart'; @@ -53,41 +46,10 @@ class FidoScreen extends ConsumerWidget { 'WebAuthn requires the FIDO2 application to be enabled on your YubiKey', ); } - if (Platform.isWindows && error is RpcError) { - if (error.status == 'connection-error' && - !ref.watch( - rpcStateProvider.select((state) => state.isAdmin))) { - return MessagePage( - title: const Text('WebAuthn'), - graphic: noPermission, - message: 'WebAuthn management requires elevated privileges.', - actions: [ - OutlinedButton.icon( - label: const Text('Unlock'), - icon: const Icon(Icons.lock_open), - style: AppTheme.primaryOutlinedButtonStyle(context), - onPressed: () async { - final controller = showMessage( - context, 'Elevating permissions...', - duration: const Duration(seconds: 30)); - try { - if (await ref.read(rpcProvider).elevate()) { - ref.refresh(rpcProvider); - } else { - showMessage(context, 'Permission denied'); - } - } finally { - controller.close(); - } - }), - ], - ); - } - } - return AppPage( + + return AppFailurePage( title: const Text('WebAuthn'), - centered: true, - child: AppFailureScreen(error), + cause: error, ); }, data: (fidoState) { diff --git a/lib/management/views/management_screen.dart b/lib/management/views/management_screen.dart index 81ca1f10..544b4b28 100755 --- a/lib/management/views/management_screen.dart +++ b/lib/management/views/management_screen.dart @@ -5,7 +5,6 @@ import 'package:collection/collection.dart'; import '../../app/message.dart'; import '../../app/models.dart'; import '../../app/state.dart'; -import '../../app/views/app_failure_screen.dart'; import '../../app/views/app_loading_screen.dart'; import '../../core/models.dart'; import '../../widgets/responsive_dialog.dart'; @@ -241,7 +240,18 @@ class _ManagementScreenState extends ConsumerState { final child = ref.watch(managementStateProvider(widget.deviceData.node.path)).when( loading: () => const AppLoadingScreen(), - error: (error, _) => AppFailureScreen(error), + error: (error, _) => Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text( + error.toString(), + textAlign: TextAlign.center, + ), + ], + ), + ), data: (info) { bool hasConfig = info.version.major > 4; if (hasConfig) { diff --git a/lib/oath/views/oath_screen.dart b/lib/oath/views/oath_screen.dart index ab3005de..afb1c62f 100755 --- a/lib/oath/views/oath_screen.dart +++ b/lib/oath/views/oath_screen.dart @@ -6,7 +6,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../../app/message.dart'; import '../../app/models.dart'; -import '../../app/views/app_failure_screen.dart'; +import '../../app/views/app_failure_page.dart'; import '../../app/views/app_loading_screen.dart'; import '../../app/views/app_page.dart'; import '../../app/views/graphics.dart'; @@ -31,10 +31,9 @@ class OathScreen extends ConsumerWidget { centered: true, child: const AppLoadingScreen(), ), - error: (error, _) => AppPage( + error: (error, _) => AppFailurePage( title: const Text('Authenticator'), - centered: true, - child: AppFailureScreen(error), + cause: error, ), data: (oathState) => oathState.locked ? _LockedView(devicePath, oathState)