From 76844a562b12c8ca7e8a7928fb42922411be33ed Mon Sep 17 00:00:00 2001 From: julian Date: Wed, 1 May 2024 10:44:06 -0600 Subject: [PATCH] encode resharer names in resharer config --- .../reshare/frost_reshare_step_1a.dart | 13 +- .../reshare/frost_reshare_step_1b.dart | 11 +- .../reshare/frost_reshare_step_1c.dart | 2 +- .../reshare/frost_reshare_step_2abd.dart | 169 +++-------------- .../reshare/frost_reshare_step_2c.dart | 168 +++-------------- .../reshare/frost_reshare_step_4.dart | 170 +++--------------- .../complete_reshare_config_view.dart | 9 +- .../initiate_resharing_view.dart | 5 +- .../frost_wallet/frost_wallet_providers.dart | 11 +- lib/route_generator.dart | 2 +- lib/services/frost.dart | 43 ++++- 11 files changed, 143 insertions(+), 460 deletions(-) diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart index d99851e03..9f819b760 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1a.dart @@ -63,7 +63,9 @@ class _FrostReshareStep1aState extends ConsumerState { if (mounted) { final result = Frost.beginResharer( serializedKeys: serializedKeys!, - config: ref.read(pFrostResharingData).resharerConfig!, + config: Frost.decodeRConfig( + ref.read(pFrostResharingData).resharerRConfig!, + ), ); ref.read(pFrostResharingData).startResharerData = result; @@ -216,6 +218,7 @@ class _FrostReshareStep1aState extends ConsumerState { .read(pFrostResharingData) .configData! .resharers + .values .contains(myOldIndex); super.initState(); } @@ -236,7 +239,7 @@ class _FrostReshareStep1aState extends ConsumerState { mainAxisAlignment: MainAxisAlignment.center, children: [ QrImageView( - data: ref.watch(pFrostResharingData).resharerConfig!, + data: ref.watch(pFrostResharingData).resharerRConfig!, size: 220, backgroundColor: Theme.of(context).extension()!.background, @@ -252,13 +255,13 @@ class _FrostReshareStep1aState extends ConsumerState { ), DetailItem( title: "Config", - detail: ref.watch(pFrostResharingData).resharerConfig!, + detail: ref.watch(pFrostResharingData).resharerRConfig!, button: Util.isDesktop ? IconCopyButton( - data: ref.watch(pFrostResharingData).resharerConfig!, + data: ref.watch(pFrostResharingData).resharerRConfig!, ) : SimpleCopyButton( - data: ref.watch(pFrostResharingData).resharerConfig!, + data: ref.watch(pFrostResharingData).resharerRConfig!, ), ), SizedBox( diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart index 998bc12f5..81815fff8 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1b.dart @@ -63,13 +63,16 @@ class _FrostReshareStep1bState extends ConsumerState { ref.read(pFrostResharingData).reset(); ref.read(pFrostResharingData).myName = frostInfo.myName; - ref.read(pFrostResharingData).resharerConfig = configFieldController.text; + ref.read(pFrostResharingData).resharerRConfig = + configFieldController.text; String? salt; try { salt = Format.uint8listToString( resharerSalt( - resharerConfig: ref.read(pFrostResharingData).resharerConfig!, + resharerConfig: Frost.decodeRConfig( + ref.read(pFrostResharingData).resharerRConfig!, + ), ), ); } catch (_) { @@ -97,7 +100,9 @@ class _FrostReshareStep1bState extends ConsumerState { if (mounted) { final result = Frost.beginResharer( serializedKeys: serializedKeys!, - config: ref.read(pFrostResharingData).resharerConfig!, + config: Frost.decodeRConfig( + ref.read(pFrostResharingData).resharerRConfig!, + ), ); ref.read(pFrostResharingData).startResharerData = result; diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart index 56d28c499..b46cd3587 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_1c.dart @@ -176,7 +176,7 @@ class _FrostReshareStep1cState extends ConsumerState { ref.read(pFrostResharingData).reset(); ref.read(pFrostResharingData).myName = myNameFieldController.text; - ref.read(pFrostResharingData).resharerConfig = + ref.read(pFrostResharingData).resharerRConfig = configFieldController.text; if (!ref diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart index fdbb2f4cf..bd2b5c8ce 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2abd.dart @@ -1,8 +1,6 @@ import 'dart:async'; -import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart'; @@ -11,20 +9,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart'; import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; -import 'package:stackwallet/widgets/stack_text_field.dart'; -import 'package:stackwallet/widgets/textfield_icon_button.dart'; +import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep2abd extends ConsumerStatefulWidget { const FrostReshareStep2abd({super.key}); @@ -41,7 +33,7 @@ class _FrostReshareStep2abdState extends ConsumerState { final List controllers = []; final List focusNodes = []; - late final List resharerIndexes; + late final Map resharers; late final int myResharerIndexIndex; late final String myResharerStart; late final bool amOutgoingParticipant; @@ -67,7 +59,9 @@ class _FrostReshareStep2abdState extends ConsumerState { final result = Frost.beginReshared( myName: ref.read(pFrostResharingData).myName!, - resharerConfig: ref.read(pFrostResharingData).resharerConfig!, + resharerConfig: Frost.decodeRConfig( + ref.read(pFrostResharingData).resharerRConfig!, + ), resharerStarts: resharerStarts, ); @@ -116,11 +110,11 @@ class _FrostReshareStep2abdState extends ConsumerState { myResharerStart = ref.read(pFrostResharingData).startResharerData!.resharerStart; - resharerIndexes = ref.read(pFrostResharingData).configData!.resharers; - myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex); + resharers = ref.read(pFrostResharingData).configData!.resharers; + myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex); if (myResharerIndexIndex >= 0) { // remove my name for now as we don't need a text field for it - resharerIndexes.removeAt(myResharerIndexIndex); + resharers.remove(ref.read(pFrostResharingData).myName!); } amOutgoingParticipant = !ref @@ -129,7 +123,7 @@ class _FrostReshareStep2abdState extends ConsumerState { .newParticipants .contains(ref.read(pFrostResharingData).myName!); - for (int i = 0; i < resharerIndexes.length; i++) { + for (int i = 0; i < resharers.length; i++) { controllers.add(TextEditingController()); focusNodes.add(FocusNode()); fieldIsEmptyFlags.add(true); @@ -192,137 +186,20 @@ class _FrostReshareStep2abdState extends ConsumerState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - for (int i = 0; i < resharerIndexes.length; i++) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - key: Key("frostResharerTextFieldKey_$i"), - controller: controllers[i], - focusNode: focusNodes[i], - readOnly: false, - autocorrect: false, - enableSuggestions: false, - style: STextStyles.field(context), - onChanged: (_) { - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - }, - decoration: standardInputDecoration( - "Enter index " - "${resharerIndexes[i]}" - "'s resharer", - focusNodes[i], - context, - ).copyWith( - contentPadding: const EdgeInsets.only( - left: 16, - top: 6, - bottom: 8, - right: 5, - ), - suffixIcon: Padding( - padding: fieldIsEmptyFlags[i] - ? const EdgeInsets.only(right: 8) - : const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - !fieldIsEmptyFlags[i] - ? TextFieldIconButton( - semanticsLabel: - "Clear Button. Clears The Resharer Field Input.", - key: Key( - "frostResharerClearButtonKey_$i"), - onTap: () { - controllers[i].text = ""; - - setState(() { - fieldIsEmptyFlags[i] = true; - }); - }, - child: const XIcon(), - ) - : TextFieldIconButton( - semanticsLabel: - "Paste Button. Pastes From Clipboard To Resharer Field Input.", - key: Key( - "frostResharerPasteButtonKey_$i"), - onTap: () async { - final ClipboardData? data = - await Clipboard.getData( - Clipboard.kTextPlain); - if (data?.text != null && - data!.text!.isNotEmpty) { - controllers[i].text = - data.text!.trim(); - } - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - }, - child: fieldIsEmptyFlags[i] - ? const ClipboardIcon() - : const XIcon(), - ), - if (fieldIsEmptyFlags[i]) - TextFieldIconButton( - semanticsLabel: "Scan QR Button. " - "Opens Camera For Scanning QR Code.", - key: Key( - "frostCommitmentsScanQrButtonKey_$i"), - onTap: () async { - try { - if (FocusScope.of(context) - .hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration( - milliseconds: 75)); - } - - final qrResult = - await BarcodeScanner.scan(); - - controllers[i].text = - qrResult.rawContent; - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - } on PlatformException catch (e, s) { - Logging.instance.log( - "Failed to get camera permissions " - "while trying to scan qr code: $e\n$s", - level: LogLevel.Warning, - ); - } - }, - child: const QrCodeIcon(), - ), - ], - ), - ), - ), - ), - ), - ), - ), - ], + for (int i = 0; i < resharers.length; i++) + FrostStepField( + controller: controllers[i], + focusNode: focusNodes[i], + showQrScanOption: true, + label: resharers.keys.elementAt(i), + hint: "Enter " + "${resharers.keys.elementAt(i)}" + "'s resharer", + onChanged: (_) { + setState(() { + fieldIsEmptyFlags[i] = controllers[i].text.isEmpty; + }); + }, ), ], ), diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart index 88c112095..6ba4dd5ca 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_2c.dart @@ -1,23 +1,15 @@ import 'dart:async'; -import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart'; import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart'; import 'package:stackwallet/services/frost.dart'; -import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; -import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; -import 'package:stackwallet/widgets/stack_text_field.dart'; -import 'package:stackwallet/widgets/textfield_icon_button.dart'; +import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; class FrostReshareStep2c extends ConsumerStatefulWidget { const FrostReshareStep2c({super.key}); @@ -33,7 +25,7 @@ class _FrostReshareStep2cState extends ConsumerState { final List controllers = []; final List focusNodes = []; - late final List resharerIndexes; + late final Map resharers; final List fieldIsEmptyFlags = []; @@ -50,7 +42,9 @@ class _FrostReshareStep2cState extends ConsumerState { final result = Frost.beginReshared( myName: ref.read(pFrostResharingData).myName!, - resharerConfig: ref.read(pFrostResharingData).resharerConfig!, + resharerConfig: Frost.decodeRConfig( + ref.read(pFrostResharingData).resharerRConfig!, + ), resharerStarts: resharerStarts, ); @@ -84,9 +78,9 @@ class _FrostReshareStep2cState extends ConsumerState { @override void initState() { - resharerIndexes = ref.read(pFrostResharingData).configData!.resharers; + resharers = ref.read(pFrostResharingData).configData!.resharers; - for (int i = 0; i < resharerIndexes.length; i++) { + for (int i = 0; i < resharers.length; i++) { controllers.add(TextEditingController()); focusNodes.add(FocusNode()); fieldIsEmptyFlags.add(true); @@ -115,137 +109,23 @@ class _FrostReshareStep2cState extends ConsumerState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - for (int i = 0; i < resharerIndexes.length; i++) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - key: Key("frostResharerTextFieldKey_$i"), - controller: controllers[i], - focusNode: focusNodes[i], - readOnly: false, - autocorrect: false, - enableSuggestions: false, - style: STextStyles.field(context), - onChanged: (_) { - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - }, - decoration: standardInputDecoration( - "Enter index " - "${resharerIndexes[i]}" - "'s resharer", - focusNodes[i], - context, - ).copyWith( - contentPadding: const EdgeInsets.only( - left: 16, - top: 6, - bottom: 8, - right: 5, - ), - suffixIcon: Padding( - padding: fieldIsEmptyFlags[i] - ? const EdgeInsets.only(right: 8) - : const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - !fieldIsEmptyFlags[i] - ? TextFieldIconButton( - semanticsLabel: - "Clear Button. Clears The Resharer Field Input.", - key: Key( - "frostResharerClearButtonKey_$i"), - onTap: () { - controllers[i].text = ""; - - setState(() { - fieldIsEmptyFlags[i] = true; - }); - }, - child: const XIcon(), - ) - : TextFieldIconButton( - semanticsLabel: - "Paste Button. Pastes From Clipboard To Resharer Field Input.", - key: Key( - "frostResharerPasteButtonKey_$i"), - onTap: () async { - final ClipboardData? data = - await Clipboard.getData( - Clipboard.kTextPlain); - if (data?.text != null && - data!.text!.isNotEmpty) { - controllers[i].text = - data.text!.trim(); - } - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - }, - child: fieldIsEmptyFlags[i] - ? const ClipboardIcon() - : const XIcon(), - ), - if (fieldIsEmptyFlags[i]) - TextFieldIconButton( - semanticsLabel: "Scan QR Button. " - "Opens Camera For Scanning QR Code.", - key: Key( - "frostCommitmentsScanQrButtonKey_$i"), - onTap: () async { - try { - if (FocusScope.of(context) - .hasFocus) { - FocusScope.of(context).unfocus(); - await Future.delayed( - const Duration( - milliseconds: 75)); - } - - final qrResult = - await BarcodeScanner.scan(); - - controllers[i].text = - qrResult.rawContent; - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - } on PlatformException catch (e, s) { - Logging.instance.log( - "Failed to get camera permissions " - "while trying to scan qr code: $e\n$s", - level: LogLevel.Warning, - ); - } - }, - child: const QrCodeIcon(), - ), - ], - ), - ), - ), - ), - ), - ), - ), - ], + for (int i = 0; i < resharers.length; i++) + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: FrostStepField( + controller: controllers[i], + focusNode: focusNodes[i], + showQrScanOption: true, + label: resharers.keys.elementAt(i), + hint: "Enter " + "${resharers.keys.elementAt(i)}" + "'s resharer", + onChanged: (_) { + setState(() { + fieldIsEmptyFlags[i] = controllers[i].text.isEmpty; + }); + }, + ), ), ], ), diff --git a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart index 52789ebe2..8a6c3e302 100644 --- a/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart +++ b/lib/pages/add_wallet_views/frost_ms/reshare/frost_reshare_step_4.dart @@ -1,8 +1,6 @@ import 'dart:ffi'; -import 'package:barcode_scan2/barcode_scan2.dart'; import 'package:flutter/material.dart'; -import 'package:flutter/services.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:qr_flutter/qr_flutter.dart'; import 'package:stackwallet/pages/add_wallet_views/frost_ms/new/steps/frost_route_generator.dart'; @@ -13,20 +11,14 @@ import 'package:stackwallet/providers/db/main_db_provider.dart'; import 'package:stackwallet/providers/frost_wallet/frost_wallet_providers.dart'; import 'package:stackwallet/services/frost.dart'; import 'package:stackwallet/themes/stack_colors.dart'; -import 'package:stackwallet/utilities/constants.dart'; import 'package:stackwallet/utilities/logger.dart'; -import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/util.dart'; import 'package:stackwallet/wallets/isar/models/frost_wallet_info.dart'; import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart'; import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/detail_item.dart'; -import 'package:stackwallet/widgets/icon_widgets/clipboard_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/qrcode_icon.dart'; -import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_dialog.dart'; -import 'package:stackwallet/widgets/stack_text_field.dart'; -import 'package:stackwallet/widgets/textfield_icon_button.dart'; +import 'package:stackwallet/widgets/textfields/frost_step_field.dart'; // was FinishResharingView class FrostReshareStep4 extends ConsumerStatefulWidget { @@ -43,7 +35,7 @@ class _FrostReshareStep4State extends ConsumerState { final List controllers = []; final List focusNodes = []; - late final List resharerIndexes; + late final Map resharers; late final String myName; late final int? myResharerIndexIndex; late final String? myResharerComplete; @@ -118,7 +110,7 @@ class _FrostReshareStep4State extends ConsumerState { myName = ref.read(pFrostResharingData).myName!; - resharerIndexes = ref.read(pFrostResharingData).configData!.resharers; + resharers = ref.read(pFrostResharingData).configData!.resharers; if (amNewParticipant) { myResharerComplete = null; @@ -135,10 +127,10 @@ class _FrostReshareStep4State extends ConsumerState { final myOldIndex = frostInfo.participants.indexOf(ref.read(pFrostResharingData).myName!); - myResharerIndexIndex = resharerIndexes.indexOf(myOldIndex); + myResharerIndexIndex = resharers.values.toList().indexOf(myOldIndex); if (myResharerIndexIndex! >= 0) { // remove my name for now as we don't need a text field for it - resharerIndexes.removeAt(myResharerIndexIndex!); + resharers.remove(ref.read(pFrostResharingData).myName!); } amOutgoingParticipant = !ref @@ -148,7 +140,7 @@ class _FrostReshareStep4State extends ConsumerState { .contains(ref.read(pFrostResharingData).myName!); } - for (int i = 0; i < resharerIndexes.length; i++) { + for (int i = 0; i < resharers.length; i++) { controllers.add(TextEditingController()); focusNodes.add(FocusNode()); fieldIsEmptyFlags.add(true); @@ -216,139 +208,23 @@ class _FrostReshareStep4State extends ConsumerState { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ - for (int i = 0; i < resharerIndexes.length; i++) - Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(vertical: 8), - child: ClipRRect( - borderRadius: BorderRadius.circular( - Constants.size.circularBorderRadius, - ), - child: TextField( - key: Key("frostEncryptionKeyTextFieldKey_$i"), - controller: controllers[i], - focusNode: focusNodes[i], - readOnly: false, - autocorrect: false, - enableSuggestions: false, - style: STextStyles.field(context), - onChanged: (_) { - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - }, - decoration: standardInputDecoration( - "Enter index " - "${resharerIndexes[i]}" - "'s resharer complete", - focusNodes[i], - context, - ).copyWith( - contentPadding: const EdgeInsets.only( - left: 16, - top: 6, - bottom: 8, - right: 5, - ), - suffixIcon: Padding( - padding: fieldIsEmptyFlags[i] - ? const EdgeInsets.only(right: 8) - : const EdgeInsets.only(right: 0), - child: UnconstrainedBox( - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceAround, - children: [ - !fieldIsEmptyFlags[i] - ? TextFieldIconButton( - semanticsLabel: - "Clear Button. Clears The Encryption Key Field Input.", - key: Key( - "frostEncryptionKeyClearButtonKey_$i"), - onTap: () { - controllers[i].text = ""; - - setState(() { - fieldIsEmptyFlags[i] = true; - }); - }, - child: const XIcon(), - ) - : TextFieldIconButton( - semanticsLabel: - "Paste Button. Pastes From Clipboard To Encryption Key Field Input.", - key: Key( - "frostEncryptionKeyPasteButtonKey_$i"), - onTap: () async { - final ClipboardData? data = - await Clipboard.getData( - Clipboard.kTextPlain); - if (data?.text != null && - data!.text!.isNotEmpty) { - controllers[i].text = - data.text!.trim(); - } - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i] - .text - .isEmpty; - }); - }, - child: fieldIsEmptyFlags[i] - ? const ClipboardIcon() - : const XIcon(), - ), - if (fieldIsEmptyFlags[i]) - TextFieldIconButton( - semanticsLabel: "Scan QR Button. " - "Opens Camera For Scanning QR Code.", - key: Key("frostScanQrButtonKey_$i"), - onTap: () async { - try { - if (FocusScope.of(context) - .hasFocus) { - FocusScope.of(context) - .unfocus(); - await Future.delayed( - const Duration( - milliseconds: 75)); - } - - final qrResult = - await BarcodeScanner.scan(); - - controllers[i].text = - qrResult.rawContent; - - setState(() { - fieldIsEmptyFlags[i] = - controllers[i].text.isEmpty; - }); - } on PlatformException catch (e, s) { - Logging.instance.log( - "Failed to get camera permissions " - "while trying to scan qr code: $e\n$s", - level: LogLevel.Warning, - ); - } - }, - child: const QrCodeIcon(), - ), - ], - ), - ), - ), - ), - ), - ), - ), - ], + for (int i = 0; i < resharers.length; i++) + Padding( + padding: const EdgeInsets.symmetric(vertical: 8), + child: FrostStepField( + controller: controllers[i], + focusNode: focusNodes[i], + showQrScanOption: true, + label: resharers.keys.elementAt(i), + hint: "Enter " + "${resharers.keys.elementAt(i)}" + "'s resharer", + onChanged: (_) { + setState(() { + fieldIsEmptyFlags[i] = controllers[i].text.isEmpty; + }); + }, + ), ), ], ), diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart index ffb1fab0b..03cffcb51 100644 --- a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/complete_reshare_config_view.dart @@ -37,7 +37,7 @@ final class CompleteReshareConfigView extends ConsumerStatefulWidget { static const String routeName = "/completeReshareConfigView"; final String walletId; - final List resharers; + final Map resharers; @override ConsumerState createState() => @@ -91,7 +91,7 @@ class _CompleteReshareConfigViewState final config = Frost.createResharerConfig( newThreshold: int.parse(_newThresholdController.text), - resharers: widget.resharers, + resharers: widget.resharers.values.toList(), newParticipants: newParticipants, ); @@ -121,7 +121,10 @@ class _CompleteReshareConfigViewState } ref.read(pFrostResharingData).myName = myName; - ref.read(pFrostResharingData).resharerConfig = config; + ref.read(pFrostResharingData).resharerRConfig = Frost.encodeRConfig( + config, + widget.resharers, + ); final wallet = ref.read(pWallets).getWallet(widget.walletId) as BitcoinFrostWallet; diff --git a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart index 87345370f..ca5ab67e7 100644 --- a/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart +++ b/lib/pages/settings_views/wallet_settings_view/frost_ms/initiate_resharing/initiate_resharing_view.dart @@ -234,10 +234,11 @@ class _BeginReshareConfigViewState onPressed: () async { // include self now selectedParticipants.add(myName); - final List resharers = []; + + final Map resharers = {}; for (final name in selectedParticipants) { - resharers.add(originalParticipants.indexOf(name)); + resharers[name] = originalParticipants.indexOf(name); } await Navigator.of(context).pushNamed( diff --git a/lib/providers/frost_wallet/frost_wallet_providers.dart b/lib/providers/frost_wallet/frost_wallet_providers.dart index 3b181b7b8..7b3ee3eda 100644 --- a/lib/providers/frost_wallet/frost_wallet_providers.dart +++ b/lib/providers/frost_wallet/frost_wallet_providers.dart @@ -60,13 +60,14 @@ class _ResharingData { IncompleteFrostWallet? incompleteWallet; // resharer encoded config string - String? resharerConfig; + String? resharerRConfig; + ({ int newThreshold, - List resharers, + Map resharers, List newParticipants, - })? get configData => resharerConfig != null - ? Frost.extractResharerConfigData(resharerConfig: resharerConfig!) + })? get configData => resharerRConfig != null + ? Frost.extractResharerConfigData(rConfig: resharerRConfig!) : null; // resharer start string (for sharing) and machine @@ -93,7 +94,7 @@ class _ResharingData { // reset/clear all data void reset() { - resharerConfig = null; + resharerRConfig = null; startResharerData = null; startResharedData = null; resharerComplete = null; diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 28402ebfb..d60c60de3 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -542,7 +542,7 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case CompleteReshareConfigView.routeName: - if (args is ({String walletId, List resharers})) { + if (args is ({String walletId, Map resharers})) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => CompleteReshareConfigView( diff --git a/lib/services/frost.dart b/lib/services/frost.dart index a420a5b16..adf88695a 100644 --- a/lib/services/frost.dart +++ b/lib/services/frost.dart @@ -1,3 +1,4 @@ +import 'dart:convert'; import 'dart:ffi'; import 'dart:typed_data'; @@ -551,11 +552,14 @@ abstract class Frost { static ({ int newThreshold, - List resharers, + Map resharers, List newParticipants, }) extractResharerConfigData({ - required String resharerConfig, + required String rConfig, }) { + final decoded = _decodeRConfigWithResharers(rConfig); + final resharerConfig = decoded.config; + try { final newThreshold = resharerNewThreshold( resharerConfigPointer: decodedResharerConfig( @@ -597,9 +601,17 @@ abstract class Frost { ); } + final Map resharersMap = {}; + + for (final resharer in resharers) { + resharersMap[decoded.resharers.entries + .firstWhere((e) => e.value == resharer) + .key] = resharer; + } + return ( newThreshold: newThreshold, - resharers: resharers, + resharers: resharersMap, newParticipants: newParticipants, ); } catch (e, s) { @@ -610,4 +622,29 @@ abstract class Frost { rethrow; } } + + static String encodeRConfig( + String config, + Map resharers, + ) { + return base64Encode("$config@${jsonEncode(resharers)}".toUint8ListFromUtf8); + } + + static String decodeRConfig( + String rConfig, + ) { + return base64Decode(rConfig).toUtf8String.split("@").first; + } + + static ({Map resharers, String config}) + _decodeRConfigWithResharers( + String rConfig, + ) { + final parts = base64Decode(rConfig).toUtf8String.split("@"); + + final config = parts[0]; + final resharers = Map.from(jsonDecode(parts[1]) as Map); + + return (resharers: resharers, config: config); + } }