gui: support user/password RPC authentication
This change updates the GUI to support the latest lianad config file with the user/password option for bitcoind RPC authentication. The settings have been updated to set either cookie file path or user and password. The installer still only supports the cookie file and has only been updated with the changes required to compile. When starting, the internal bitcoind now looks for the cookie file in the usual location rather than relying on the config file.
This commit is contained in:
parent
b8f8d1b944
commit
3ccdafbda2
2
gui/Cargo.lock
generated
2
gui/Cargo.lock
generated
@ -2431,7 +2431,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "liana"
|
||||
version = "4.0.0"
|
||||
source = "git+https://github.com/wizardsardine/liana?branch=master#dee069e72343a67607f4429125e4c80dc0d73055"
|
||||
source = "git+https://github.com/wizardsardine/liana?branch=master#b8f8d1b944120879986a71255bab19e5b342ecc8"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bdk_coin_select",
|
||||
|
||||
@ -8,12 +8,13 @@ use chrono::prelude::*;
|
||||
use iced::Command;
|
||||
use tracing::info;
|
||||
|
||||
use liana::config::{BitcoinConfig, BitcoindConfig, Config};
|
||||
use liana::config::{BitcoinConfig, BitcoindConfig, BitcoindRpcAuth, Config};
|
||||
|
||||
use liana_ui::{component::form, widget::Element};
|
||||
|
||||
use crate::{
|
||||
app::{cache::Cache, error::Error, message::Message, state::settings::Setting, view, State},
|
||||
bitcoind::{RpcAuthType, RpcAuthValues},
|
||||
daemon::Daemon,
|
||||
};
|
||||
|
||||
@ -140,7 +141,8 @@ pub struct BitcoindSettings {
|
||||
bitcoin_config: BitcoinConfig,
|
||||
edit: bool,
|
||||
processing: bool,
|
||||
cookie_path: form::Value<String>,
|
||||
rpc_auth_vals: RpcAuthValues,
|
||||
selected_auth_type: RpcAuthType,
|
||||
addr: form::Value<String>,
|
||||
daemon_is_external: bool,
|
||||
bitcoind_is_internal: bool,
|
||||
@ -159,7 +161,33 @@ impl BitcoindSettings {
|
||||
daemon_is_external: bool,
|
||||
bitcoind_is_internal: bool,
|
||||
) -> BitcoindSettings {
|
||||
let path = bitcoind_config.cookie_path.to_str().unwrap().to_string();
|
||||
let (rpc_auth_vals, selected_auth_type) = match &bitcoind_config.rpc_auth {
|
||||
BitcoindRpcAuth::CookieFile(path) => (
|
||||
RpcAuthValues {
|
||||
cookie_path: form::Value {
|
||||
valid: true,
|
||||
value: path.to_str().unwrap().to_string(),
|
||||
},
|
||||
user: form::Value::default(),
|
||||
password: form::Value::default(),
|
||||
},
|
||||
RpcAuthType::CookieFile,
|
||||
),
|
||||
BitcoindRpcAuth::UserPass(user, password) => (
|
||||
RpcAuthValues {
|
||||
cookie_path: form::Value::default(),
|
||||
user: form::Value {
|
||||
valid: true,
|
||||
value: user.clone(),
|
||||
},
|
||||
password: form::Value {
|
||||
valid: true,
|
||||
value: password.clone(),
|
||||
},
|
||||
},
|
||||
RpcAuthType::UserPass,
|
||||
),
|
||||
};
|
||||
let addr = bitcoind_config.addr.to_string();
|
||||
BitcoindSettings {
|
||||
daemon_is_external,
|
||||
@ -168,10 +196,8 @@ impl BitcoindSettings {
|
||||
bitcoin_config,
|
||||
edit: false,
|
||||
processing: false,
|
||||
cookie_path: form::Value {
|
||||
valid: true,
|
||||
value: path,
|
||||
},
|
||||
rpc_auth_vals,
|
||||
selected_auth_type,
|
||||
addr: form::Value {
|
||||
valid: true,
|
||||
value: addr,
|
||||
@ -209,21 +235,41 @@ impl Setting for BitcoindSettings {
|
||||
if !self.processing {
|
||||
match field {
|
||||
"socket_address" => self.addr.value = value,
|
||||
"cookie_file_path" => self.cookie_path.value = value,
|
||||
"cookie_file_path" => self.rpc_auth_vals.cookie_path.value = value,
|
||||
"user" => self.rpc_auth_vals.user.value = value,
|
||||
"password" => self.rpc_auth_vals.password.value = value,
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
view::SettingsEditMessage::BitcoindRpcAuthTypeSelected(auth_type) => {
|
||||
if !self.processing {
|
||||
self.selected_auth_type = auth_type;
|
||||
}
|
||||
}
|
||||
view::SettingsEditMessage::Confirm => {
|
||||
let new_addr = SocketAddr::from_str(&self.addr.value);
|
||||
self.addr.valid = new_addr.is_ok();
|
||||
let new_path = PathBuf::from_str(&self.cookie_path.value);
|
||||
self.cookie_path.valid = new_path.is_ok();
|
||||
let rpc_auth = match self.selected_auth_type {
|
||||
RpcAuthType::CookieFile => {
|
||||
let new_path = PathBuf::from_str(&self.rpc_auth_vals.cookie_path.value);
|
||||
if let Ok(path) = new_path {
|
||||
self.rpc_auth_vals.cookie_path.valid = true;
|
||||
Some(BitcoindRpcAuth::CookieFile(path))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
RpcAuthType::UserPass => Some(BitcoindRpcAuth::UserPass(
|
||||
self.rpc_auth_vals.user.value.clone(),
|
||||
self.rpc_auth_vals.password.value.clone(),
|
||||
)),
|
||||
};
|
||||
|
||||
if self.addr.valid & self.cookie_path.valid {
|
||||
if let (true, Some(rpc_auth)) = (self.addr.valid, rpc_auth) {
|
||||
let mut daemon_config = daemon.config().cloned().unwrap();
|
||||
daemon_config.bitcoind_config = Some(liana::config::BitcoindConfig {
|
||||
cookie_path: new_path.unwrap(),
|
||||
rpc_auth,
|
||||
addr: new_addr.unwrap(),
|
||||
});
|
||||
self.processing = true;
|
||||
@ -242,7 +288,8 @@ impl Setting for BitcoindSettings {
|
||||
self.bitcoin_config.network,
|
||||
cache.blockheight,
|
||||
&self.addr,
|
||||
&self.cookie_path,
|
||||
&self.rpc_auth_vals,
|
||||
&self.selected_auth_type,
|
||||
self.processing,
|
||||
)
|
||||
} else {
|
||||
@ -342,6 +389,7 @@ impl Setting for RescanSetting {
|
||||
Message::StartRescan,
|
||||
);
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
Command::none()
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use crate::app::menu::Menu;
|
||||
use crate::{app::menu::Menu, bitcoind::RpcAuthType};
|
||||
use liana::miniscript::bitcoin::bip32::Fingerprint;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@ -75,6 +75,7 @@ pub enum SettingsMessage {
|
||||
pub enum SettingsEditMessage {
|
||||
Select,
|
||||
FieldEdited(&'static str, String),
|
||||
BitcoindRpcAuthTypeSelected(RpcAuthType),
|
||||
Cancel,
|
||||
Confirm,
|
||||
}
|
||||
|
||||
@ -3,11 +3,14 @@ use std::str::FromStr;
|
||||
|
||||
use iced::{
|
||||
alignment,
|
||||
widget::{scrollable, Space},
|
||||
widget::{radio, scrollable, Space},
|
||||
Alignment, Length,
|
||||
};
|
||||
|
||||
use liana::miniscript::bitcoin::{bip32::Fingerprint, Network};
|
||||
use liana::{
|
||||
config::BitcoindRpcAuth,
|
||||
miniscript::bitcoin::{bip32::Fingerprint, Network},
|
||||
};
|
||||
|
||||
use super::{dashboard, message::*};
|
||||
|
||||
@ -26,6 +29,7 @@ use crate::{
|
||||
menu::Menu,
|
||||
view::{hw, warning::warn},
|
||||
},
|
||||
bitcoind::{RpcAuthType, RpcAuthValues},
|
||||
hw::HardwareWallet,
|
||||
};
|
||||
|
||||
@ -208,7 +212,8 @@ pub fn bitcoind_edit<'a>(
|
||||
network: Network,
|
||||
blockheight: i32,
|
||||
addr: &form::Value<String>,
|
||||
cookie_path: &form::Value<String>,
|
||||
rpc_auth_vals: &RpcAuthValues,
|
||||
selected_auth_type: &RpcAuthType,
|
||||
processing: bool,
|
||||
) -> Element<'a, SettingsEditMessage> {
|
||||
let mut col = Column::new().spacing(20);
|
||||
@ -244,18 +249,60 @@ pub fn bitcoind_edit<'a>(
|
||||
|
||||
col = col
|
||||
.push(
|
||||
Column::new()
|
||||
.push(text("Cookie file path:").bold().small())
|
||||
[RpcAuthType::CookieFile, RpcAuthType::UserPass]
|
||||
.iter()
|
||||
.fold(
|
||||
Row::new()
|
||||
.push(text("RPC authentication:").small().bold())
|
||||
.spacing(10),
|
||||
|row, auth_type| {
|
||||
row.push(radio(
|
||||
format!("{}", auth_type),
|
||||
*auth_type,
|
||||
Some(*selected_auth_type),
|
||||
SettingsEditMessage::BitcoindRpcAuthTypeSelected,
|
||||
))
|
||||
.spacing(30)
|
||||
.align_items(Alignment::Center)
|
||||
},
|
||||
),
|
||||
)
|
||||
.push(match selected_auth_type {
|
||||
RpcAuthType::CookieFile => Column::new()
|
||||
.push(
|
||||
form::Form::new_trimmed("Cookie file path", cookie_path, |value| {
|
||||
SettingsEditMessage::FieldEdited("cookie_file_path", value)
|
||||
})
|
||||
form::Form::new_trimmed(
|
||||
"Cookie file path",
|
||||
&rpc_auth_vals.cookie_path,
|
||||
|value| SettingsEditMessage::FieldEdited("cookie_file_path", value),
|
||||
)
|
||||
.warning("Please enter a valid filesystem path")
|
||||
.size(20)
|
||||
.padding(5),
|
||||
)
|
||||
.spacing(5),
|
||||
)
|
||||
RpcAuthType::UserPass => Column::new()
|
||||
.push(
|
||||
Row::new()
|
||||
.push(
|
||||
form::Form::new_trimmed("User", &rpc_auth_vals.user, |value| {
|
||||
SettingsEditMessage::FieldEdited("user", value)
|
||||
})
|
||||
.warning("Please enter a valid user")
|
||||
.size(20)
|
||||
.padding(5),
|
||||
)
|
||||
.push(
|
||||
form::Form::new_trimmed("Password", &rpc_auth_vals.password, |value| {
|
||||
SettingsEditMessage::FieldEdited("password", value)
|
||||
})
|
||||
.warning("Please enter a valid password")
|
||||
.size(20)
|
||||
.padding(5),
|
||||
)
|
||||
.spacing(10),
|
||||
)
|
||||
.spacing(5),
|
||||
})
|
||||
.push(
|
||||
Column::new()
|
||||
.push(text("Socket address:").bold().small())
|
||||
@ -345,13 +392,17 @@ pub fn bitcoind<'a>(
|
||||
.push(separation().width(Length::Fill));
|
||||
}
|
||||
|
||||
let rows = vec![
|
||||
(
|
||||
"Cookie file path:",
|
||||
config.cookie_path.to_str().unwrap().to_string(),
|
||||
),
|
||||
("Socket address:", config.addr.to_string()),
|
||||
];
|
||||
let mut rows = vec![];
|
||||
match &config.rpc_auth {
|
||||
BitcoindRpcAuth::CookieFile(path) => {
|
||||
rows.push(("Cookie file path:", path.to_str().unwrap().to_string()));
|
||||
}
|
||||
BitcoindRpcAuth::UserPass(user, password) => {
|
||||
rows.push(("User:", user.clone()));
|
||||
rows.push(("Password:", password.clone()));
|
||||
}
|
||||
}
|
||||
rows.push(("Socket address:", config.addr.to_string()));
|
||||
|
||||
let mut col_fields = Column::new();
|
||||
for (k, v) in rows {
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
use liana::{
|
||||
config::BitcoindConfig,
|
||||
config::{BitcoindConfig, BitcoindRpcAuth},
|
||||
miniscript::bitcoin::{self, Network},
|
||||
};
|
||||
use liana_ui::component::form;
|
||||
use std::fmt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
use std::thread;
|
||||
@ -222,6 +224,7 @@ impl Bitcoind {
|
||||
// We've started bitcoind in the background, however it may fail to start for whatever
|
||||
// reason. And we need its JSONRPC interface to be available to continue. Thus wait for it
|
||||
// to have created the cookie file, regularly checking it did not fail to start.
|
||||
let cookie_path = internal_bitcoind_cookie_path(&bitcoind_datadir, network);
|
||||
loop {
|
||||
match process.try_wait() {
|
||||
Ok(None) => {}
|
||||
@ -229,11 +232,11 @@ impl Bitcoind {
|
||||
Ok(Some(status)) => {
|
||||
log::error!("Bitcoind exited with status '{}'", status);
|
||||
return Err(StartInternalBitcoindError::CookieFileNotFound(
|
||||
config.cookie_path.to_string_lossy().into_owned(),
|
||||
cookie_path.to_string_lossy().into_owned(),
|
||||
));
|
||||
}
|
||||
}
|
||||
if config.cookie_path.exists() {
|
||||
if cookie_path.exists() {
|
||||
log::info!("Bitcoind seems to have successfully started.");
|
||||
break;
|
||||
}
|
||||
@ -241,9 +244,10 @@ impl Bitcoind {
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
}
|
||||
|
||||
config.cookie_path = config.cookie_path.canonicalize().map_err(|e| {
|
||||
config.rpc_auth = BitcoindRpcAuth::CookieFile(cookie_path.canonicalize().map_err(|e| {
|
||||
StartInternalBitcoindError::CouldNotCanonicalizeCookiePath(e.to_string())
|
||||
})?;
|
||||
})?);
|
||||
|
||||
liana::BitcoinD::new(&config, "internal_bitcoind_start".to_string())
|
||||
.map_err(|e| StartInternalBitcoindError::BitcoinDError(e.to_string()))?;
|
||||
|
||||
@ -273,3 +277,25 @@ pub fn stop_bitcoind(config: &BitcoindConfig) -> bool {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum RpcAuthType {
|
||||
CookieFile,
|
||||
UserPass,
|
||||
}
|
||||
|
||||
impl fmt::Display for RpcAuthType {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
RpcAuthType::CookieFile => write!(f, "Cookie file path"),
|
||||
RpcAuthType::UserPass => write!(f, "User and password"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct RpcAuthValues {
|
||||
pub cookie_path: form::Value<String>,
|
||||
pub user: form::Value<String>,
|
||||
pub password: form::Value<String>,
|
||||
}
|
||||
|
||||
@ -554,7 +554,7 @@ impl Step for DefineBitcoind {
|
||||
}
|
||||
(Ok(path), Ok(addr)) => {
|
||||
ctx.bitcoind_config = Some(BitcoindConfig {
|
||||
cookie_path: path,
|
||||
rpc_auth: liana::config::BitcoindRpcAuth::CookieFile(path),
|
||||
addr,
|
||||
});
|
||||
true
|
||||
@ -803,7 +803,7 @@ impl Step for InternalBitcoindStep {
|
||||
match Bitcoind::start(
|
||||
&self.network,
|
||||
BitcoindConfig {
|
||||
cookie_path,
|
||||
rpc_auth: liana::config::BitcoindRpcAuth::CookieFile(cookie_path),
|
||||
addr: internal_bitcoind_address(rpc_port),
|
||||
},
|
||||
&self.liana_datadir,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user