installer: register wallet
This commit is contained in:
parent
a2021ca326
commit
c2ed30961c
6
gui/Cargo.lock
generated
6
gui/Cargo.lock
generated
@ -125,7 +125,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "async-hwi"
|
||||
version = "0.0.1"
|
||||
source = "git+https://github.com/revault/async-hwi?branch=add-ledger#0eace00eca1ece4e4c49f2cd4d6fbffa2d527ce5"
|
||||
source = "git+https://github.com/revault/async-hwi?branch=add-ledger#de5615ba2e2e2d3ded6a058f0193f8787d3873dc"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"base64",
|
||||
@ -1380,7 +1380,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "ledger_bitcoin_client"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/edouardparis/app-bitcoin-new/?branch=bitcoin_client_rs#4f7951ce7c464db80f241ca8cd46c45770d6eec7"
|
||||
source = "git+https://github.com/edouardparis/app-bitcoin-new/?branch=bitcoin_client_rs#95ec68b546d49a77eee274880d2450fdb08f840c"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"bitcoin",
|
||||
@ -2725,7 +2725,7 @@ version = "1.6.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675"
|
||||
dependencies = [
|
||||
"cfg-if 1.0.0",
|
||||
"cfg-if 0.1.10",
|
||||
"rand 0.8.5",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use minisafe::miniscript::bitcoin;
|
||||
use minisafe::miniscript::bitcoin::{util::bip32::Fingerprint, Network};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use super::Error;
|
||||
@ -15,10 +15,11 @@ pub enum Message {
|
||||
Reload,
|
||||
Select(usize),
|
||||
Installed(Result<PathBuf, Error>),
|
||||
Network(bitcoin::Network),
|
||||
Network(Network),
|
||||
DefineBitcoind(DefineBitcoind),
|
||||
DefineDescriptor(DefineDescriptor),
|
||||
ConnectedHardwareWallets(Vec<HardwareWallet>),
|
||||
WalletRegistered(Result<(Fingerprint, Option<[u8; 32]>), Error>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
@ -15,7 +15,7 @@ use std::path::PathBuf;
|
||||
use crate::{app::config as gui_config, installer::config::DEFAULT_FILE_NAME};
|
||||
|
||||
pub use message::Message;
|
||||
use step::{Context, DefineBitcoind, DefineDescriptor, Final, Step, Welcome};
|
||||
use step::{Context, DefineBitcoind, DefineDescriptor, Final, RegisterDescriptor, Step, Welcome};
|
||||
|
||||
pub struct Installer {
|
||||
should_exit: bool,
|
||||
@ -50,6 +50,7 @@ impl Installer {
|
||||
steps: vec![
|
||||
Welcome::new(network).into(),
|
||||
DefineDescriptor::new().into(),
|
||||
RegisterDescriptor::default().into(),
|
||||
DefineBitcoind::new().into(),
|
||||
Final::new().into(),
|
||||
],
|
||||
@ -95,6 +96,7 @@ impl Installer {
|
||||
.get_mut(self.current)
|
||||
.expect("There is always a step");
|
||||
current_step.load_context(&self.context);
|
||||
return current_step.load();
|
||||
}
|
||||
Command::none()
|
||||
}
|
||||
|
||||
@ -283,3 +283,103 @@ async fn get_extended_pubkey(
|
||||
wildcard: Wildcard::Unhardened,
|
||||
}))
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct RegisterDescriptor {
|
||||
descriptor: Option<InheritanceDescriptor>,
|
||||
processing: bool,
|
||||
chosen_hw: Option<usize>,
|
||||
hws: Vec<(HardwareWallet, Option<[u8; 32]>)>,
|
||||
error: Option<Error>,
|
||||
}
|
||||
|
||||
impl Step for RegisterDescriptor {
|
||||
fn load_context(&mut self, ctx: &Context) {
|
||||
self.descriptor = ctx.descriptor.clone();
|
||||
}
|
||||
fn update(&mut self, message: Message) -> Command<Message> {
|
||||
match message {
|
||||
Message::Select(i) => {
|
||||
if let Some((hw, hmac)) = self.hws.get(i) {
|
||||
if hmac.is_none() {
|
||||
let device = hw.device.clone();
|
||||
let descriptor = self.descriptor.as_ref().unwrap().to_string();
|
||||
self.chosen_hw = Some(i);
|
||||
self.processing = true;
|
||||
self.error = None;
|
||||
return Command::perform(
|
||||
register_wallet(device, hw.fingerprint, descriptor),
|
||||
Message::WalletRegistered,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::WalletRegistered(res) => {
|
||||
self.processing = false;
|
||||
self.chosen_hw = None;
|
||||
match res {
|
||||
Ok((fingerprint, hmac)) => {
|
||||
if let Some(hw_h) = self
|
||||
.hws
|
||||
.iter_mut()
|
||||
.find(|hw_h| hw_h.0.fingerprint == fingerprint)
|
||||
{
|
||||
hw_h.1 = Some(hmac.unwrap_or([0x00; 32]));
|
||||
}
|
||||
}
|
||||
Err(e) => self.error = Some(e),
|
||||
}
|
||||
}
|
||||
Message::ConnectedHardwareWallets(hws) => {
|
||||
for hw in hws {
|
||||
if !self
|
||||
.hws
|
||||
.iter()
|
||||
.any(|(h, _)| h.fingerprint == hw.fingerprint)
|
||||
{
|
||||
self.hws.push((hw, None));
|
||||
}
|
||||
}
|
||||
}
|
||||
Message::Reload => {
|
||||
return self.load();
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Command::none()
|
||||
}
|
||||
fn apply(&mut self, ctx: &mut Context) -> bool {
|
||||
true
|
||||
}
|
||||
fn load(&self) -> Command<Message> {
|
||||
Command::perform(list_hardware_wallets(), Message::ConnectedHardwareWallets)
|
||||
}
|
||||
fn view(&self) -> Element<Message> {
|
||||
let desc = self.descriptor.as_ref().unwrap();
|
||||
view::register_descriptor(
|
||||
&desc.to_string(),
|
||||
&self.hws,
|
||||
self.error.as_ref(),
|
||||
self.processing,
|
||||
self.chosen_hw,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
async fn register_wallet(
|
||||
hw: std::sync::Arc<dyn async_hwi::HWI + Send + Sync>,
|
||||
fingerprint: Fingerprint,
|
||||
descriptor: String,
|
||||
) -> Result<(Fingerprint, Option<[u8; 32]>), Error> {
|
||||
let hmac = hw
|
||||
.register_wallet("Minisafe", &descriptor)
|
||||
.await
|
||||
.map_err(Error::from)?;
|
||||
Ok((fingerprint, hmac))
|
||||
}
|
||||
|
||||
impl From<RegisterDescriptor> for Box<dyn Step> {
|
||||
fn from(s: RegisterDescriptor) -> Box<dyn Step> {
|
||||
Box::new(s)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
mod descriptor;
|
||||
pub use descriptor::DefineDescriptor;
|
||||
pub use descriptor::{DefineDescriptor, RegisterDescriptor};
|
||||
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
@ -25,6 +25,9 @@ pub trait Step {
|
||||
}
|
||||
fn view(&self) -> Element<Message>;
|
||||
fn load_context(&mut self, _ctx: &Context) {}
|
||||
fn load(&self) -> Command<Message> {
|
||||
Command::none()
|
||||
}
|
||||
fn skip(&self, _ctx: &Context) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
@ -159,6 +159,59 @@ pub fn define_descriptor<'a>(
|
||||
)
|
||||
}
|
||||
|
||||
pub fn register_descriptor<'a>(
|
||||
descriptor: &str,
|
||||
hws: &[(HardwareWallet, Option<[u8; 32]>)],
|
||||
error: Option<&Error>,
|
||||
processing: bool,
|
||||
chosen_hw: Option<usize>,
|
||||
) -> Element<'a, Message> {
|
||||
layout(
|
||||
column()
|
||||
.push(text("Register descriptor").bold().size(50))
|
||||
.push(text(descriptor).small())
|
||||
.push_maybe(error.map(|e| card::error("Failed to import xpub", &e.to_string())))
|
||||
.push(if !hws.is_empty() {
|
||||
column()
|
||||
.push(text(&format!("{} hardware wallets connected", hws.len())).bold())
|
||||
.spacing(10)
|
||||
.push(
|
||||
hws.iter()
|
||||
.enumerate()
|
||||
.fold(column().spacing(10), |col, (i, hw)| {
|
||||
col.push(hw_list_view(
|
||||
i,
|
||||
&hw.0,
|
||||
Some(i) == chosen_hw,
|
||||
processing,
|
||||
hw.1.is_some(),
|
||||
))
|
||||
}),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
} else {
|
||||
column().push(card::simple(
|
||||
column()
|
||||
.spacing(20)
|
||||
.push("No hardware wallet connected")
|
||||
.push(button::primary(None, "Refresh").on_press(Message::Reload))
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::Fill),
|
||||
))
|
||||
})
|
||||
.push(
|
||||
button::primary(None, "Next")
|
||||
.on_press(Message::Next)
|
||||
.width(Length::Units(200)),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
.padding(100)
|
||||
.spacing(50)
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn define_bitcoin<'a>(
|
||||
address: &form::Value<String>,
|
||||
cookie_path: &form::Value<String>,
|
||||
@ -282,18 +335,30 @@ pub fn hardware_wallet_xpubs_modal<'a>(
|
||||
hws.iter()
|
||||
.enumerate()
|
||||
.fold(column().spacing(10), |col, (i, hw)| {
|
||||
col.push(hw_list_view(i, hw, Some(i) == chosen_hw, processing))
|
||||
col.push(hw_list_view(
|
||||
i,
|
||||
hw,
|
||||
Some(i) == chosen_hw,
|
||||
processing,
|
||||
false,
|
||||
))
|
||||
}),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
} else {
|
||||
column().push(card::simple(
|
||||
column()
|
||||
.spacing(10)
|
||||
.push("Please connect a hardware wallet")
|
||||
.push(button::primary(None, "Refresh").on_press(Message::Reload))
|
||||
.align_items(Alignment::Center),
|
||||
))
|
||||
column()
|
||||
.push(
|
||||
card::simple(
|
||||
column()
|
||||
.spacing(20)
|
||||
.width(Length::Fill)
|
||||
.push("Please connect a hardware wallet")
|
||||
.push(button::primary(None, "Refresh").on_press(Message::Reload))
|
||||
.align_items(Alignment::Center),
|
||||
)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.width(Length::Fill)
|
||||
})
|
||||
.width(Length::Fill)
|
||||
.height(Length::Fill)
|
||||
@ -308,6 +373,7 @@ fn hw_list_view<'a>(
|
||||
hw: &HardwareWallet,
|
||||
chosen: bool,
|
||||
processing: bool,
|
||||
registered: bool,
|
||||
) -> Element<'a, Message> {
|
||||
let mut bttn = iced::pure::button(
|
||||
row()
|
||||
@ -327,6 +393,12 @@ fn hw_list_view<'a>(
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.push_maybe(if registered {
|
||||
Some(column().push(icon::circle_check_icon().color(color::SUCCESS)))
|
||||
} else {
|
||||
None
|
||||
})
|
||||
.align_items(Alignment::Center)
|
||||
.width(Length::Fill),
|
||||
)
|
||||
.padding(10)
|
||||
@ -353,6 +425,7 @@ fn layout<'a>(content: impl Into<Element<'a, Message>>) -> Element<'a, Message>
|
||||
.center_x()
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.style(BackgroundStyle)
|
||||
.into()
|
||||
}
|
||||
|
||||
@ -372,12 +445,12 @@ fn modal<'a>(content: impl Into<Element<'a, Message>>) -> Element<'a, Message> {
|
||||
.center_x()
|
||||
.height(Length::Fill)
|
||||
.width(Length::Fill)
|
||||
.style(ModalStyle)
|
||||
.style(BackgroundStyle)
|
||||
.into()
|
||||
}
|
||||
|
||||
pub struct ModalStyle;
|
||||
impl widget::container::StyleSheet for ModalStyle {
|
||||
pub struct BackgroundStyle;
|
||||
impl widget::container::StyleSheet for BackgroundStyle {
|
||||
fn style(&self) -> widget::container::Style {
|
||||
widget::container::Style {
|
||||
background: color::BACKGROUND.into(),
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user