Merge #848: Grey out harware wallets when unrelated or do not support method

3372e2f1e0be711dac71becf57541e48309e93e4 gui: grey out hws with addr verif unimplemented (edouardparis)
0ef49ed3f716e57f4bcd9a3f95d9c48dbce488d3 gui: grey out unrelated hws (edouardparis)

Pull request description:

  close #830

ACKs for top commit:
  jp1ac4:
    ACK 3372e2f1e0.

Tree-SHA512: 8c8cf17b05d3920dfd32e558c3ee27b94c4b9f65e931734cfc62cb8479e986d60882796bbc48b0c5f0061cda689a3b837b6d6bb159738139fa7f30684fa956a2
This commit is contained in:
Antoine Poinsot 2023-12-07 14:54:06 +01:00
commit 6151c57af4
No known key found for this signature in database
GPG Key ID: E13FC145CD3F4304
3 changed files with 202 additions and 33 deletions

View File

@ -2,7 +2,11 @@ use iced::Length;
use liana_ui::{component::hw, theme, widget::*};
use crate::{app::view::message::*, hw::HardwareWallet};
use crate::{
app::view::message::*,
hw::{HardwareWallet, UnsupportedReason},
};
use async_hwi::DeviceKind;
pub fn hw_list_view(
i: usize,
@ -40,9 +44,17 @@ pub fn hw_list_view(
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
}
}
HardwareWallet::Unsupported { version, kind, .. } => {
hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref())
}
HardwareWallet::Unsupported {
version,
kind,
reason,
..
} => match reason {
UnsupportedReason::NotPartOfWallet(fg) => {
hw::unrelated_hardware_wallet(&kind.to_string(), version.as_ref(), fg)
}
_ => hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref()),
},
HardwareWallet::Locked {
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
@ -90,9 +102,17 @@ pub fn hw_list_view_for_registration(
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
}
}
HardwareWallet::Unsupported { version, kind, .. } => {
hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref())
}
HardwareWallet::Unsupported {
version,
kind,
reason,
..
} => match reason {
UnsupportedReason::NotPartOfWallet(fg) => {
hw::unrelated_hardware_wallet(&kind.to_string(), version.as_ref(), fg)
}
_ => hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref()),
},
HardwareWallet::Locked {
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
@ -113,7 +133,7 @@ pub fn hw_list_view_verify_address(
hw: &HardwareWallet,
chosen: bool,
) -> Element<Message> {
let mut bttn = Button::new(match hw {
let (content, selectable) = match hw {
HardwareWallet::Supported {
kind,
version,
@ -122,21 +142,59 @@ pub fn hw_list_view_verify_address(
..
} => {
if chosen {
hw::processing_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
(
hw::processing_hardware_wallet(
kind,
version.as_ref(),
fingerprint,
alias.as_ref(),
),
false,
)
} else {
hw::supported_hardware_wallet(kind, version.as_ref(), fingerprint, alias.as_ref())
match kind {
DeviceKind::Specter | DeviceKind::SpecterSimulator => {
(hw::unimplemented_method_hardware_wallet(
&kind.to_string(),
version.as_ref(),
fingerprint,
"Liana cannot request the device to display the address. \n The verification must be done manually with the device control."
), false)
}
_ => (hw::supported_hardware_wallet(
kind,
version.as_ref(),
fingerprint,
alias.as_ref(),
), true),
}
}
}
HardwareWallet::Unsupported { version, kind, .. } => {
hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref())
}
HardwareWallet::Unsupported {
version,
kind,
reason,
..
} => (
match reason {
UnsupportedReason::NotPartOfWallet(fg) => {
hw::unrelated_hardware_wallet(&kind.to_string(), version.as_ref(), fg)
}
_ => hw::unsupported_hardware_wallet(&kind.to_string(), version.as_ref()),
},
false,
),
HardwareWallet::Locked {
kind, pairing_code, ..
} => hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
})
.style(theme::Button::Border)
.width(Length::Fill);
if !chosen && hw.is_supported() {
} => (
hw::locked_hardware_wallet(kind, pairing_code.as_ref()),
false,
),
};
let mut bttn = Button::new(content)
.style(theme::Button::Border)
.width(Length::Fill);
if selectable && hw.is_supported() {
bttn = bttn.on_press(Message::SelectHardwareWallet(i));
}
Container::new(bttn)

View File

@ -14,6 +14,15 @@ use liana::miniscript::bitcoin::{bip32::Fingerprint, hashes::hex::FromHex, Netwo
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};
#[derive(Debug, Clone)]
pub enum UnsupportedReason {
Version {
minimal_supported_version: &'static str,
},
Method(&'static str),
NotPartOfWallet(Fingerprint),
}
// Todo drop the Clone, to remove the Mutex on HardwareWallet::Locked
#[derive(Debug, Clone)]
pub enum HardwareWallet {
@ -21,7 +30,7 @@ pub enum HardwareWallet {
id: String,
kind: DeviceKind,
version: Option<Version>,
message: String,
reason: UnsupportedReason,
},
Locked {
id: String,
@ -225,21 +234,35 @@ impl HardwareWallets {
BitBox02::from(paired_bb).with_network(network);
let fingerprint = bitbox2.get_master_fingerprint().await?;
let mut registered = false;
if let Some(wallet) = wallet {
if let Some(wallet) = &wallet {
let desc = wallet.main_descriptor.to_string();
bitbox2 = bitbox2.with_policy(&desc)?;
registered =
bitbox2.is_policy_registered(&desc).await?;
}
Ok(HardwareWallet::Supported {
id: id.clone(),
kind: DeviceKind::BitBox02,
fingerprint,
device: bitbox2.into(),
version: None,
registered: Some(registered),
alias: None,
})
if wallet
.map(|w| w.descriptor_keys().contains(&fingerprint))
== Some(true)
{
Ok(HardwareWallet::Supported {
id: id.clone(),
kind: DeviceKind::BitBox02,
fingerprint,
device: bitbox2.into(),
version: None,
registered: Some(registered),
alias: None,
})
} else {
Ok(HardwareWallet::Unsupported {
id: id.clone(),
kind: DeviceKind::BitBox02,
version: None,
reason: UnsupportedReason::NotPartOfWallet(
fingerprint,
),
})
}
},
|res| HardwareWalletMessage::Unlocked(id_cloned, res),
));
@ -417,7 +440,9 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) {
id,
kind: device.device_kind(),
version,
message: "Minimal supported app version is 2.1.0".to_string(),
reason: UnsupportedReason::Version {
minimal_supported_version: "2.1.0",
},
});
}
}
@ -426,7 +451,9 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) {
id,
kind: device.device_kind(),
version: None,
message: "Minimal supported app version is 2.1.0".to_string(),
reason: UnsupportedReason::Version {
minimal_supported_version: "2.1.0",
},
});
}
}
@ -516,7 +543,9 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) {
id,
kind: device.device_kind(),
version,
message: "Minimal supported app version is 2.1.0".to_string(),
reason: UnsupportedReason::Version {
minimal_supported_version: "2.1.0",
},
});
}
}
@ -525,7 +554,9 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) {
id,
kind: device.device_kind(),
version: None,
message: "Minimal supported app version is 2.1.0".to_string(),
reason: UnsupportedReason::Version {
minimal_supported_version: "2.1.0",
},
});
}
},
@ -536,6 +567,29 @@ async fn refresh(mut state: State) -> (HardwareWalletMessage, State) {
}
}
if let Some(wallet) = &state.wallet {
let wallet_keys = wallet.descriptor_keys();
for hw in &mut hws {
if let HardwareWallet::Supported {
fingerprint,
id,
kind,
version,
..
} = &hw
{
if !wallet_keys.contains(fingerprint) {
*hw = HardwareWallet::Unsupported {
id: id.clone(),
kind: *kind,
version: version.clone(),
reason: UnsupportedReason::NotPartOfWallet(*fingerprint),
};
}
}
}
}
state.connected_supported_hws = still
.iter()
.chain(hws.iter().filter_map(|hw| match hw {

View File

@ -87,6 +87,63 @@ pub fn unregistered_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Displa
.padding(10)
}
pub fn unimplemented_method_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,
fingerprint: F,
message: &'static str,
) -> Container<'a, T> {
container(
tooltip::Tooltip::new(
container(
column(vec![
text::p1_regular(format!("#{}", fingerprint)).into(),
Row::new()
.spacing(5)
.push(text::caption(kind.to_string()))
.push_maybe(version.map(|v| text::caption(v.to_string())))
.into(),
])
.width(Length::Fill),
)
.width(Length::Fill)
.padding(10),
message,
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
)
.width(Length::Fill)
}
pub fn unrelated_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,
fingerprint: F,
) -> Container<'a, T> {
container(
tooltip::Tooltip::new(
container(
column(vec![
text::p1_regular(format!("#{}", fingerprint)).into(),
Row::new()
.spacing(5)
.push(text::caption(kind.to_string()))
.push_maybe(version.map(|v| text::caption(v.to_string())))
.into(),
])
.width(Length::Fill),
)
.width(Length::Fill)
.padding(10),
"This signer does not have a key in this wallet.",
tooltip::Position::Bottom,
)
.style(theme::Container::Card(theme::Card::Simple)),
)
.width(Length::Fill)
}
pub fn processing_hardware_wallet<'a, T: 'a, K: Display, V: Display, F: Display>(
kind: K,
version: Option<V>,