Add liana-connect cache file
This commit is contained in:
parent
102a8d841d
commit
1746314e7d
16
Cargo.lock
generated
16
Cargo.lock
generated
@ -254,6 +254,21 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-fd-lock"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7569377d7062165f6f7834d9cb3051974a2d141433cc201c2f94c149e993cccf"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"cfg-if",
|
||||
"pin-project",
|
||||
"rustix",
|
||||
"thiserror 1.0.69",
|
||||
"tokio",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-fs"
|
||||
version = "2.1.2"
|
||||
@ -2993,6 +3008,7 @@ dependencies = [
|
||||
name = "liana-gui"
|
||||
version = "10.0.0"
|
||||
dependencies = [
|
||||
"async-fd-lock",
|
||||
"async-hwi",
|
||||
"async-trait",
|
||||
"backtrace",
|
||||
|
||||
@ -29,6 +29,7 @@ iced_runtime = "0.13.1"
|
||||
email_address = "0.2.7"
|
||||
|
||||
tokio = {version = "1.21.0", features = ["signal"]}
|
||||
async-fd-lock = "0.2.0"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
|
||||
|
||||
@ -66,7 +66,21 @@ impl Settings {
|
||||
pub struct AuthConfig {
|
||||
pub email: String,
|
||||
pub wallet_id: String,
|
||||
pub refresh_token: String,
|
||||
// legacy field, refresh_token is now stored in the connect cache file
|
||||
// Keep it in case, user want to open the wallet with a previous Liana-GUI version.
|
||||
// Field cannot be ignored as the settings file is override during settings update.
|
||||
// TODO: remove later after multiple versions.
|
||||
pub refresh_token: Option<String>,
|
||||
}
|
||||
|
||||
impl AuthConfig {
|
||||
pub fn new(email: String, wallet_id: String) -> Self {
|
||||
Self {
|
||||
email,
|
||||
wallet_id,
|
||||
refresh_token: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
@ -241,7 +255,6 @@ pub enum SettingsError {
|
||||
WritingFile(String),
|
||||
Unexpected(String),
|
||||
}
|
||||
|
||||
impl std::fmt::Display for SettingsError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@ -13,6 +13,7 @@ use liana_ui::{
|
||||
widget::{Column, Element},
|
||||
};
|
||||
use lianad::config::Config;
|
||||
use std::ops::Deref;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use std::io::Write;
|
||||
@ -37,6 +38,7 @@ use crate::{
|
||||
api::payload::{Provider, ProviderKey},
|
||||
BackendClient, BackendWalletClient,
|
||||
},
|
||||
cache::update_connect_cache,
|
||||
},
|
||||
},
|
||||
signer::Signer,
|
||||
@ -550,6 +552,22 @@ pub async fn create_remote_wallet(
|
||||
|
||||
info!("Settings file created");
|
||||
|
||||
let backend = remote_backend.inner_client();
|
||||
if let Err(e) = update_connect_cache(
|
||||
&network_datadir,
|
||||
backend.auth.read().await.deref(),
|
||||
backend.auth_client(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// this error is not critical, the liana-connect backend stored the wallet
|
||||
// and user can reauthenticate.
|
||||
tracing::error!("Failed to update Liana-Connect cache: {}", e);
|
||||
} else {
|
||||
info!("Liana-Connect cache updated");
|
||||
};
|
||||
|
||||
Ok(gui_config_path)
|
||||
}
|
||||
|
||||
@ -599,6 +617,22 @@ pub async fn import_remote_wallet(
|
||||
|
||||
info!("Gui configuration file created");
|
||||
|
||||
let backend = backend.inner_client();
|
||||
if let Err(e) = update_connect_cache(
|
||||
&network_datadir,
|
||||
backend.auth.read().await.deref(),
|
||||
backend.auth_client(),
|
||||
false,
|
||||
)
|
||||
.await
|
||||
{
|
||||
// this error is not critical, the liana-connect backend stored the wallet
|
||||
// and user can reauthenticate.
|
||||
tracing::error!("Failed to update Liana-Connect cache: {}", e);
|
||||
} else {
|
||||
info!("Liana-Connect cache updated");
|
||||
};
|
||||
|
||||
Ok(gui_config_path)
|
||||
}
|
||||
|
||||
@ -631,19 +665,16 @@ pub async fn extract_remote_gui_settings(ctx: &Context, backend: &BackendWalletC
|
||||
.expect("LianaDescriptor.to_string() always include the checksum")
|
||||
.to_string();
|
||||
|
||||
let auth = backend.inner_client().auth.read().await;
|
||||
|
||||
Settings {
|
||||
wallets: vec![WalletSetting {
|
||||
name: wallet_name(descriptor),
|
||||
descriptor_checksum,
|
||||
keys: Vec::new(),
|
||||
hardware_wallets: Vec::new(),
|
||||
remote_backend_auth: Some(AuthConfig {
|
||||
email: backend.user_email().to_string(),
|
||||
wallet_id: backend.wallet_id(),
|
||||
refresh_token: auth.refresh_token.clone(),
|
||||
}),
|
||||
remote_backend_auth: Some(AuthConfig::new(
|
||||
backend.user_email().to_string(),
|
||||
backend.wallet_id(),
|
||||
)),
|
||||
}],
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,6 @@ use reqwest::{Error, IntoUrl, Method, RequestBuilder, Response};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use crate::{
|
||||
app::settings::{AuthConfig, Settings},
|
||||
daemon::{model::*, Daemon, DaemonBackend, DaemonError},
|
||||
dir::LianaDirectory,
|
||||
hw::HardwareWalletConfig,
|
||||
@ -28,7 +27,10 @@ use crate::{
|
||||
|
||||
use self::api::{UTXOKind, DEFAULT_OUTPOINTS_LIMIT};
|
||||
|
||||
use super::auth::{self, AccessTokenResponse, AuthError};
|
||||
use super::{
|
||||
auth::{self, AccessTokenResponse, AuthError},
|
||||
cache::update_connect_cache,
|
||||
};
|
||||
|
||||
impl From<Error> for DaemonError {
|
||||
fn from(value: Error) -> Self {
|
||||
@ -101,6 +103,10 @@ impl BackendClient {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn auth_client(&self) -> &auth::AuthClient {
|
||||
&self.auth_client
|
||||
}
|
||||
|
||||
pub fn user_email(&self) -> &str {
|
||||
&self.auth_client.email
|
||||
}
|
||||
@ -532,45 +538,20 @@ impl Daemon for BackendWalletClient {
|
||||
return Ok(());
|
||||
}
|
||||
Ok(mut old) => {
|
||||
let new = self
|
||||
.inner
|
||||
.auth_client
|
||||
.refresh_token(&auth.refresh_token)
|
||||
.await?;
|
||||
|
||||
let network_dir = datadir.network_directory(network);
|
||||
let mut settings = Settings::from_file(&network_dir).map_err(|e| {
|
||||
DaemonError::Unexpected(format!(
|
||||
"Cannot access to settings.json file: {}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
|
||||
if let Some(wallet_settings) = settings.wallets.iter_mut().find(|w| {
|
||||
if let Some(auth) = &w.remote_backend_auth {
|
||||
auth.wallet_id == self.wallet_uuid
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
wallet_settings.remote_backend_auth = Some(AuthConfig {
|
||||
email: self.inner.auth_client.email.clone(),
|
||||
wallet_id: self.wallet_id(),
|
||||
refresh_token: new.refresh_token.clone(),
|
||||
});
|
||||
} else {
|
||||
tracing::info!("Wallet id was not found in the settings");
|
||||
}
|
||||
|
||||
settings.to_file(&network_dir).map_err(|e| {
|
||||
DaemonError::Unexpected(format!(
|
||||
"Cannot access to settings.json file: {}",
|
||||
e
|
||||
))
|
||||
let new = update_connect_cache(
|
||||
&network_dir,
|
||||
&old,
|
||||
&self.inner.auth_client,
|
||||
true, // refresh the token
|
||||
)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
DaemonError::Unexpected(format!("Cannot update Liana-connect cache: {}", e))
|
||||
})?;
|
||||
|
||||
*old = new;
|
||||
tracing::info!("Liana backend access was refreshed");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
159
liana-gui/src/services/connect/client/cache.rs
Normal file
159
liana-gui/src/services/connect/client/cache.rs
Normal file
@ -0,0 +1,159 @@
|
||||
use crate::dir::NetworkDirectory;
|
||||
use async_fd_lock::LockWrite;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::io::SeekFrom;
|
||||
use tokio::fs::OpenOptions;
|
||||
use tokio::io::AsyncSeekExt;
|
||||
use tokio::io::{AsyncReadExt, AsyncWriteExt};
|
||||
|
||||
use super::auth::{AccessTokenResponse, AuthClient, AuthError};
|
||||
|
||||
pub const CONNECT_CACHE_FILENAME: &str = "connect.json";
|
||||
|
||||
#[derive(Debug, Default, Clone, Deserialize, Serialize)]
|
||||
pub struct ConnectCache {
|
||||
pub accounts: Vec<Account>,
|
||||
}
|
||||
|
||||
impl ConnectCache {
|
||||
fn upsert_credential(&mut self, email: &str, tokens: AccessTokenResponse) {
|
||||
if let Some(c) = self.accounts.iter_mut().find(|c| c.email == email) {
|
||||
c.tokens = tokens;
|
||||
} else {
|
||||
self.accounts.push(Account {
|
||||
email: email.to_string(),
|
||||
tokens,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct Account {
|
||||
pub email: String,
|
||||
pub tokens: AccessTokenResponse,
|
||||
}
|
||||
|
||||
impl Account {
|
||||
pub fn from_cache(
|
||||
network_dir: &NetworkDirectory,
|
||||
email: &str,
|
||||
) -> Result<Option<Self>, ConnectCacheError> {
|
||||
let mut path = network_dir.path().to_path_buf();
|
||||
path.push(CONNECT_CACHE_FILENAME);
|
||||
|
||||
std::fs::read(path)
|
||||
.map_err(|e| match e.kind() {
|
||||
std::io::ErrorKind::NotFound => ConnectCacheError::NotFound,
|
||||
_ => ConnectCacheError::ReadingFile(format!("Reading settings file: {}", e)),
|
||||
})
|
||||
.and_then(|file_content| {
|
||||
serde_json::from_slice::<ConnectCache>(&file_content).map_err(|e| {
|
||||
ConnectCacheError::ReadingFile(format!("Parsing settings file: {}", e))
|
||||
})
|
||||
})
|
||||
.map(|cache| cache.accounts.into_iter().find(|c| c.email == email))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn update_connect_cache(
|
||||
network_dir: &NetworkDirectory,
|
||||
current_tokens: &AccessTokenResponse,
|
||||
client: &AuthClient,
|
||||
refresh: bool,
|
||||
) -> Result<AccessTokenResponse, ConnectCacheError> {
|
||||
let email = &client.email;
|
||||
let mut path = network_dir.path().to_path_buf();
|
||||
path.push(CONNECT_CACHE_FILENAME);
|
||||
|
||||
let file_exists = tokio::fs::try_exists(&path).await.unwrap_or(false);
|
||||
|
||||
let mut file = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.create(true)
|
||||
.truncate(false)
|
||||
.open(&path)
|
||||
.await
|
||||
.map_err(|e| ConnectCacheError::ReadingFile(format!("Opening file: {}", e)))?
|
||||
.lock_write()
|
||||
.await
|
||||
.map_err(|e| ConnectCacheError::ReadingFile(format!("Locking file: {:?}", e)))?;
|
||||
|
||||
let mut cache = if file_exists {
|
||||
let mut file_content = Vec::new();
|
||||
file.read_to_end(&mut file_content)
|
||||
.await
|
||||
.map_err(|e| ConnectCacheError::ReadingFile(format!("Reading file content: {}", e)))?;
|
||||
|
||||
match serde_json::from_slice::<ConnectCache>(&file_content) {
|
||||
Ok(cache) => cache,
|
||||
Err(e) => {
|
||||
tracing::warn!("Something wrong with Liana-Connect cache file: {:?}", e);
|
||||
tracing::warn!("Liana-Connect cache file is reset");
|
||||
ConnectCache::default()
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ConnectCache::default()
|
||||
};
|
||||
|
||||
if let Some(c) = cache.accounts.iter().find(|cred| cred.email == *email) {
|
||||
// An other process updated the tokens
|
||||
if current_tokens.expires_at < c.tokens.expires_at {
|
||||
tracing::debug!("Liana-Connect authentication tokens are up to date, nothing to do");
|
||||
return Ok(c.tokens.clone());
|
||||
}
|
||||
}
|
||||
|
||||
let tokens = if refresh {
|
||||
client
|
||||
.refresh_token(¤t_tokens.refresh_token)
|
||||
.await
|
||||
.map_err(ConnectCacheError::Updating)?
|
||||
} else {
|
||||
current_tokens.clone()
|
||||
};
|
||||
|
||||
cache.upsert_credential(email, tokens.clone());
|
||||
|
||||
let content = serde_json::to_vec_pretty(&cache).map_err(|e| {
|
||||
ConnectCacheError::WritingFile(format!("Failed to serialize settings: {}", e))
|
||||
})?;
|
||||
|
||||
file.seek(SeekFrom::Start(0)).await.map_err(|e| {
|
||||
ConnectCacheError::WritingFile(format!("Failed to seek to start of file: {}", e))
|
||||
})?;
|
||||
|
||||
file.write_all(&content).await.map_err(|e| {
|
||||
tracing::warn!("failed to write to file: {:?}", e);
|
||||
ConnectCacheError::WritingFile(e.to_string())
|
||||
})?;
|
||||
|
||||
file.inner_mut()
|
||||
.set_len(content.len() as u64)
|
||||
.await
|
||||
.map_err(|e| ConnectCacheError::WritingFile(format!("Failed to truncate file: {}", e)))?;
|
||||
|
||||
Ok(tokens)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ConnectCacheError {
|
||||
NotFound,
|
||||
ReadingFile(String),
|
||||
WritingFile(String),
|
||||
Unexpected(String),
|
||||
Updating(AuthError),
|
||||
}
|
||||
impl std::fmt::Display for ConnectCacheError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::NotFound => write!(f, "ConnectCache file not found"),
|
||||
Self::ReadingFile(e) => write!(f, "Error while reading file: {}", e),
|
||||
Self::WritingFile(e) => write!(f, "Error while writing file: {}", e),
|
||||
Self::Unexpected(e) => write!(f, "Unexpected error: {}", e),
|
||||
Self::Updating(e) => write!(f, "Error while updating cache file: {}", e),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,6 @@
|
||||
pub mod auth;
|
||||
pub mod backend;
|
||||
pub mod cache;
|
||||
|
||||
use liana::miniscript::bitcoin;
|
||||
|
||||
|
||||
@ -13,7 +13,7 @@ use lianad::commands::ListCoinsResult;
|
||||
use crate::{
|
||||
app::{
|
||||
cache::coins_to_cache,
|
||||
settings::{AuthConfig, Settings, SettingsError, WalletSetting},
|
||||
settings::{Settings, SettingsError},
|
||||
},
|
||||
daemon::DaemonError,
|
||||
dir::LianaDirectory,
|
||||
@ -22,15 +22,18 @@ use crate::{
|
||||
use super::client::{
|
||||
auth::{AuthClient, AuthError},
|
||||
backend::{api, BackendClient, BackendWalletClient},
|
||||
cache::{self, update_connect_cache, ConnectCacheError},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Error {
|
||||
Auth(AuthError),
|
||||
CredentialsMissing,
|
||||
// DaemonError does not implement Clone.
|
||||
// TODO: maybe Arc is overkill
|
||||
Backend(Arc<DaemonError>),
|
||||
Settings(SettingsError),
|
||||
Cache(cache::ConnectCacheError),
|
||||
Unexpected(String),
|
||||
}
|
||||
|
||||
@ -38,8 +41,10 @@ impl std::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Auth(e) => write!(f, "Authentication error: {}", e),
|
||||
Self::CredentialsMissing => write!(f, "credentials missing"),
|
||||
Self::Backend(e) => write!(f, "Remote backend error: {}", e),
|
||||
Self::Settings(e) => write!(f, "Settings file error: {}", e),
|
||||
Self::Cache(e) => write!(f, "Connect cache file error: {}", e),
|
||||
Self::Unexpected(e) => write!(f, "Unexpected error: {}", e),
|
||||
}
|
||||
}
|
||||
@ -63,6 +68,12 @@ impl From<SettingsError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ConnectCacheError> for Error {
|
||||
fn from(value: ConnectCacheError) -> Self {
|
||||
Self::Cache(value)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Message {
|
||||
View(ViewMessage),
|
||||
@ -156,13 +167,13 @@ impl LianaLiteLogin {
|
||||
},
|
||||
Task::none(),
|
||||
),
|
||||
Ok(auth_config) => (
|
||||
Ok(setting) => (
|
||||
Self {
|
||||
network,
|
||||
datadir,
|
||||
datadir: datadir.clone(),
|
||||
step: ConnectionStep::CheckingAuthFile,
|
||||
connection_error: None,
|
||||
wallet_id: auth_config.wallet_id.clone(),
|
||||
wallet_id: setting.wallet_id.clone(),
|
||||
auth_error: None,
|
||||
processing: true,
|
||||
},
|
||||
@ -174,14 +185,14 @@ impl LianaLiteLogin {
|
||||
let client = AuthClient::new(
|
||||
service_config.auth_api_url,
|
||||
service_config.auth_api_public_key,
|
||||
auth_config.email,
|
||||
setting.email,
|
||||
);
|
||||
connect_with_refresh_token(
|
||||
connect_with_credentials(
|
||||
client,
|
||||
auth_config.refresh_token,
|
||||
auth_config.wallet_id,
|
||||
setting.wallet_id,
|
||||
service_config.backend_api_url,
|
||||
network,
|
||||
datadir,
|
||||
)
|
||||
.await
|
||||
},
|
||||
@ -327,9 +338,11 @@ impl LianaLiteLogin {
|
||||
self.auth_error = None;
|
||||
let wallet_id = self.wallet_id.clone();
|
||||
let network = self.network;
|
||||
let datadir = self.datadir.clone();
|
||||
return Task::perform(
|
||||
async move {
|
||||
connect(client, otp, wallet_id, backend_api_url, network).await
|
||||
connect(client, otp, wallet_id, backend_api_url, network, datadir)
|
||||
.await
|
||||
},
|
||||
Message::Connected,
|
||||
);
|
||||
@ -343,21 +356,8 @@ impl LianaLiteLogin {
|
||||
return Task::perform(async move { Some(client) }, Message::Install);
|
||||
}
|
||||
Ok(BackendState::WalletExists(client, wallet, coins)) => {
|
||||
let datadir = self.datadir.clone();
|
||||
let network = self.network;
|
||||
return Task::perform(
|
||||
async move {
|
||||
update_wallet_auth_settings(
|
||||
datadir,
|
||||
network,
|
||||
wallet.clone(),
|
||||
client.user_email().to_string(),
|
||||
client.auth().await.refresh_token,
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok((client, wallet, coins))
|
||||
},
|
||||
async move { Ok((client, wallet, coins)) },
|
||||
Message::Run,
|
||||
);
|
||||
}
|
||||
@ -494,68 +494,20 @@ impl LianaLiteLogin {
|
||||
}
|
||||
}
|
||||
|
||||
async fn update_wallet_auth_settings(
|
||||
datadir: LianaDirectory,
|
||||
network: Network,
|
||||
wallet: api::Wallet,
|
||||
email: String,
|
||||
refresh_token: String,
|
||||
) -> Result<(), Error> {
|
||||
let network_dir = datadir.network_directory(network);
|
||||
let mut settings = Settings::from_file(&network_dir)?;
|
||||
|
||||
let descriptor_checksum = wallet
|
||||
.descriptor
|
||||
.to_string()
|
||||
.split_once('#')
|
||||
.map(|(_, checksum)| checksum)
|
||||
.expect("Failed to get checksum from a valid LianaDescriptor")
|
||||
.to_string();
|
||||
|
||||
let remote_backend_auth = Some(AuthConfig {
|
||||
email,
|
||||
wallet_id: wallet.id.clone(),
|
||||
refresh_token,
|
||||
});
|
||||
|
||||
if let Some(wallet_settings) = settings.wallets.iter_mut().find(|w| {
|
||||
if let Some(auth) = &w.remote_backend_auth {
|
||||
auth.wallet_id == wallet.id
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}) {
|
||||
wallet_settings.remote_backend_auth = remote_backend_auth;
|
||||
} else {
|
||||
tracing::info!("Wallet id was not found in the settings, adding now the wallet settings to the settings.json file");
|
||||
settings.wallets.insert(
|
||||
0,
|
||||
WalletSetting {
|
||||
name: wallet.name,
|
||||
descriptor_checksum,
|
||||
keys: Vec::new(),
|
||||
hardware_wallets: Vec::new(),
|
||||
remote_backend_auth,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
settings.to_file(&network_dir).map_err(|e| {
|
||||
DaemonError::Unexpected(format!("Cannot access to settings.json file: {}", e))
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn connect(
|
||||
auth: AuthClient,
|
||||
token: String,
|
||||
wallet_id: String,
|
||||
backend_api_url: String,
|
||||
network: Network,
|
||||
liana_directory: LianaDirectory,
|
||||
) -> Result<BackendState, Error> {
|
||||
let network_dir = liana_directory.network_directory(network);
|
||||
let access = auth.verify_otp(token.trim_end()).await?;
|
||||
let client = BackendClient::connect(auth, backend_api_url, access.clone(), network).await?;
|
||||
let client =
|
||||
BackendClient::connect(auth.clone(), backend_api_url, access.clone(), network).await?;
|
||||
|
||||
update_connect_cache(&network_dir, &access, &auth, false).await?;
|
||||
|
||||
let wallets = client.list_wallets().await?;
|
||||
if wallets.is_empty() {
|
||||
@ -566,25 +518,35 @@ pub async fn connect(
|
||||
let first = wallets.first().cloned().ok_or(DaemonError::NoAnswer)?;
|
||||
let (wallet_client, wallet) = client.connect_wallet(first);
|
||||
let coins = coins_to_cache(Arc::new(wallet_client.clone())).await?;
|
||||
|
||||
Ok(BackendState::WalletExists(wallet_client, wallet, coins))
|
||||
} else if let Some(wallet) = wallets.into_iter().find(|w| w.id == wallet_id) {
|
||||
let (wallet_client, wallet) = client.connect_wallet(wallet);
|
||||
let coins = coins_to_cache(Arc::new(wallet_client.clone())).await?;
|
||||
|
||||
Ok(BackendState::WalletExists(wallet_client, wallet, coins))
|
||||
} else {
|
||||
Ok(BackendState::NoWallet(client))
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn connect_with_refresh_token(
|
||||
pub async fn connect_with_credentials(
|
||||
auth: AuthClient,
|
||||
refresh_token: String,
|
||||
wallet_id: String,
|
||||
backend_api_url: String,
|
||||
network: Network,
|
||||
liana_directory: LianaDirectory,
|
||||
) -> Result<BackendState, Error> {
|
||||
let access = auth.refresh_token(&refresh_token).await?;
|
||||
let client = BackendClient::connect(auth, backend_api_url, access.clone(), network).await?;
|
||||
let network_dir = liana_directory.network_directory(network);
|
||||
let mut tokens = cache::Credential::from_cache(&network_dir, &auth.email)?
|
||||
.ok_or(Error::CredentialsMissing)?
|
||||
.tokens;
|
||||
|
||||
if tokens.expires_at < chrono::Utc::now().timestamp() {
|
||||
tokens = cache::update_connect_cache(&network_dir, &tokens, &auth, true).await?;
|
||||
}
|
||||
|
||||
let client = BackendClient::connect(auth, backend_api_url, tokens, network).await?;
|
||||
|
||||
if let Some(wallet) = client
|
||||
.list_wallets()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user