From 70dea710ae4e4427402120cc8f54516d9f2cf9b4 Mon Sep 17 00:00:00 2001 From: edouard Date: Thu, 19 Oct 2023 18:00:03 +0200 Subject: [PATCH] installer: forbid keys with same master fg in same path --- gui/Cargo.lock | 2 +- gui/src/installer/step/descriptor.rs | 36 ++++++++++++++++++++++++++-- gui/src/installer/view.rs | 10 +++++++- 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/gui/Cargo.lock b/gui/Cargo.lock index ad984f3c..118698a5 100644 --- a/gui/Cargo.lock +++ b/gui/Cargo.lock @@ -2113,7 +2113,7 @@ dependencies = [ [[package]] name = "liana" version = "2.0.0" -source = "git+https://github.com/wizardsardine/liana?branch=master#605a13d4bab662f832b8fcb0d915eb17d0360c1f" +source = "git+https://github.com/wizardsardine/liana?branch=master#4f2ff1abc0e2700d563f3077eb71c22ef9573e5c" dependencies = [ "backtrace", "bip39", diff --git a/gui/src/installer/step/descriptor.rs b/gui/src/installer/step/descriptor.rs index a23217f8..600e1dc8 100644 --- a/gui/src/installer/step/descriptor.rs +++ b/gui/src/installer/step/descriptor.rs @@ -1,4 +1,5 @@ use std::collections::{BTreeMap, HashMap, HashSet}; +use std::iter::FromIterator; use std::path::PathBuf; use std::str::FromStr; use std::sync::{Arc, Mutex}; @@ -256,7 +257,15 @@ impl Step for DefineDescriptor { self.setup_mut().check_for_duplicate(); } message::DefineKey::Edit => { + let setup = self.setup_mut(); let modal = EditXpubModal::new( + HashSet::from_iter(setup.spending_keys.iter().filter_map(|key| { + if key.is_some() && key != &setup.spending_keys[i] { + *key + } else { + None + } + })), self.setup_mut().spending_keys[i], None, i, @@ -338,8 +347,18 @@ impl Step for DefineDescriptor { self.setup_mut().check_for_duplicate(); } message::DefineKey::Edit => { + let setup = self.setup_mut(); let modal = EditXpubModal::new( - self.setup[&self.network].recovery_paths[i].keys[j], + HashSet::from_iter(setup.recovery_paths[i].keys.iter().filter_map( + |key| { + if key.is_some() && key != &setup.recovery_paths[i].keys[j] { + *key + } else { + None + } + }, + )), + setup.recovery_paths[i].keys[j], Some(i), j, self.network, @@ -658,6 +677,9 @@ pub struct EditXpubModal { form_xpub: form::Value, edit_name: bool, + other_path_keys: HashSet, + duplicate_master_fg: bool, + keys: Vec, hws: Vec, hot_signer: Arc>, @@ -668,6 +690,7 @@ pub struct EditXpubModal { impl EditXpubModal { #[allow(clippy::too_many_arguments)] fn new( + other_path_keys: HashSet, key: Option, path_index: Option, key_index: usize, @@ -677,6 +700,7 @@ impl EditXpubModal { ) -> Self { let hot_signer_fingerprint = hot_signer.lock().unwrap().fingerprint(); Self { + other_path_keys, form_name: form::Value { valid: true, value: key @@ -712,6 +736,7 @@ impl EditXpubModal { chosen_signer: key.map(|k| (k, None)), hot_signer_fingerprint, hot_signer, + duplicate_master_fg: false, } } fn load(&self) -> Command { @@ -728,6 +753,10 @@ impl DescriptorEditModal for EditXpubModal { } fn update(&mut self, message: Message) -> Command { + // Reset these fields. + // the fonction will setup them again if something is wrong + self.duplicate_master_fg = false; + self.error = None; match message { Message::Select(i) => { if let Some(HardwareWallet::Supported { @@ -862,7 +891,9 @@ impl DescriptorEditModal for EditXpubModal { let key_index = self.key_index; let name = self.form_name.value.clone(); let device_kind = self.chosen_signer.and_then(|(_, kind)| kind); - if let Some(path_index) = self.path_index { + if self.other_path_keys.contains(&key.master_fingerprint()) { + self.duplicate_master_fg = true; + } else if let Some(path_index) = self.path_index { return Command::perform( async move { (path_index, key_index, key) }, move |(path_index, key_index, key)| { @@ -964,6 +995,7 @@ impl DescriptorEditModal for EditXpubModal { &self.form_xpub, &self.form_name, self.edit_name, + self.duplicate_master_fg, ) } } diff --git a/gui/src/installer/view.rs b/gui/src/installer/view.rs index d04709df..35bdd518 100644 --- a/gui/src/installer/view.rs +++ b/gui/src/installer/view.rs @@ -1295,6 +1295,7 @@ pub fn edit_key_modal<'a>( form_xpub: &form::Value, form_name: &'a form::Value, edit_name: bool, + duplicate_master_fg: bool, ) -> Element<'a, Message> { Column::new() .push_maybe(error.map(|e| card::error("Failed to import xpub", e.to_string()))) @@ -1411,8 +1412,15 @@ pub fn edit_key_modal<'a>( Column::new() }, ) + .push_maybe( + if duplicate_master_fg { + Some(text("A single signing device may not be used more than once per path. (It can still be used in other paths.)").style(color::RED)) + } else { + None + } + ) .push( - if form_xpub.valid && !form_xpub.value.is_empty() && !form_name.value.is_empty() + if form_xpub.valid && !form_xpub.value.is_empty() && !form_name.value.is_empty() && !duplicate_master_fg { button::primary(None, "Apply") .on_press(Message::DefineDescriptor(