This commit is contained in:
Dain Nilsson 2022-01-21 12:42:27 +01:00
commit f585825b8e
No known key found for this signature in database
GPG Key ID: F04367096FBA95E8
4 changed files with 78 additions and 22 deletions

View File

@ -6,6 +6,7 @@ import '../app/state.dart';
import 'state.dart';
import 'views/add_account_page.dart';
import 'views/password_dialog.dart';
import 'views/reset_dialog.dart';
List<MenuAction> buildOathMenuActions(
BuildContext context, AutoDisposeProviderRef ref) {
@ -41,14 +42,10 @@ List<MenuAction> buildOathMenuActions(
text: 'Factory reset',
icon: const Icon(Icons.delete_forever),
action: () {
ScaffoldMessenger.of(context)
..clearSnackBars()
..showSnackBar(
const SnackBar(
content: Text('Not implemented'),
duration: Duration(seconds: 2),
),
);
showDialog(
context: context,
builder: (context) => ResetDialog(device),
);
},
),
];

View File

@ -39,7 +39,7 @@ final oathStateProvider = StateNotifierProvider.autoDispose
.family<OathStateNotifier, OathState?, List<String>>(
(ref, devicePath) {
final session = ref.watch(_sessionProvider(devicePath));
final notifier = OathStateNotifier(session, ref.read);
final notifier = OathStateNotifier(session, ref);
session
..setErrorHandler('state-reset', (_) async {
ref.refresh(_sessionProvider(devicePath));
@ -58,20 +58,20 @@ final oathStateProvider = StateNotifierProvider.autoDispose
class OathStateNotifier extends StateNotifier<OathState?> {
final RpcNodeSession _session;
final Reader _read;
OathStateNotifier(this._session, this._read) : super(null);
final Ref _ref;
OathStateNotifier(this._session, this._ref) : super(null);
refresh() async {
var result = await _session.command('get');
log.config('application status', jsonEncode(result));
var oathState = OathState.fromJson(result['data']);
final key = _read(_lockKeyProvider(_session.devicePath));
final key = _ref.read(_lockKeyProvider(_session.devicePath));
if (oathState.locked && key != null) {
final result = await _session.command('validate', params: {'key': key});
if (result['unlocked']) {
oathState = oathState.copyWith(locked: false);
} else {
_read(_lockKeyProvider(_session.devicePath).notifier).unsetKey();
_ref.read(_lockKeyProvider(_session.devicePath).notifier).unsetKey();
}
}
if (mounted) {
@ -79,6 +79,12 @@ class OathStateNotifier extends StateNotifier<OathState?> {
}
}
Future<void> reset() async {
await _session.command('reset');
_ref.read(_lockKeyProvider(_session.devicePath).notifier).unsetKey();
_ref.refresh(_sessionProvider(_session.devicePath));
}
Future<bool> unlock(String password) async {
var result =
await _session.command('derive', params: {'password': password});
@ -86,19 +92,16 @@ class OathStateNotifier extends StateNotifier<OathState?> {
final status = await _session.command('validate', params: {'key': key});
if (mounted && status['unlocked']) {
log.config('applet unlocked');
_read(_lockKeyProvider(_session.devicePath).notifier).setKey(key);
_ref.read(_lockKeyProvider(_session.devicePath).notifier).setKey(key);
state = state?.copyWith(locked: false);
}
return status['unlocked'];
}
Future<bool> _checkPassword(String password) async {
log.info('Calling check password $password');
var result =
await _session.command('derive', params: {'password': password});
log.info(
'Check ${_read(_lockKeyProvider(_session.devicePath))} == ${result['key']}');
return _read(_lockKeyProvider(_session.devicePath)) == result['key'];
return _ref.read(_lockKeyProvider(_session.devicePath)) == result['key'];
}
Future<bool> setPassword(String? current, String password) async {
@ -117,7 +120,7 @@ class OathStateNotifier extends StateNotifier<OathState?> {
var key = result['key'];
await _session.command('set_key', params: {'key': key});
log.config('OATH key set');
_read(_lockKeyProvider(_session.devicePath).notifier).setKey(key);
_ref.read(_lockKeyProvider(_session.devicePath).notifier).setKey(key);
if (mounted) {
state = state?.copyWith(hasKey: true);
}
@ -131,7 +134,7 @@ class OathStateNotifier extends StateNotifier<OathState?> {
}
}
await _session.command('unset_key');
_read(_lockKeyProvider(_session.devicePath).notifier).unsetKey();
_ref.read(_lockKeyProvider(_session.devicePath).notifier).unsetKey();
if (mounted) {
state = state?.copyWith(hasKey: false, locked: false);
}

View File

@ -140,13 +140,13 @@ class _ManagePasswordDialogState extends ConsumerState<ManagePasswordDialog> {
],
),
actions: [
TextButton(
OutlinedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
TextButton(
ElevatedButton(
onPressed: _newPassword.isNotEmpty &&
_newPassword == _confirmPassword &&
(!hasKey || _currentPassword.isNotEmpty)

View File

@ -0,0 +1,56 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:yubico_authenticator/oath/state.dart';
import '../../app/models.dart';
import '../../app/state.dart';
class ResetDialog extends ConsumerWidget {
final DeviceNode device;
const ResetDialog(this.device, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
// If current device changes, we need to pop back to the main Page.
ref.listen<DeviceNode?>(currentDeviceProvider, (previous, next) {
Navigator.of(context).pop();
});
return AlertDialog(
title: const Text('Reset to defaults?'),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
const Text(
'Warning! This will irrevocably delete all OATH TOTP/HOTP accounts from your YubiKey.'),
const Text(''),
Text(
'You OATH credentials, as well as any password set, will be removed from this YubiKey. Make sure to first disable these from their respective web sites to avoid being locked out of your accounts.',
style: Theme.of(context).textTheme.bodyText1,
),
],
),
actions: [
OutlinedButton(
onPressed: () {
Navigator.of(context).pop();
},
child: const Text('Cancel'),
),
ElevatedButton(
onPressed: () async {
await ref.read(oathStateProvider(device.path).notifier).reset();
Navigator.of(context).pop();
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('OATH application reset'),
duration: Duration(seconds: 2),
),
);
},
child: const Text('Reset YubiKey'),
),
],
);
}
}