From 98f1b22b9e820cf2d2c76bc0c0dfd895d85c39f5 Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 22 Jul 2024 18:10:57 +0100 Subject: [PATCH 1/3] put a secured gate around the app --- app/lib/common/utils/utils.dart | 1 + app/lib/main.dart | 90 +++++++++++++++++++++++++++++++-- app/pubspec.lock | 8 +++ app/pubspec.yaml | 1 + 4 files changed, 95 insertions(+), 5 deletions(-) diff --git a/app/lib/common/utils/utils.dart b/app/lib/common/utils/utils.dart index 1c1c01dc5d6c..ab153690d00b 100644 --- a/app/lib/common/utils/utils.dart +++ b/app/lib/common/utils/utils.dart @@ -372,6 +372,7 @@ enum LabsFeature { // specific features chatUnread, + obfuscatedApp, // not a lab anymore but needs to stay for backwards compat tasks, diff --git a/app/lib/main.dart b/app/lib/main.dart index 355fb0dde132..cfcfdf74d611 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -9,14 +9,18 @@ import 'package:acter/common/tutorial_dialogs/space_overview_tutorials/space_ove import 'package:acter/common/utils/language.dart'; import 'package:acter/common/utils/logging.dart'; import 'package:acter/common/utils/main.dart'; +import 'package:acter/common/utils/utils.dart'; import 'package:acter/features/cli/main.dart'; import 'package:acter/features/settings/providers/settings_providers.dart'; import 'package:acter/router/providers/router_providers.dart'; +import 'package:acter/router/router.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart'; +import 'package:secure_application/secure_application.dart'; import 'package:video_player_media_kit/video_player_media_kit.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -83,11 +87,19 @@ class Acter extends ConsumerStatefulWidget { } class _ActerState extends ConsumerState with WidgetsBindingObserver { + final secureApplicationController = SecureApplicationController( + SecureApplicationState( + locked: true, + secured: true, + ), + ); @override void initState() { super.initState(); initLanguage(ref); WidgetsBinding.instance.addObserver(this); + + // WidgetsBinding.instance?.addPostFrameCallback((_) => localAuthenticate()); } @override @@ -101,21 +113,89 @@ class _ActerState extends ConsumerState with WidgetsBindingObserver { super.dispose(); } + Widget appBuilder(BuildContext context, Widget? child) { + final obfuscateApp = + ref.watch(featuresProvider).isActive(LabsFeature.obfuscatedApp); + + // EasyLoading Wrapper + final easyLoadingBuilder = EasyLoading.init(); + // all toast msgs will appear at bottom + EasyLoading.instance.toastPosition = EasyLoadingToastPosition.bottom; + final inner = easyLoadingBuilder(context, child); + + if (obfuscateApp || true) { + print("putting into secure app"); + return SecureApplication( + nativeRemoveDelay: 800, + secureApplicationController: secureApplicationController, + onNeedUnlock: (secureApplicationController) async { + var authResult = await askValidation(context); + if (authResult ?? false) { + secureApplicationController!.authSuccess(unlock: true); + } else { + secureApplicationController!.authFailed(unlock: true); + secureApplicationController!.open(); + } + return null; + }, + child: SecureGate( + blurr: 5, + lockedBuilder: (context, secureNotifier) => Center( + child: OutlinedButton( + child: const Text('test'), + onPressed: () => secureNotifier!.unlock(), + ), + ), + child: inner, + ), + ); + } + + return inner; + } + + Future askValidation(BuildContext context) async { + final context = rootNavKey.currentState!.overlay!.context; + print("asking to validate!"); + return await showDialog( + context: context, + barrierDismissible: false, // user must tap button! + builder: (BuildContext context) { + return CupertinoAlertDialog( + title: Text('Unlock app content'), + content: Text( + 'Do you wan to unlock the application content? Clicking no will secure the app'), + actions: [ + CupertinoDialogAction( + isDefaultAction: true, + child: Text('No'), + onPressed: () { + Navigator.of(context).pop(false); + }, + ), + CupertinoDialogAction( + child: Text('Yes'), + onPressed: () { + Navigator.of(context).pop(true); + }, + ), + ], + ); + }, + ); + } + @override Widget build(BuildContext context) { final language = ref.watch(languageProvider); final router = ref.watch(routerProvider); - // all toast msgs will appear at bottom - final builder = EasyLoading.init(); - EasyLoading.instance.toastPosition = EasyLoadingToastPosition.bottom; - return Portal( child: MaterialApp.router( routerConfig: router, theme: ActerTheme.theme, title: 'Acter', - builder: builder, + builder: appBuilder, locale: Locale(language), localizationsDelegates: L10n.localizationsDelegates, supportedLocales: L10n.supportedLocales, diff --git a/app/pubspec.lock b/app/pubspec.lock index a4df6c60f457..08869b5d0a88 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -1896,6 +1896,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.1" + secure_application: + dependency: "direct main" + description: + name: secure_application + sha256: b8e34b4bc2467a3a3c0a649e46ae6a442df7ca27aeaddebb8a53c40656da0385 + url: "https://pub.dev" + source: hosted + version: "4.0.1" sensors_plus: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index f9f819c60a17..f9d5be6743ca 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -128,6 +128,7 @@ dependencies: firebase_core: ^3.1.0 scrolls_to_top: ^2.1.1 scrollable_positioned_list: ^0.3.8 + secure_application: ^4.0.1 dev_dependencies: flutter_test: From 3749a87ef7c35583c703f800ec361aa09a06ee5c Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 22 Jul 2024 18:48:37 +0100 Subject: [PATCH 2/3] Hide app behind simple_calculator --- app/lib/main.dart | 26 ++++++++++---------------- app/pubspec.lock | 32 ++++++++++++++++++++++++++++++++ app/pubspec.yaml | 1 + 3 files changed, 43 insertions(+), 16 deletions(-) diff --git a/app/lib/main.dart b/app/lib/main.dart index cfcfdf74d611..5da3bd3ec59b 100644 --- a/app/lib/main.dart +++ b/app/lib/main.dart @@ -21,6 +21,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:multi_trigger_autocomplete/multi_trigger_autocomplete.dart'; import 'package:secure_application/secure_application.dart'; +import 'package:flutter_simple_calculator/flutter_simple_calculator.dart'; import 'package:video_player_media_kit/video_player_media_kit.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; @@ -128,23 +129,16 @@ class _ActerState extends ConsumerState with WidgetsBindingObserver { return SecureApplication( nativeRemoveDelay: 800, secureApplicationController: secureApplicationController, - onNeedUnlock: (secureApplicationController) async { - var authResult = await askValidation(context); - if (authResult ?? false) { - secureApplicationController!.authSuccess(unlock: true); - } else { - secureApplicationController!.authFailed(unlock: true); - secureApplicationController!.open(); - } - return null; - }, child: SecureGate( - blurr: 5, - lockedBuilder: (context, secureNotifier) => Center( - child: OutlinedButton( - child: const Text('test'), - onPressed: () => secureNotifier!.unlock(), - ), + opacity: 1, + lockedBuilder: (context, secureNotifier) => SimpleCalculator( + onChanged: (key, value, expression) { + print("key $key, value $value, expression: $expression"); + if (value.toString() == '1984.0') { + print('unlocking'); + secureNotifier!.unlock(); + } + }, ), child: inner, ), diff --git a/app/pubspec.lock b/app/pubspec.lock index 08869b5d0a88..eaea9d431c22 100644 --- a/app/pubspec.lock +++ b/app/pubspec.lock @@ -96,6 +96,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.0.12" + auto_size_text: + dependency: transitive + description: + name: auto_size_text + sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599" + url: "https://pub.dev" + source: hosted + version: "3.0.0" basic_utils: dependency: transitive description: @@ -675,6 +683,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.5" + flutter_grid_button: + dependency: transitive + description: + name: flutter_grid_button + sha256: "51e8a3838439ccdc33363a8fec2cb7575d63a3a2cf37f189d110a05ae2740752" + url: "https://pub.dev" + source: hosted + version: "2.1.0" flutter_highlight: dependency: transitive description: @@ -882,6 +898,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + flutter_simple_calculator: + dependency: "direct main" + description: + name: flutter_simple_calculator + sha256: f88568cc8db0c8c865095b5ae4cbaa9faa67a230b4a353f07367a275902a7022 + url: "https://pub.dev" + source: hosted + version: "2.3.0" flutter_slidable: dependency: "direct main" description: @@ -1318,6 +1342,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.8.0" + math_expressions: + dependency: transitive + description: + name: math_expressions + sha256: db0b72d867491c4e53a1c773e2708d5d6e94bbe06be07080fc9f896766b9cd3d + url: "https://pub.dev" + source: hosted + version: "2.5.0" matrix_link_text: dependency: transitive description: diff --git a/app/pubspec.yaml b/app/pubspec.yaml index f9d5be6743ca..6aad124e1e54 100644 --- a/app/pubspec.yaml +++ b/app/pubspec.yaml @@ -129,6 +129,7 @@ dependencies: scrolls_to_top: ^2.1.1 scrollable_positioned_list: ^0.3.8 secure_application: ^4.0.1 + flutter_simple_calculator: ^2.3.0 dev_dependencies: flutter_test: From 3a5c19297fb10779a3037c45a193f4f94c2751fa Mon Sep 17 00:00:00 2001 From: Benjamin Kampmann Date: Mon, 28 Oct 2024 18:46:23 +0000 Subject: [PATCH 3/3] Expose App Obfuscation Labs Feature --- app/lib/features/settings/pages/labs_page.dart | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/app/lib/features/settings/pages/labs_page.dart b/app/lib/features/settings/pages/labs_page.dart index 6a11204e1a43..dcb186cc9b9c 100644 --- a/app/lib/features/settings/pages/labs_page.dart +++ b/app/lib/features/settings/pages/labs_page.dart @@ -33,6 +33,11 @@ class SettingsLabsPage extends ConsumerWidget { title: Text(lang.labsAppFeatures), tiles: [ const LabsNotificationsSettingsTile(), + ], + ), + SettingsSection( + title: Text(lang.securityAndPrivacy), + tiles: [ SettingsTile.switchTile( title: Text(lang.encryptionBackupKeyBackup), description: Text(lang.sharedCalendarAndEvents), @@ -44,6 +49,18 @@ class SettingsLabsPage extends ConsumerWidget { newVal, ), ), + SettingsTile.switchTile( + title: const Text('Hide App behind Calculator'), + description: const Text( + 'Show a calculator when starting or switching to the app. Press 1984 enter to pass'), + initialValue: + ref.watch(isActiveProvider(LabsFeature.obfuscatedApp)), + onToggle: (newVal) => updateFeatureState( + ref, + LabsFeature.obfuscatedApp, + newVal, + ), + ), ], ), SettingsSection(