WIP: desktop password

This commit is contained in:
julian 2022-11-04 13:32:02 -06:00
parent 21f18326d8
commit 4dd8ae23c5
5 changed files with 174 additions and 15 deletions

View file

@ -30,7 +30,8 @@ import 'package:stackwallet/pages/loading_view.dart';
import 'package:stackwallet/pages/pinpad_views/create_pin_view.dart';
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/desktop_login_view.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
import 'package:stackwallet/providers/global/base_currencies_provider.dart';
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
@ -207,6 +208,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
late final Completer<void> loadingCompleter;
bool didLoad = false;
bool _desktopHasPassword = false;
Future<void> load() async {
try {
@ -218,6 +220,11 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
await DB.instance.init();
await _prefs.init();
if (Util.isDesktop) {
_desktopHasPassword =
await ref.read(storageCryptoHandlerProvider).hasPassword();
}
_notificationsService = ref.read(notificationsProvider);
_nodeService = ref.read(nodeServiceChangeNotifierProvider);
_tradesService = ref.read(tradesServiceProvider);
@ -545,21 +552,23 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// FlutterNativeSplash.remove();
if (_wallets.hasWallets || _prefs.hasPin) {
// return HomeView();
if (Util.isDesktop &&
(_wallets.hasWallets || _desktopHasPassword)) {
String? startupWalletId;
if (ref.read(prefsChangeNotifierProvider).gotoWalletOnStartup) {
startupWalletId =
ref.read(prefsChangeNotifierProvider).startupWalletId;
}
// TODO proper desktop auth view
if (Util.isDesktop) {
Future<void>.delayed(Duration.zero).then((value) =>
Navigator.of(context).pushNamedAndRemoveUntil(
DesktopHomeView.routeName, (route) => false));
return Container();
return DesktopLoginView(startupWalletId: startupWalletId);
} else if (!Util.isDesktop &&
(_wallets.hasWallets || _prefs.hasPin)) {
// return HomeView();
String? startupWalletId;
if (ref.read(prefsChangeNotifierProvider).gotoWalletOnStartup) {
startupWalletId =
ref.read(prefsChangeNotifierProvider).startupWalletId;
}
return LockscreenView(

View file

@ -1,10 +1,12 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/constants.dart';
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
@ -18,7 +20,7 @@ import 'package:stackwallet/widgets/progress_bar.dart';
import 'package:stackwallet/widgets/stack_text_field.dart';
import 'package:zxcvbn/zxcvbn.dart';
class CreatePasswordView extends StatefulWidget {
class CreatePasswordView extends ConsumerStatefulWidget {
const CreatePasswordView({
Key? key,
this.secureStore = const SecureStorageWrapper(
@ -31,10 +33,10 @@ class CreatePasswordView extends StatefulWidget {
final FlutterSecureStorageInterface secureStore;
@override
State<CreatePasswordView> createState() => _CreatePasswordViewState();
ConsumerState<CreatePasswordView> createState() => _CreatePasswordViewState();
}
class _CreatePasswordViewState extends State<CreatePasswordView> {
class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
late final TextEditingController passwordController;
late final TextEditingController passwordRepeatController;
@ -76,8 +78,16 @@ class _CreatePasswordViewState extends State<CreatePasswordView> {
return;
}
await widget.secureStore
.write(key: "stackDesktopPassword", value: passphrase);
try {
await ref.read(storageCryptoHandlerProvider).initFromNew(passphrase);
} catch (e) {
unawaited(showFloatingFlushBar(
type: FlushBarType.warning,
message: "Error: $e",
context: context,
));
return;
}
if (mounted) {
unawaited(Navigator.of(context)

View file

@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
class DesktopLoginView extends StatefulWidget {
const DesktopLoginView({
Key? key,
this.startupWalletId,
}) : super(key: key);
static const String routeName = "/desktopLogin";
final String? startupWalletId;
@override
State<DesktopLoginView> createState() => _DesktopLoginViewState();
}
class _DesktopLoginViewState extends State<DesktopLoginView> {
@override
Widget build(BuildContext context) {
return Material(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"Login",
style: STextStyles.desktopH3(context),
),
PrimaryButton(
label: "Login",
onPressed: () {
// todo auth
Navigator.of(context).pushNamedAndRemoveUntil(
DesktopHomeView.routeName,
(route) => false,
);
},
)
],
),
);
}
}

View file

@ -0,0 +1,4 @@
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/utilities/desktop_password_service.dart';
final storageCryptoHandlerProvider = Provider<DPS>((ref) => DPS());

View file

@ -0,0 +1,89 @@
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:stack_wallet_backup/secure_storage.dart';
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
import 'package:stackwallet/utilities/logger.dart';
const String _kKeyBlobKey = "swbKeyBlobKeyStringID";
String _getMessageFromException(Object exception) {
if (exception is IncorrectPassphrase) {
return exception.errMsg();
}
if (exception is BadDecryption) {
return exception.errMsg();
}
if (exception is InvalidLength) {
return exception.errMsg();
}
if (exception is EncodingError) {
return exception.errMsg();
}
return exception.toString();
}
class DPS {
StorageCryptoHandler? _handler;
final SecureStorageWrapper secureStorageWrapper;
StorageCryptoHandler get handler {
if (_handler == null) {
throw Exception(
"DPS: attempted to access handler without proper authentication");
}
return _handler!;
}
DPS({
this.secureStorageWrapper = const SecureStorageWrapper(
FlutterSecureStorage(),
),
});
Future<void> initFromNew(String passphrase) async {
if (_handler != null) {
throw Exception("DPS: attempted to re initialize with new passphrase");
}
try {
_handler = await StorageCryptoHandler.fromNewPassphrase(passphrase);
await secureStorageWrapper.write(
key: _kKeyBlobKey,
value: await _handler!.getKeyBlob(),
);
} catch (e, s) {
Logging.instance.log(
"${_getMessageFromException(e)}\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
Future<void> initFromExisting(String passphrase) async {
if (_handler != null) {
throw Exception(
"DPS: attempted to re initialize with existing passphrase");
}
final keyBlob = await secureStorageWrapper.read(key: _kKeyBlobKey);
if (keyBlob == null) {
throw Exception(
"DPS: failed to find keyBlob while attempting to initialize with existing passphrase");
}
try {
_handler = await StorageCryptoHandler.fromExisting(passphrase, keyBlob);
} catch (e, s) {
Logging.instance.log(
"${_getMessageFromException(e)}\n$s",
level: LogLevel.Error,
);
rethrow;
}
}
Future<bool> hasPassword() async {
return (await secureStorageWrapper.read(key: _kKeyBlobKey)) != null;
}
}