mirror of
https://github.com/Yubico/yubioath-flutter.git
synced 2024-12-23 02:01:36 +03:00
Move "allow screenshots" to Troubleshooting, show warning.
This commit is contained in:
parent
32076aee51
commit
7e3a6205ce
@ -12,6 +12,7 @@ import 'app/logging.dart';
|
||||
import 'app/message.dart';
|
||||
import 'app/state.dart';
|
||||
import 'core/state.dart';
|
||||
import 'android/state.dart';
|
||||
import 'desktop/state.dart';
|
||||
import 'version.dart';
|
||||
import 'widgets/responsive_dialog.dart';
|
||||
@ -25,151 +26,173 @@ class AboutPage extends ConsumerWidget {
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return ResponsiveDialog(
|
||||
title: const Text('About'),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset('assets/graphics/app-icon.png', scale: 1 / 0.75),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
child: Text(
|
||||
Platform.isAndroid
|
||||
? 'Yubico Authenticator Preview'
|
||||
: 'Yubico Authenticator',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
const Text(version),
|
||||
const Text(''),
|
||||
const Text('Copyright © 2022 Yubico'),
|
||||
const Text('All rights reserved'),
|
||||
const Text(''),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_terms_of_use,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse(
|
||||
'https://www.yubico.com/support/terms-conditions/yubico-license-agreement/'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
title: Text(AppLocalizations.of(context)!.general_about),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 32),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.asset('assets/graphics/app-icon.png', scale: 1 / 0.75),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 24.0),
|
||||
child: Text(
|
||||
'Yubico Authenticator',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_privacy_policy,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse(
|
||||
'https://www.yubico.com/support/terms-conditions/privacy-notice/'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_open_src_licenses,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const LicensePage(
|
||||
applicationVersion: version,
|
||||
),
|
||||
settings: const RouteSettings(name: 'licenses'),
|
||||
));
|
||||
},
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 24.0, bottom: 8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_help_and_feedback,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_send_feedback,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse('https://forms.gle/nYPVWcFnqoprZX1S9'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_i_need_help,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse('https://support.yubico.com/support/home'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 24.0, bottom: 8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_troubleshooting,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
const LoggingPanel(),
|
||||
if (isDesktop) ...[
|
||||
const SizedBox(height: 12.0),
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.bug_report_outlined),
|
||||
label:
|
||||
Text(AppLocalizations.of(context)!.general_run_diagnostics),
|
||||
onPressed: () async {
|
||||
_log.info('Running diagnostics...');
|
||||
final response =
|
||||
await ref.read(rpcProvider).command('diagnose', []);
|
||||
final data = response['diagnostics'] as List;
|
||||
data.insert(0, {
|
||||
'app_version': version,
|
||||
'dart': Platform.version,
|
||||
});
|
||||
final text = const JsonEncoder.withIndent(' ').convert(data);
|
||||
await Clipboard.setData(ClipboardData(text: text));
|
||||
await ref.read(withContextProvider)(
|
||||
(context) async {
|
||||
showMessage(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.general_diagnostics_copied);
|
||||
const Text(version),
|
||||
const Text(''),
|
||||
const Text('Copyright © 2022 Yubico'),
|
||||
const Text('All rights reserved'),
|
||||
const Text(''),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_terms_of_use,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse(
|
||||
'https://www.yubico.com/support/terms-conditions/yubico-license-agreement/'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
);
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_privacy_policy,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse(
|
||||
'https://www.yubico.com/support/terms-conditions/privacy-notice/'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_open_src_licenses,
|
||||
style: const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).push(MaterialPageRoute<void>(
|
||||
builder: (BuildContext context) => const LicensePage(
|
||||
applicationVersion: version,
|
||||
),
|
||||
settings: const RouteSettings(name: 'licenses'),
|
||||
));
|
||||
},
|
||||
),
|
||||
]
|
||||
],
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 24.0, bottom: 8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_help_and_feedback,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_send_feedback,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse('https://forms.gle/nYPVWcFnqoprZX1S9'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
TextButton(
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_i_need_help,
|
||||
style:
|
||||
const TextStyle(decoration: TextDecoration.underline),
|
||||
),
|
||||
onPressed: () {
|
||||
launchUrl(
|
||||
Uri.parse('https://support.yubico.com/support/home'),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(top: 24.0, bottom: 8.0),
|
||||
child: Divider(),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 16.0),
|
||||
child: Text(
|
||||
AppLocalizations.of(context)!.general_troubleshooting,
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
),
|
||||
const LoggingPanel(),
|
||||
|
||||
// Diagnostics (desktop only)
|
||||
if (isDesktop) ...[
|
||||
const SizedBox(height: 12.0),
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.bug_report_outlined),
|
||||
label:
|
||||
Text(AppLocalizations.of(context)!.general_run_diagnostics),
|
||||
onPressed: () async {
|
||||
_log.info('Running diagnostics...');
|
||||
final response =
|
||||
await ref.read(rpcProvider).command('diagnose', []);
|
||||
final data = response['diagnostics'] as List;
|
||||
data.insert(0, {
|
||||
'app_version': version,
|
||||
'dart': Platform.version,
|
||||
});
|
||||
final text = const JsonEncoder.withIndent(' ').convert(data);
|
||||
await Clipboard.setData(ClipboardData(text: text));
|
||||
await ref.read(withContextProvider)(
|
||||
(context) async {
|
||||
showMessage(
|
||||
context,
|
||||
AppLocalizations.of(context)!
|
||||
.general_diagnostics_copied);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
// Enable screenshots (Android only)
|
||||
if (isAndroid) ...[
|
||||
const SizedBox(height: 12.0),
|
||||
FilterChip(
|
||||
label: Text(
|
||||
AppLocalizations.of(context)!.general_allow_screenshots),
|
||||
selected: ref.watch(androidAllowScreenshotsProvider),
|
||||
onSelected: (value) async {
|
||||
ref
|
||||
.read(androidAllowScreenshotsProvider.notifier)
|
||||
.setAllowScreenshots(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@ -201,8 +224,6 @@ class LoggingPanel extends ConsumerWidget {
|
||||
onChanged: (level) {
|
||||
ref.read(logLevelProvider.notifier).setLogLevel(level);
|
||||
_log.debug('Log level set to $level');
|
||||
showMessage(context,
|
||||
'${AppLocalizations.of(context)!.general_log_level_set_to} $level');
|
||||
},
|
||||
),
|
||||
ActionChip(
|
||||
|
@ -1,4 +0,0 @@
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
||||
final appMethodsProvider = Provider<MethodChannel>( (ref) => const MethodChannel('app.methods'));
|
@ -6,6 +6,21 @@ import '../app/state.dart';
|
||||
import 'devices.dart';
|
||||
|
||||
const _contextChannel = MethodChannel('android.state.appContext');
|
||||
const _methodsChannel = MethodChannel('app.methods');
|
||||
|
||||
final androidAllowScreenshotsProvider =
|
||||
StateNotifierProvider<AllowScreenshotsNotifier, bool>(
|
||||
(ref) => AllowScreenshotsNotifier(),
|
||||
);
|
||||
|
||||
class AllowScreenshotsNotifier extends StateNotifier<bool> {
|
||||
AllowScreenshotsNotifier() : super(false);
|
||||
|
||||
void setAllowScreenshots(bool value) async {
|
||||
state = value;
|
||||
await _methodsChannel.invokeMethod('hideAppThumbnail', !value);
|
||||
}
|
||||
}
|
||||
|
||||
final androidSubPageProvider =
|
||||
StateNotifierProvider<CurrentAppNotifier, Application>((ref) {
|
||||
|
@ -1,18 +1,12 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import 'package:yubico_authenticator/android/app_methods.dart';
|
||||
import 'package:yubico_authenticator/app/logging.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:yubico_authenticator/core/state.dart';
|
||||
|
||||
import '../../core/state.dart';
|
||||
import '../../app/state.dart';
|
||||
import '../../widgets/list_title.dart';
|
||||
import '../../widgets/responsive_dialog.dart';
|
||||
|
||||
final _log = Logger('android_settings_page');
|
||||
final _hideAppThumbnailProvider = StateProvider<bool>((ref) => true);
|
||||
|
||||
const String _prefNfcOpenApp = 'prefNfcOpenApp';
|
||||
const String _prefNfcBypassTouch = 'prefNfcBypassTouch';
|
||||
const String _prefNfcCopyOtp = 'prefNfcCopyOtp';
|
||||
@ -88,7 +82,6 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
prefs.getString(_prefClipKbdLayout) ?? _defaultClipKbdLayout;
|
||||
final nfcBypassTouch = prefs.getBool(_prefNfcBypassTouch) ?? false;
|
||||
final themeMode = ref.watch(themeModeProvider);
|
||||
final hideAppThumbnail = ref.watch(_hideAppThumbnailProvider);
|
||||
|
||||
final theme = Theme.of(context);
|
||||
|
||||
@ -149,21 +142,6 @@ class _AndroidSettingsPageState extends ConsumerState<AndroidSettingsPage> {
|
||||
ref.read(themeModeProvider.notifier).setThemeMode(newMode);
|
||||
},
|
||||
),
|
||||
const ListTitle('Security'),
|
||||
SwitchListTile(
|
||||
title: const Text('Hide app thumbnail'),
|
||||
value: hideAppThumbnail,
|
||||
onChanged: (value) async {
|
||||
try {
|
||||
bool hideAppThumbnail = await ref
|
||||
.read(appMethodsProvider)
|
||||
.invokeMethod('hideAppThumbnail', value);
|
||||
ref.read(_hideAppThumbnailProvider.notifier).state =
|
||||
hideAppThumbnail;
|
||||
} catch (e) {
|
||||
_log.error('Failed to call hideAppThumbnail', e);
|
||||
}
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
@ -4,6 +4,9 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import '../core/state.dart';
|
||||
import '../android/state.dart';
|
||||
|
||||
String _pad(int value, int zeroes) => value.toString().padLeft(zeroes, '0');
|
||||
|
||||
extension DateTimeFormat on DateTime {
|
||||
@ -85,23 +88,41 @@ class LogWarningOverlay extends StatelessWidget {
|
||||
children: [
|
||||
child,
|
||||
Consumer(builder: (context, ref, _) {
|
||||
if (ref.watch(logLevelProvider
|
||||
.select((level) => level.value <= Level.CONFIG.value))) {
|
||||
return const Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: IgnorePointer(
|
||||
child: Text(
|
||||
'WARNING: Potentially sensitive data is being logged!',
|
||||
textDirection: TextDirection.ltr,
|
||||
style: TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
final sensitiveLogs = ref.watch(logLevelProvider
|
||||
.select((level) => level.value <= Level.CONFIG.value));
|
||||
final allowScreenshots =
|
||||
isAndroid ? ref.watch(androidAllowScreenshotsProvider) : false;
|
||||
|
||||
if (!(sensitiveLogs || allowScreenshots)) {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
final String message;
|
||||
if (sensitiveLogs && allowScreenshots) {
|
||||
message =
|
||||
'Potentially sensitive data is being logged, and other apps can potentially record the screen';
|
||||
} else if (sensitiveLogs) {
|
||||
message = 'Potentially sensitive data is being logged';
|
||||
} else if (allowScreenshots) {
|
||||
message = 'Other apps can potentially record the screen';
|
||||
} else {
|
||||
return const SizedBox();
|
||||
}
|
||||
|
||||
return Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: IgnorePointer(
|
||||
child: Text(
|
||||
'WARNING: $message!',
|
||||
textDirection: TextDirection.ltr,
|
||||
textAlign: TextAlign.center,
|
||||
style: const TextStyle(
|
||||
color: Colors.red,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
return const SizedBox();
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
@ -81,6 +81,7 @@
|
||||
"mgmt_toggle_applications": "Toggle applications",
|
||||
"mgmt_save": "Save",
|
||||
|
||||
"general_about": "About",
|
||||
"general_terms_of_use": "Terms of use",
|
||||
"general_privacy_policy": "Privacy policy",
|
||||
"general_open_src_licenses": "Open source licenses",
|
||||
@ -92,10 +93,9 @@
|
||||
"general_run_diagnostics": "Run diagnostics",
|
||||
"general_diagnostics_copied": "Diagnostic data copied to clipboard",
|
||||
"general_log_level": "Log level",
|
||||
"general_log_level_set_to": "Log level set to",
|
||||
"general_copy_log": "Copy log",
|
||||
"general_log_copied": "Log copied to clipboard",
|
||||
|
||||
"general_allow_screenshots": "Allow screenshots",
|
||||
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user