From 4930fc23879e9c62824a09113a9e4b5226b898ba Mon Sep 17 00:00:00 2001 From: Inex Code Date: Thu, 2 May 2024 15:05:38 +0300 Subject: [PATCH] feat: Show the error screen when libsecret fails --- lib/config/hive_config.dart | 54 ++++++++------ lib/main.dart | 10 ++- lib/ui/layouts/brand_hero_screen.dart | 4 +- .../errors/failed_to_init_secure_storage.dart | 71 +++++++++++++++++++ 4 files changed, 117 insertions(+), 22 deletions(-) create mode 100644 lib/ui/pages/errors/failed_to_init_secure_storage.dart diff --git a/lib/config/hive_config.dart b/lib/config/hive_config.dart index 55b35e9e..ea6cca9c 100644 --- a/lib/config/hive_config.dart +++ b/lib/config/hive_config.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'dart:typed_data'; +import 'package:flutter/services.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:selfprivacy/logic/models/hive/backblaze_bucket.dart'; @@ -28,33 +28,47 @@ class HiveConfig { await Hive.openBox(BNames.appSettingsBox); - final HiveAesCipher cipher = HiveAesCipher( - await getEncryptedKey(BNames.serverInstallationEncryptionKey), - ); + try { + final HiveAesCipher cipher = HiveAesCipher( + await getEncryptedKey(BNames.serverInstallationEncryptionKey), + ); - await Hive.openBox(BNames.usersDeprecated); - await Hive.openBox(BNames.usersBox, encryptionCipher: cipher); + await Hive.openBox(BNames.usersDeprecated); + await Hive.openBox(BNames.usersBox, encryptionCipher: cipher); - final Box deprecatedUsers = Hive.box(BNames.usersDeprecated); - if (deprecatedUsers.isNotEmpty) { - final Box users = Hive.box(BNames.usersBox); - await users.addAll(deprecatedUsers.values.toList()); - await deprecatedUsers.clear(); + final Box deprecatedUsers = Hive.box(BNames.usersDeprecated); + if (deprecatedUsers.isNotEmpty) { + final Box users = Hive.box(BNames.usersBox); + await users.addAll(deprecatedUsers.values.toList()); + await deprecatedUsers.clear(); + } + + await Hive.openBox( + BNames.serverInstallationBox, + encryptionCipher: cipher, + ); + } on PlatformException catch (e) { + print('HiveConfig: Error while opening boxes: $e'); + rethrow; } - - await Hive.openBox(BNames.serverInstallationBox, encryptionCipher: cipher); } static Future getEncryptedKey(final String encKey) async { const FlutterSecureStorage secureStorage = FlutterSecureStorage(); - final bool hasEncryptionKey = await secureStorage.containsKey(key: encKey); - if (!hasEncryptionKey) { - final List key = Hive.generateSecureKey(); - await secureStorage.write(key: encKey, value: base64UrlEncode(key)); - } + try { + final bool hasEncryptionKey = + await secureStorage.containsKey(key: encKey); + if (!hasEncryptionKey) { + final List key = Hive.generateSecureKey(); + await secureStorage.write(key: encKey, value: base64UrlEncode(key)); + } - final String? string = await secureStorage.read(key: encKey); - return base64Url.decode(string!); + final String? string = await secureStorage.read(key: encKey); + return base64Url.decode(string!); + } on PlatformException catch (e) { + print('HiveConfig: Error while getting encryption key: $e'); + rethrow; + } } } diff --git a/lib/main.dart b/lib/main.dart index 13b05aad..af680a1a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:selfprivacy/config/bloc_config.dart'; import 'package:selfprivacy/config/bloc_observer.dart'; @@ -9,13 +10,20 @@ import 'package:selfprivacy/config/hive_config.dart'; import 'package:selfprivacy/config/localization.dart'; import 'package:selfprivacy/logic/cubit/app_settings/app_settings_cubit.dart'; import 'package:selfprivacy/theming/factory/app_theme_factory.dart'; +import 'package:selfprivacy/ui/pages/errors/failed_to_init_secure_storage.dart'; import 'package:selfprivacy/ui/router/router.dart'; // import 'package:wakelock/wakelock.dart'; import 'package:timezone/data/latest.dart' as tz; void main() async { WidgetsFlutterBinding.ensureInitialized(); - await HiveConfig.init(); + try { + await HiveConfig.init(); + } on PlatformException catch (e) { + runApp( + FailedToInitSecureStorageScreen(e: e), + ); + } // await SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp]); // try { diff --git a/lib/ui/layouts/brand_hero_screen.dart b/lib/ui/layouts/brand_hero_screen.dart index 6286bd3c..a82ed720 100644 --- a/lib/ui/layouts/brand_hero_screen.dart +++ b/lib/ui/layouts/brand_hero_screen.dart @@ -127,7 +127,9 @@ class _HeroSliverAppBarState extends State { Widget build(final BuildContext context) { final isMobile = widget.ignoreBreakpoints ? true : Breakpoints.small.isActive(context); - final isJobsListEmpty = context.watch().state is JobsStateEmpty; + final isJobsListEmpty = widget.hasFlashButton + ? context.watch().state is JobsStateEmpty + : true; return SliverAppBar( expandedHeight: widget.hasHeroIcon ? 148.0 + _size.height : 72.0 + _size.height, diff --git a/lib/ui/pages/errors/failed_to_init_secure_storage.dart b/lib/ui/pages/errors/failed_to_init_secure_storage.dart new file mode 100644 index 00000000..10d6e935 --- /dev/null +++ b/lib/ui/pages/errors/failed_to_init_secure_storage.dart @@ -0,0 +1,71 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:gap/gap.dart'; +import 'package:selfprivacy/ui/layouts/brand_hero_screen.dart'; +import 'package:selfprivacy/ui/pages/more/about_application.dart'; + +class FailedToInitSecureStorageScreen extends StatelessWidget { + const FailedToInitSecureStorageScreen({ + required this.e, + super.key, + }); + + final PlatformException e; + + @override + Widget build(final BuildContext context) => MaterialApp( + home: BrandHeroScreen( + heroIcon: Icons.error_outline, + heroTitle: 'Failed to initialize secure storage', + hasBackButton: false, + children: [ + const Text( + 'SelfPrivacy requires a secure storage provided by your operating system to encrypt sensitive data, but it failed to initialize.', + ), + if (Platform.isLinux) + const Text( + 'Please make sure that the libsecret library is installed.', + ), + const Gap(16), + Text('Error: ${e.message}'), + const Gap(16), + const Divider(), + const Gap(16), + const LinkListTile( + title: 'Our website', + subtitle: 'selfprivacy.org', + uri: 'https://selfprivacy.org/', + icon: Icons.language_outlined, + ), + const LinkListTile( + title: 'Documentation', + subtitle: 'selfprivacy.org/docs', + uri: 'https://selfprivacy.org/docs/', + icon: Icons.library_books_outlined, + ), + const LinkListTile( + title: 'Privacy Policy', + subtitle: 'selfprivacy.org/privacy-policy', + uri: 'https://selfprivacy.org/privacy-policy/', + icon: Icons.policy_outlined, + ), + const LinkListTile( + title: 'Matrix support chat', + subtitle: '#chat:selfprivacy.org', + uri: 'https://matrix.to/#/#chat:selfprivacy.org', + icon: Icons.question_answer_outlined, + longPressText: '#chat:selfprivacy.org', + ), + const LinkListTile( + title: 'Telegram support chat', + subtitle: '@selfprivacy_chat', + uri: 'https://t.me/selfprivacy_chat', + icon: Icons.question_answer_outlined, + longPressText: '@selfprivacy_chat', + ), + ], + ), + ); +}