basic desktop change passphrase functionality

This commit is contained in:
julian 2022-11-14 13:24:40 -06:00
parent bdf1008424
commit e053764554
2 changed files with 474 additions and 388 deletions

View file

@ -1,9 +1,13 @@
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/src/widgets/framework.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.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';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/widgets/desktop/primary_button.dart';
@ -47,6 +51,63 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
String passwordFeedback =
"Add another word or two. Uncommon words are better. Use a few words, avoid common phrases. No need for symbols, digits, or uppercase letters.";
Future<bool> attemptChangePW() async {
final String pw = passwordCurrentController.text;
final String pwNew = passwordController.text;
final String pwNewRepeat = passwordRepeatController.text;
final verified =
await ref.read(storageCryptoHandlerProvider).verifyPassphrase(pw);
if (verified) {
if (pwNew != pwNewRepeat) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "New passphrase does not match!",
context: context,
),
);
return false;
} else {
final success =
await ref.read(storageCryptoHandlerProvider).changePassphrase(
pw,
pwNew,
);
if (success) {
unawaited(
showFloatingFlushBar(
type: FlushBarType.success,
message: "Passphrase successfully changed",
context: context,
),
);
return true;
} else {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Passphrase change failed",
context: context,
),
);
return false;
}
}
} else {
unawaited(
showFloatingFlushBar(
type: FlushBarType.warning,
message: "Current passphrase is not valid!",
context: context,
),
);
return false;
}
}
@override
void initState() {
passwordCurrentController = TextEditingController();
@ -78,11 +139,12 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
debugPrint("BUILD: $runtimeType");
return Column(
children: [
Padding(
padding: const EdgeInsets.only(
right: 30,
),
Row(
children: [
Expanded(
child: RoundedWhiteContainer(
radiusMultiplier: 2,
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
@ -91,37 +153,29 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
width: 48,
height: 48,
),
Center(
child: Padding(
padding: const EdgeInsets.all(10),
child: RichText(
textAlign: TextAlign.start,
text: TextSpan(
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
TextSpan(
text: "Change Password",
const SizedBox(
height: 16,
),
Text(
"Change Password",
style: STextStyles.desktopTextSmall(context),
),
TextSpan(
text:
"\n\nProtect your Stack Wallet with a strong password. Stack Wallet does not store "
const SizedBox(
height: 8,
),
Text(
"Protect your Stack Wallet with a strong password. Stack Wallet does not store "
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
style:
STextStyles.desktopTextExtraExtraSmall(context),
),
],
const SizedBox(
height: 20,
),
),
),
),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: EdgeInsets.all(
10,
),
child: changePassword
changePassword
? SizedBox(
width: 512,
child: Column(
@ -129,8 +183,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
children: [
Text(
"Current password",
style:
STextStyles.desktopTextExtraExtraSmall(
style: STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
@ -179,7 +233,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye
: Assets.svg.eyeSlash,
color: Theme.of(context)
.extension<StackColors>()!
.extension<
StackColors>()!
.textDark3,
width: 16,
height: 16,
@ -192,14 +247,16 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
),
),
),
onChanged: (newValue) {},
onChanged: (newValue) {
setState(() {});
},
),
),
const SizedBox(height: 16),
Text(
"New password",
style:
STextStyles.desktopTextExtraExtraSmall(
style: STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
@ -248,7 +305,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye
: Assets.svg.eyeSlash,
color: Theme.of(context)
.extension<StackColors>()!
.extension<
StackColors>()!
.textDark3,
width: 16,
height: 16,
@ -310,8 +368,9 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
padding: EdgeInsets.only(
left: 12,
right: 12,
top:
passwordFeedback.isNotEmpty ? 4 : 0,
top: passwordFeedback.isNotEmpty
? 4
: 0,
),
child: passwordFeedback.isNotEmpty
? Text(
@ -357,8 +416,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
const SizedBox(height: 16),
Text(
"Confirm new password",
style:
STextStyles.desktopTextExtraExtraSmall(
style: STextStyles
.desktopTextExtraExtraSmall(
context)
.copyWith(
color: Theme.of(context)
@ -407,7 +466,8 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
? Assets.svg.eye
: Assets.svg.eyeSlash,
color: Theme.of(context)
.extension<StackColors>()!
.extension<
StackColors>()!
.textDark3,
width: 16,
height: 16,
@ -427,21 +487,25 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
),
const SizedBox(height: 20),
PrimaryButton(
width: 142,
width: 160,
desktopMed: true,
enabled: shouldEnableSave,
label: "Save changes",
onPressed: () {
onPressed: () async {
final didChangePW =
await attemptChangePW();
if (didChangePW) {
setState(() {
changePassword = false;
});
}
},
)
],
),
)
: PrimaryButton(
width: 192,
width: 210,
desktopMed: true,
enabled: true,
label: "Set up new password",
@ -451,38 +515,18 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
});
},
),
),
],
),
],
),
),
),
const SizedBox(
width: 40,
),
],
),
],
);
}
}
class NewPasswordButton extends ConsumerWidget {
const NewPasswordButton({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
return SizedBox(
width: 200,
height: 48,
child: TextButton(
style: Theme.of(context)
.extension<StackColors>()!
.getPrimaryEnabledButtonColor(context),
onPressed: () {},
child: Text(
"Set up new password",
style: STextStyles.button(context),
),
),
);
}
}

View file

@ -115,6 +115,48 @@ class DPS {
}
}
Future<bool> changePassphrase(
String passphraseOld,
String passphraseNew,
) async {
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
final keyBlob = DB.instance.get<String>(
boxName: DB.boxNameDesktopData,
key: _kKeyBlobKey,
);
await box.close();
if (keyBlob == null) {
// no passphrase key blob found so any passphrase is technically bad
return false;
}
if (!(await verifyPassphrase(passphraseOld))) {
return false;
}
try {
await _handler!.resetPassphrase(passphraseNew);
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
await DB.instance.put<String>(
boxName: DB.boxNameDesktopData,
key: _kKeyBlobKey,
value: await _handler!.getKeyBlob(),
);
await box.close();
// successfully updated passphrase
return true;
} catch (e, s) {
Logging.instance.log(
"${_getMessageFromException(e)}\n$s",
level: LogLevel.Warning,
);
return false;
}
}
Future<bool> hasPassword() async {
final keyBlob = DB.instance.get<String>(
boxName: DB.boxNameDesktopData,