From 383908b17104fc00c5cd5e48ca949fa0cdffc307 Mon Sep 17 00:00:00 2001 From: ghe0 Date: Fri, 28 Mar 2025 23:35:53 +0200 Subject: [PATCH] added support for self signed TLS certificates --- Cargo.lock | 2 + Cargo.toml | 2 +- README.md | 1 - scripts/install.sh | 3 ++ src/bin/detee-cli.rs | 8 ++-- src/bin/super-detee-cli.rs | 15 ++++---- src/config.rs | 78 +++++++++++++++++++++----------------- src/general/cli_handler.rs | 6 +-- src/general/grpc.rs | 61 ++++++++++++++++++----------- src/sgx/grpc_brain.rs | 37 +++++++++++++----- src/sgx/grpc_dtpm.rs | 8 ++-- src/snp/grpc.rs | 38 +++++++++++++++---- 12 files changed, 165 insertions(+), 94 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a13f5d3..e3fb603 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3585,8 +3585,10 @@ dependencies = [ "percent-encoding", "pin-project", "prost", + "rustls-pemfile", "socket2", "tokio", + "tokio-rustls", "tokio-stream", "tower 0.4.13", "tower-layer", diff --git a/Cargo.toml b/Cargo.toml index e418d84..69592f9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,7 +19,7 @@ serde_yaml = "0.9.34" tabled = "0.17.0" tokio-stream = "0.1.17" tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] } -tonic = "0.12" +tonic = { version = "0.12", features = ["tls"] } thiserror = "2.0.9" bs58 = "0.5.1" chrono = "0.4.39" diff --git a/README.md b/README.md index 76d0b73..f119942 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,6 @@ Inside the container, configure the accounts for your session: ssh-keygen # Hit enter a few times. detee-cli account ssh-pubkey-path /root/.ssh/id_ed25519.pub -detee-cli account brain-url http://164.92.249.180:31337 ``` ### VM creation diff --git a/scripts/install.sh b/scripts/install.sh index bb45301..11aeb2b 100755 --- a/scripts/install.sh +++ b/scripts/install.sh @@ -56,6 +56,9 @@ install_detee-cli() { } cargo build --release cp ./target/release/detee-cli ${HOME}/.detee/bin + [[ -f "${HOME}/.detee/cli/root_ca.pem" ]] || { + wget -O "${HOME}/.detee/cli/root_ca.pem" https://registry.detee.ltd/root_ca.pem + } } install_super-detee-cli() { diff --git a/src/bin/detee-cli.rs b/src/bin/detee-cli.rs index 3097f07..ae625d9 100644 --- a/src/bin/detee-cli.rs +++ b/src/bin/detee-cli.rs @@ -13,6 +13,8 @@ More information can be found at https://detee.ltd Feel free to browser applications bundles or VM disks available for immediate deployment."#; fn main() { + // TODO: figure if there is a more elegant way to solve this than calling default_provider in main + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let log_level = match std::env::var("LOG_LEVEL") { Ok(val) => match val.as_str() { "DEBUG" => log::LevelFilter::Debug, @@ -610,10 +612,10 @@ fn clap_cmd() -> Command { .required(true) ) ) - .subcommand(Command::new("brain-url").about("define the URL of the brain you work with") + .subcommand(Command::new("network").about("specify if you connect to testnet or staging") .arg( - Arg::new("url") - .help("supply the URL of the brain you want to connect to") + Arg::new("name") + .help("the name of the network that you are connecting to") .required(true) ) ) diff --git a/src/bin/super-detee-cli.rs b/src/bin/super-detee-cli.rs index bf25a9a..9a9cdb3 100644 --- a/src/bin/super-detee-cli.rs +++ b/src/bin/super-detee-cli.rs @@ -14,6 +14,7 @@ It allows you to: The admin pubkeys are hardcoded in the brain."#; fn main() { + let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); let log_level = match std::env::var("LOG_LEVEL") { Ok(val) => match val.as_str() { "DEBUG" => log::LevelFilter::Debug, @@ -74,11 +75,11 @@ fn main() { Command::new("show").about("show account data associated with this CLI"), ) .subcommand( - Command::new("brain-url") - .about("define the URL of the brain you work with") + Command::new("network") + .about("specify if you connect to testnet or staging") .arg( - Arg::new("url") - .help("supply the URL of the brain you want to connect to") + Arg::new("name") + .help("name of the network you are connecting to") .required(true), ), ), @@ -114,9 +115,9 @@ fn handle_account(matches: &ArgMatches) { } Err(e) => println!("Could not get contracts due to error: {e:?}"), }, - Some(("brain-url", path_subcommand)) => { - let url: String = path_subcommand.get_one::("url").unwrap().clone(); - Config::set_brain_url(&url); + Some(("network", path_subcommand)) => { + let name: String = path_subcommand.get_one::("name").unwrap().clone(); + Config::set_network(&name); } _ => cli_print(Ok(config::Config::get_account_data())), } diff --git a/src/config.rs b/src/config.rs index 3a554d9..b5d990e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -11,7 +11,7 @@ use std::{fs::File, io::Write, path::Path}; #[derive(Serialize, Default)] pub struct AccountData { path: String, - brain_url: String, + network: String, ssh_pubkey: String, account_balance: f64, locked_funds: f64, @@ -25,8 +25,8 @@ pub struct AccountData { impl super::HumanOutput for AccountData { fn human_cli_print(&self) { - if !self.brain_url.is_empty() { - println!("The brain URL is: {}", self.brain_url); + if !self.network.is_empty() { + println!("The network you are using is: {}", self.network); } if !self.ssh_pubkey.is_empty() { println!("The SSH key used for VMs is: {}", self.ssh_pubkey); @@ -53,7 +53,14 @@ impl super::HumanOutput for AccountData { #[derive(Serialize, Deserialize, Debug, Default)] pub struct Config { ssh_key_path: String, - brain_url: String, + #[serde(default = "default_network")] + network: String, +} + +fn default_network() -> String { + // default to testnet + // TODO: remove instruction from docs to set brain_url, since it defaults now + "testing".to_string() } #[derive(thiserror::Error, Debug)] @@ -80,7 +87,7 @@ pub enum Error { impl Config { fn save_to_disk(&self) -> Result<(), Error> { - let path = Self::path()?; + let path = Self::config_path()?; debug!("Writing config file to disk at {}", path); let mut file = File::create(path)?; file.write_all(serde_yaml::to_string(self)?.as_bytes())?; @@ -169,7 +176,7 @@ impl Config { Ok(dir + "/uuid_list") } - pub fn path_dir() -> Result { + pub fn cli_dir_path() -> Result { let dir = Self::home_dir() + ("/.detee/cli"); if !Path::new(&dir).exists() { warn!("Could not config dir. Creating {dir}"); @@ -178,26 +185,26 @@ impl Config { Ok(dir) } - fn path() -> Result { - let config_path = Self::path_dir()? + ("/cli-config.yaml"); + fn config_path() -> Result { + let config_path = Self::cli_dir_path()? + ("/cli-config.yaml"); Ok(config_path) } fn detee_wallet_key_path() -> Result { - let config_path = Self::path_dir()? + ("/secret_detee_wallet_key"); + let config_path = Self::cli_dir_path()? + ("/secret_detee_wallet_key"); Ok(config_path) } fn load_config_from_file() -> Result { - Ok(serde_yaml::from_str(&std::fs::read_to_string(Self::path()?)?)?) + Ok(serde_yaml::from_str(&std::fs::read_to_string(Self::config_path()?)?)?) } pub fn init_config() -> Self { // TODO: create if it does not exist - let mut config = match Self::load_config_from_file() { + let config = match Self::load_config_from_file() { Ok(config) => config, Err(e) => { - debug!("Could not load config due to error: {e}"); + log::error!("Could not load config due to error: {e}"); eprintln!("Config file not found. Creating new config file!"); let config = Self::default(); if let Err(e) = config.save_to_disk() { @@ -207,11 +214,6 @@ impl Config { config } }; - // default to testnet if there is no brain_url - // TODO: remove instruction from docs to set brain_url, since it defaults now - if config.brain_url.is_empty() { - config.brain_url = "http://164.92.249.180:31337".to_string(); - } config } @@ -297,19 +299,27 @@ impl Config { Ok(self.ssh_key_path.clone()) } - pub fn get_brain_url() -> String { - Self::init_config().brain_url + pub fn get_root_ca_path() -> Result { + Ok(Self::cli_dir_path()? + "/root_ca.pem") } - pub fn set_brain_url(brain_url: &str) { - let brain_url = match brain_url { - "testnet" => "http://164.92.249.180:31337", - "staging" => "http://159.65.58.38:31337", - something_else => something_else, - }; + pub fn get_brain_info() -> (String, String) { + match Self::init_config().network.as_str() { + "staging" => ("https://159.65.58.38:31337".to_string(), "staging-brain".to_string()), + _ => ("https://164.92.249.180:31337".to_string(), "testing-brain".to_string()), + } + } + + pub fn set_network(mut network: &str) { + if network != "staging" { + log::error!( + "The network {network} is not officially supported. Defaulting to testnet!" + ); + network = "testnet"; + } let mut config = Self::init_config(); - info!("Setting brain URL to {brain_url}"); - config.brain_url = brain_url.to_string(); + info!("Setting the network to {network}"); + config.network = network.to_string(); if let Err(e) = config.save_to_disk() { log::error!("Could not save new brain URL to config: {e}"); } @@ -318,18 +328,18 @@ impl Config { pub fn get_account_data() -> AccountData { let mut account_data = AccountData { ..Default::default() }; let config = Self::init_config(); - match Self::path() { + match Self::config_path() { Ok(path) => account_data.path = path, Err(e) => { println!("Could not read config due to error: {e}"); std::process::exit(1); } } - if config.brain_url.is_empty() { - log::error!("The brain URL is not set! To configure it, run:"); - eprintln!(r#" detee-cli account brain-url "http://[::1]:31337/""#); + if config.network.is_empty() { + log::error!("The network is not set! To configure it, run:"); + eprintln!(" detee-cli account network testnet"); } else { - account_data.brain_url = config.brain_url; + account_data.network = config.network; } if config.ssh_key_path.is_empty() { log::error!("SSH public key path not set! To configure it, run:"); @@ -408,7 +418,7 @@ impl Config { } pub fn hratls_key_path() -> Result { - Ok(Self::path_dir()? + ("/hratls_private_key.pem")) + Ok(Self::cli_dir_path()? + ("/hratls_private_key.pem")) } } @@ -449,7 +459,7 @@ impl Config { } pub fn mrsigner_key_path() -> Result { - Ok(Self::path_dir()? + ("/app_signing_key.pem")) + Ok(Self::cli_dir_path()? + ("/app_signing_key.pem")) } } diff --git a/src/general/cli_handler.rs b/src/general/cli_handler.rs index dfe1f46..5fcd1c9 100644 --- a/src/general/cli_handler.rs +++ b/src/general/cli_handler.rs @@ -55,9 +55,9 @@ pub fn handle_account(matches: &ArgMatches) { let path: String = path_subcommand.get_one::("path").unwrap().clone(); config::Config::set_ssh_pubkey_path(&path); } - Some(("brain-url", path_subcommand)) => { - let url: String = path_subcommand.get_one::("url").unwrap().clone(); - config::Config::set_brain_url(&url); + Some(("network", path_subcommand)) => { + let name: String = path_subcommand.get_one::("name").unwrap().clone(); + config::Config::set_network(&name); } _ => cli_print(Ok(config::Config::get_account_data())), } diff --git a/src/general/grpc.rs b/src/general/grpc.rs index 5ec43ca..0db1ba3 100644 --- a/src/general/grpc.rs +++ b/src/general/grpc.rs @@ -4,6 +4,7 @@ use crate::utils::sign_request; use detee_shared::general_proto::ReportNodeReq; use log::{debug, info, warn}; use tokio_stream::StreamExt; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; pub mod proto { pub use detee_shared::common_proto::*; @@ -27,20 +28,40 @@ pub enum Error { InternalError(#[from] crate::utils::Error), #[error(transparent)] ConfigError(#[from] crate::config::Error), + #[error("The Root CA file got corrupted.")] + CorruptedRootCa(#[from] std::io::Error), + #[error("Internal app error: could not parse Brain URL")] + CorruptedBrainUrl, +} + +async fn client() -> Result, Error> { + let (brain_url, brain_san) = Config::get_brain_info(); + Ok(BrainGeneralCliClient::new( + Channel::from_shared(brain_url.to_string()) + .map_err(|_| Error::CorruptedBrainUrl)? + .tls_config( + ClientTlsConfig::new() + .ca_certificate(Certificate::from_pem(std::fs::read_to_string( + Config::get_root_ca_path()?, + )?)) + .domain_name(brain_san), + )? + .connect() + .await?, + )) } pub async fn get_balance(account: &str) -> Result { - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let response = - client.get_balance(sign_request(Pubkey { pubkey: account.to_string() })?).await?; + client().await?.get_balance(sign_request(Pubkey { pubkey: account.to_string() })?).await?; log::info!("Received account from brain: {response:?}"); Ok(response.into_inner()) } pub async fn register_operator(escrow: u64, email: String) -> Result<(), Error> { debug!("Connecting to brain to register operator..."); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; - client + client() + .await? .register_operator(sign_request(RegOperatorReq { pubkey: Config::get_detee_wallet()?, escrow, @@ -52,15 +73,14 @@ pub async fn register_operator(escrow: u64, email: String) -> Result<(), Error> pub async fn inspect_operator(wallet: String) -> Result { debug!("Getting information about operator {wallet} from brain."); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; - Ok(client.inspect_operator(Pubkey { pubkey: wallet }).await?.into_inner()) + Ok(client().await?.inspect_operator(Pubkey { pubkey: wallet }).await?.into_inner()) } pub async fn list_operators() -> Result, Error> { debug!("Getting contracts from brain..."); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let mut operators = Vec::new(); - let mut grpc_stream = client.list_operators(sign_request(Empty {})?).await?.into_inner(); + let mut grpc_stream = + client().await?.list_operators(sign_request(Empty {})?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { match stream_update { Ok(op) => { @@ -77,8 +97,8 @@ pub async fn list_operators() -> Result, Error> { pub async fn kick_contract(contract_uuid: String, reason: String) -> Result { debug!("gRPC module: connecting to brain and kicking contract {contract_uuid} for reason: {reason}"); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; - Ok(client + Ok(client() + .await? .kick_contract(sign_request(KickReq { operator_wallet: Config::get_detee_wallet()?, contract_uuid, @@ -91,8 +111,8 @@ pub async fn kick_contract(contract_uuid: String, reason: String) -> Result Result<(), Error> { debug!("Connecting to brain to ban user..."); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; - client + client() + .await? .ban_user(sign_request(BanUserReq { operator_wallet: Config::get_detee_wallet()?, user_wallet, @@ -107,8 +127,8 @@ pub async fn report_node( reason: String, ) -> Result<(), Error> { debug!("Getting contracts from brain..."); - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; - client + client() + .await? .report_node(sign_request(ReportNodeReq { admin_pubkey: Config::get_detee_wallet()?, node_pubkey, @@ -122,9 +142,9 @@ pub async fn report_node( // super admin pub async fn admin_list_accounts() -> Result, Error> { - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let mut accounts = Vec::new(); - let mut grpc_stream = client.list_accounts(sign_request(Empty {})?).await?.into_inner(); + let mut grpc_stream = + client().await?.list_accounts(sign_request(Empty {})?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { match stream_update { Ok(account) => { @@ -141,9 +161,8 @@ pub async fn admin_list_accounts() -> Result, Error> { } pub async fn admin_list_contracts() -> Result, Error> { - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let mut contracts = Vec::new(); - let mut grpc_stream = client.list_all_vm_contracts(sign_request(Empty {})?).await?.into_inner(); + let mut grpc_stream = client().await?.list_all_vm_contracts(sign_request(Empty {})?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { match stream_update { Ok(contract) => { @@ -160,15 +179,13 @@ pub async fn admin_list_contracts() -> Result, Error> { } pub async fn admin_airdrop(pubkey: String, tokens: u64) -> Result<(), Error> { - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let req = sign_request(AirdropReq { pubkey, tokens })?; - let _ = client.airdrop(req).await?; + let _ = client().await?.airdrop(req).await?; Ok(()) } pub async fn admin_slash(pubkey: String, tokens: u64) -> Result<(), Error> { - let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?; let req = sign_request(SlashReq { pubkey, tokens })?; - let _ = client.slash(req).await?; + let _ = client().await?.slash(req).await?; Ok(()) } diff --git a/src/sgx/grpc_brain.rs b/src/sgx/grpc_brain.rs index 8bc7324..6ae6a31 100644 --- a/src/sgx/grpc_brain.rs +++ b/src/sgx/grpc_brain.rs @@ -5,6 +5,7 @@ use detee_shared::app_proto::{ }; use detee_shared::sgx::types::brain::AppDeployConfig; use tokio_stream::StreamExt; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use crate::config::Config; use crate::sgx::utils::calculate_nanolp_for_app; @@ -20,6 +21,10 @@ pub enum Error { InternalError(#[from] utils::Error), #[error(transparent)] ConfigError(#[from] crate::config::Error), + #[error("The Root CA file got corrupted.")] + CorruptedRootCa(#[from] std::io::Error), + #[error("Internal app error: could not parse Brain URL")] + CorruptedBrainUrl, } type Result = std::result::Result; @@ -60,6 +65,23 @@ impl crate::HumanOutput for AppContract { } } +async fn client() -> Result> { + let (brain_url, brain_san) = Config::get_brain_info(); + Ok(BrainAppCliClient::new( + Channel::from_shared(brain_url.to_string()) + .map_err(|_| Error::CorruptedBrainUrl)? + .tls_config( + ClientTlsConfig::new() + .ca_certificate(Certificate::from_pem(std::fs::read_to_string( + Config::get_root_ca_path()?, + )?)) + .domain_name(brain_san), + )? + .connect() + .await?, + )) +} + pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result { let resource = app_deploy_config.clone().resource; let mut req: NewAppReq = app_deploy_config.clone().into(); @@ -77,21 +99,19 @@ pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result { req.admin_pubkey = Config::get_detee_wallet()?; req.hratls_pubkey = Config::get_hratls_pubkey_hex()?; - let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?; - let res = daemon_serivce.deploy_app(sign_request(req)?).await?; + let res = client().await?.deploy_app(sign_request(req)?).await?; Ok(res.into_inner()) } pub async fn delete_app(app_uuid: String) -> Result<()> { let admin_pubkey = Config::get_detee_wallet()?; let delete_req = DelAppReq { uuid: app_uuid, admin_pubkey }; - let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?; - let _ = daemon_serivce.delete_app(sign_request(delete_req)?).await?; + let _ = client().await?.delete_app(sign_request(delete_req)?).await?; Ok(()) } pub async fn list_contracts(req: ListAppContractsReq) -> Result> { - let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?; + let mut daemon_serivce = client().await?; let mut res_stream = daemon_serivce.list_app_contracts(sign_request(req)?).await?.into_inner(); let mut app_contracts = vec![]; @@ -111,17 +131,14 @@ pub async fn list_contracts(req: ListAppContractsReq) -> Result } pub async fn get_one_app_node(req: AppNodeFilters) -> Result { - let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?; - let res = daemon_serivce.get_one_app_node(sign_request(req)?).await?; - + let res = client().await?.get_one_app_node(sign_request(req)?).await?; Ok(res.into_inner()) } pub async fn get_app_node_list(req: AppNodeFilters) -> Result> { log::debug!("Getting app nodes from brain..."); - let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?; let mut nodes = Vec::new(); - let mut grpc_stream = daemon_serivce.list_app_nodes(sign_request(req)?).await?.into_inner(); + let mut grpc_stream = client().await?.list_app_nodes(sign_request(req)?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { match stream_update { diff --git a/src/sgx/grpc_dtpm.rs b/src/sgx/grpc_dtpm.rs index c781111..6930279 100644 --- a/src/sgx/grpc_dtpm.rs +++ b/src/sgx/grpc_dtpm.rs @@ -17,9 +17,9 @@ use crate::sgx::utils::hratls_url_and_mr_enclave_from_app_id; #[derive(thiserror::Error, Debug)] pub enum Error { - #[error("Failed to connect to the dtpm: {0}")] - BrainConnection(#[from] tonic::transport::Error), - #[error("Received error from dtpm: {}", _0.message())] + #[error("Failed to connect to DTPM: {0}")] + DtpmConnection(#[from] tonic::transport::Error), + #[error("Received error from DTPM: {}", _0.message())] ResponseStatus(#[from] tonic::Status), #[error("Hex: {0}")] HexDecode(#[from] hex::FromHexError), @@ -44,8 +44,6 @@ pub async fn connect_dtpm_grpc_client( hex::decode_to_slice(Config::get_mrsigner()?, &mut mr_signer)?; let mr_signers = vec![mr_signer]; - let _ = rustls::crypto::aws_lc_rs::default_provider().install_default(); - let hratls_config = Arc::new(RwLock::new( HRaTlsConfig::new() .allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(mr_signers)) diff --git a/src/snp/grpc.rs b/src/snp/grpc.rs index 55b7484..b07a4ec 100644 --- a/src/snp/grpc.rs +++ b/src/snp/grpc.rs @@ -13,6 +13,7 @@ use proto::{ use tokio_stream::StreamExt; use tonic::metadata::errors::InvalidMetadataValue; use tonic::metadata::AsciiMetadataValue; +use tonic::transport::{Certificate, Channel, ClientTlsConfig}; use tonic::Request; lazy_static! { @@ -35,7 +36,11 @@ pub enum Error { #[error("Could not find contract {0}")] VmContractNotFound(String), #[error(transparent)] - InternalError(#[from] InvalidMetadataValue), + InternalParsingError(#[from] InvalidMetadataValue), + #[error("The Root CA file got corrupted.")] + CorruptedRootCa(#[from] std::io::Error), + #[error("Internal app error: could not parse Brain URL")] + CorruptedBrainUrl, } impl crate::HumanOutput for VmContract { @@ -78,6 +83,23 @@ impl crate::HumanOutput for VmNodeListResp { } } +async fn client() -> Result, Error> { + let (brain_url, brain_san) = Config::get_brain_info(); + Ok(BrainVmCliClient::new( + Channel::from_shared(brain_url.to_string()) + .map_err(|_| Error::CorruptedBrainUrl)? + .tls_config( + ClientTlsConfig::new() + .ca_certificate(Certificate::from_pem(std::fs::read_to_string( + Config::get_root_ca_path()?, + )?)) + .domain_name(brain_san), + )? + .connect() + .await?, + )) +} + fn sign_request(req: T) -> Result, Error> { let pubkey = Config::get_detee_wallet()?; let timestamp = chrono::Utc::now().to_rfc3339(); @@ -94,7 +116,7 @@ fn sign_request(req: T) -> Result, Error> { pub async fn get_node_list(req: VmNodeFilters) -> Result, Error> { debug!("Getting nodes from brain..."); - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let mut nodes = Vec::new(); let mut grpc_stream = client.list_vm_nodes(sign_request(req)?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { @@ -113,13 +135,13 @@ pub async fn get_node_list(req: VmNodeFilters) -> Result, Er } pub async fn get_one_node(req: VmNodeFilters) -> Result { - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let response = client.get_one_vm_node(sign_request(req)?).await?; Ok(response.into_inner()) } pub async fn create_vm(req: NewVmReq) -> Result { - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; debug!("Sending NewVmReq to brain: {req:?}"); match client.new_vm(sign_request(req)?).await { Ok(resp) => Ok(resp.into_inner()), @@ -129,7 +151,7 @@ pub async fn create_vm(req: NewVmReq) -> Result { pub async fn list_contracts(req: ListVmContractsReq) -> Result, Error> { debug!("Getting contracts from brain..."); - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let mut contracts = Vec::new(); let mut grpc_stream = client.list_vm_contracts(sign_request(req)?).await?.into_inner(); while let Some(stream_update) = grpc_stream.next().await { @@ -148,7 +170,7 @@ pub async fn list_contracts(req: ListVmContractsReq) -> Result, } pub async fn delete_vm(uuid: &str) -> Result<(), Error> { - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let req = DeleteVmReq { uuid: uuid.to_string(), admin_pubkey: Config::get_detee_wallet()? }; let result = client.delete_vm(sign_request(req)?).await; match result { @@ -164,7 +186,7 @@ pub async fn delete_vm(uuid: &str) -> Result<(), Error> { } pub async fn extend_vm(uuid: String, admin_pubkey: String, locked_nano: u64) -> Result<(), Error> { - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let req = ExtendVmReq { admin_pubkey, uuid, locked_nano }; let result = client.extend_vm(sign_request(req)?).await; match result { @@ -186,7 +208,7 @@ pub async fn extend_vm(uuid: String, admin_pubkey: String, locked_nano: u64) -> pub async fn update_vm(req: UpdateVmReq) -> Result { info!("Updating VM {req:?}"); - let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?; + let mut client = client().await?; let result = client.update_vm(sign_request(req)?).await; match result { Ok(resp) => {