added support for self signed TLS certificates
This commit is contained in:
parent
f97595523c
commit
383908b171
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -3585,8 +3585,10 @@ dependencies = [
|
|||||||
"percent-encoding",
|
"percent-encoding",
|
||||||
"pin-project",
|
"pin-project",
|
||||||
"prost",
|
"prost",
|
||||||
|
"rustls-pemfile",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
"tokio-rustls",
|
||||||
"tokio-stream",
|
"tokio-stream",
|
||||||
"tower 0.4.13",
|
"tower 0.4.13",
|
||||||
"tower-layer",
|
"tower-layer",
|
||||||
|
@ -19,7 +19,7 @@ serde_yaml = "0.9.34"
|
|||||||
tabled = "0.17.0"
|
tabled = "0.17.0"
|
||||||
tokio-stream = "0.1.17"
|
tokio-stream = "0.1.17"
|
||||||
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
|
tokio = { version = "1.42.0", features = ["macros", "rt-multi-thread"] }
|
||||||
tonic = "0.12"
|
tonic = { version = "0.12", features = ["tls"] }
|
||||||
thiserror = "2.0.9"
|
thiserror = "2.0.9"
|
||||||
bs58 = "0.5.1"
|
bs58 = "0.5.1"
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
|
@ -28,7 +28,6 @@ Inside the container, configure the accounts for your session:
|
|||||||
ssh-keygen
|
ssh-keygen
|
||||||
# Hit enter a few times.
|
# Hit enter a few times.
|
||||||
detee-cli account ssh-pubkey-path /root/.ssh/id_ed25519.pub
|
detee-cli account ssh-pubkey-path /root/.ssh/id_ed25519.pub
|
||||||
detee-cli account brain-url http://164.92.249.180:31337
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### VM creation
|
### VM creation
|
||||||
|
@ -56,6 +56,9 @@ install_detee-cli() {
|
|||||||
}
|
}
|
||||||
cargo build --release
|
cargo build --release
|
||||||
cp ./target/release/detee-cli ${HOME}/.detee/bin
|
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() {
|
install_super-detee-cli() {
|
||||||
|
@ -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."#;
|
Feel free to browser applications bundles or VM disks available for immediate deployment."#;
|
||||||
|
|
||||||
fn main() {
|
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") {
|
let log_level = match std::env::var("LOG_LEVEL") {
|
||||||
Ok(val) => match val.as_str() {
|
Ok(val) => match val.as_str() {
|
||||||
"DEBUG" => log::LevelFilter::Debug,
|
"DEBUG" => log::LevelFilter::Debug,
|
||||||
@ -610,10 +612,10 @@ fn clap_cmd() -> Command {
|
|||||||
.required(true)
|
.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(
|
||||||
Arg::new("url")
|
Arg::new("name")
|
||||||
.help("supply the URL of the brain you want to connect to")
|
.help("the name of the network that you are connecting to")
|
||||||
.required(true)
|
.required(true)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -14,6 +14,7 @@ It allows you to:
|
|||||||
The admin pubkeys are hardcoded in the brain."#;
|
The admin pubkeys are hardcoded in the brain."#;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
let _ = rustls::crypto::aws_lc_rs::default_provider().install_default();
|
||||||
let log_level = match std::env::var("LOG_LEVEL") {
|
let log_level = match std::env::var("LOG_LEVEL") {
|
||||||
Ok(val) => match val.as_str() {
|
Ok(val) => match val.as_str() {
|
||||||
"DEBUG" => log::LevelFilter::Debug,
|
"DEBUG" => log::LevelFilter::Debug,
|
||||||
@ -74,11 +75,11 @@ fn main() {
|
|||||||
Command::new("show").about("show account data associated with this CLI"),
|
Command::new("show").about("show account data associated with this CLI"),
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
Command::new("brain-url")
|
Command::new("network")
|
||||||
.about("define the URL of the brain you work with")
|
.about("specify if you connect to testnet or staging")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("url")
|
Arg::new("name")
|
||||||
.help("supply the URL of the brain you want to connect to")
|
.help("name of the network you are connecting to")
|
||||||
.required(true),
|
.required(true),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -114,9 +115,9 @@ fn handle_account(matches: &ArgMatches) {
|
|||||||
}
|
}
|
||||||
Err(e) => println!("Could not get contracts due to error: {e:?}"),
|
Err(e) => println!("Could not get contracts due to error: {e:?}"),
|
||||||
},
|
},
|
||||||
Some(("brain-url", path_subcommand)) => {
|
Some(("network", path_subcommand)) => {
|
||||||
let url: String = path_subcommand.get_one::<String>("url").unwrap().clone();
|
let name: String = path_subcommand.get_one::<String>("name").unwrap().clone();
|
||||||
Config::set_brain_url(&url);
|
Config::set_network(&name);
|
||||||
}
|
}
|
||||||
_ => cli_print(Ok(config::Config::get_account_data())),
|
_ => cli_print(Ok(config::Config::get_account_data())),
|
||||||
}
|
}
|
||||||
|
@ -11,7 +11,7 @@ use std::{fs::File, io::Write, path::Path};
|
|||||||
#[derive(Serialize, Default)]
|
#[derive(Serialize, Default)]
|
||||||
pub struct AccountData {
|
pub struct AccountData {
|
||||||
path: String,
|
path: String,
|
||||||
brain_url: String,
|
network: String,
|
||||||
ssh_pubkey: String,
|
ssh_pubkey: String,
|
||||||
account_balance: f64,
|
account_balance: f64,
|
||||||
locked_funds: f64,
|
locked_funds: f64,
|
||||||
@ -25,8 +25,8 @@ pub struct AccountData {
|
|||||||
|
|
||||||
impl super::HumanOutput for AccountData {
|
impl super::HumanOutput for AccountData {
|
||||||
fn human_cli_print(&self) {
|
fn human_cli_print(&self) {
|
||||||
if !self.brain_url.is_empty() {
|
if !self.network.is_empty() {
|
||||||
println!("The brain URL is: {}", self.brain_url);
|
println!("The network you are using is: {}", self.network);
|
||||||
}
|
}
|
||||||
if !self.ssh_pubkey.is_empty() {
|
if !self.ssh_pubkey.is_empty() {
|
||||||
println!("The SSH key used for VMs is: {}", self.ssh_pubkey);
|
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)]
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
ssh_key_path: String,
|
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)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
@ -80,7 +87,7 @@ pub enum Error {
|
|||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
fn save_to_disk(&self) -> Result<(), Error> {
|
fn save_to_disk(&self) -> Result<(), Error> {
|
||||||
let path = Self::path()?;
|
let path = Self::config_path()?;
|
||||||
debug!("Writing config file to disk at {}", path);
|
debug!("Writing config file to disk at {}", path);
|
||||||
let mut file = File::create(path)?;
|
let mut file = File::create(path)?;
|
||||||
file.write_all(serde_yaml::to_string(self)?.as_bytes())?;
|
file.write_all(serde_yaml::to_string(self)?.as_bytes())?;
|
||||||
@ -169,7 +176,7 @@ impl Config {
|
|||||||
Ok(dir + "/uuid_list")
|
Ok(dir + "/uuid_list")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn path_dir() -> Result<String, Error> {
|
pub fn cli_dir_path() -> Result<String, Error> {
|
||||||
let dir = Self::home_dir() + ("/.detee/cli");
|
let dir = Self::home_dir() + ("/.detee/cli");
|
||||||
if !Path::new(&dir).exists() {
|
if !Path::new(&dir).exists() {
|
||||||
warn!("Could not config dir. Creating {dir}");
|
warn!("Could not config dir. Creating {dir}");
|
||||||
@ -178,26 +185,26 @@ impl Config {
|
|||||||
Ok(dir)
|
Ok(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn path() -> Result<String, Error> {
|
fn config_path() -> Result<String, Error> {
|
||||||
let config_path = Self::path_dir()? + ("/cli-config.yaml");
|
let config_path = Self::cli_dir_path()? + ("/cli-config.yaml");
|
||||||
Ok(config_path)
|
Ok(config_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn detee_wallet_key_path() -> Result<String, Error> {
|
fn detee_wallet_key_path() -> Result<String, Error> {
|
||||||
let config_path = Self::path_dir()? + ("/secret_detee_wallet_key");
|
let config_path = Self::cli_dir_path()? + ("/secret_detee_wallet_key");
|
||||||
Ok(config_path)
|
Ok(config_path)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_config_from_file() -> Result<Self, Error> {
|
fn load_config_from_file() -> Result<Self, Error> {
|
||||||
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 {
|
pub fn init_config() -> Self {
|
||||||
// TODO: create if it does not exist
|
// 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,
|
Ok(config) => config,
|
||||||
Err(e) => {
|
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!");
|
eprintln!("Config file not found. Creating new config file!");
|
||||||
let config = Self::default();
|
let config = Self::default();
|
||||||
if let Err(e) = config.save_to_disk() {
|
if let Err(e) = config.save_to_disk() {
|
||||||
@ -207,11 +214,6 @@ impl Config {
|
|||||||
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
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,19 +299,27 @@ impl Config {
|
|||||||
Ok(self.ssh_key_path.clone())
|
Ok(self.ssh_key_path.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_brain_url() -> String {
|
pub fn get_root_ca_path() -> Result<String, Error> {
|
||||||
Self::init_config().brain_url
|
Ok(Self::cli_dir_path()? + "/root_ca.pem")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_brain_url(brain_url: &str) {
|
pub fn get_brain_info() -> (String, String) {
|
||||||
let brain_url = match brain_url {
|
match Self::init_config().network.as_str() {
|
||||||
"testnet" => "http://164.92.249.180:31337",
|
"staging" => ("https://159.65.58.38:31337".to_string(), "staging-brain".to_string()),
|
||||||
"staging" => "http://159.65.58.38:31337",
|
_ => ("https://164.92.249.180:31337".to_string(), "testing-brain".to_string()),
|
||||||
something_else => something_else,
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
|
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();
|
let mut config = Self::init_config();
|
||||||
info!("Setting brain URL to {brain_url}");
|
info!("Setting the network to {network}");
|
||||||
config.brain_url = brain_url.to_string();
|
config.network = network.to_string();
|
||||||
if let Err(e) = config.save_to_disk() {
|
if let Err(e) = config.save_to_disk() {
|
||||||
log::error!("Could not save new brain URL to config: {e}");
|
log::error!("Could not save new brain URL to config: {e}");
|
||||||
}
|
}
|
||||||
@ -318,18 +328,18 @@ impl Config {
|
|||||||
pub fn get_account_data() -> AccountData {
|
pub fn get_account_data() -> AccountData {
|
||||||
let mut account_data = AccountData { ..Default::default() };
|
let mut account_data = AccountData { ..Default::default() };
|
||||||
let config = Self::init_config();
|
let config = Self::init_config();
|
||||||
match Self::path() {
|
match Self::config_path() {
|
||||||
Ok(path) => account_data.path = path,
|
Ok(path) => account_data.path = path,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Could not read config due to error: {e}");
|
println!("Could not read config due to error: {e}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if config.brain_url.is_empty() {
|
if config.network.is_empty() {
|
||||||
log::error!("The brain URL is not set! To configure it, run:");
|
log::error!("The network is not set! To configure it, run:");
|
||||||
eprintln!(r#" detee-cli account brain-url "http://[::1]:31337/""#);
|
eprintln!(" detee-cli account network testnet");
|
||||||
} else {
|
} else {
|
||||||
account_data.brain_url = config.brain_url;
|
account_data.network = config.network;
|
||||||
}
|
}
|
||||||
if config.ssh_key_path.is_empty() {
|
if config.ssh_key_path.is_empty() {
|
||||||
log::error!("SSH public key path not set! To configure it, run:");
|
log::error!("SSH public key path not set! To configure it, run:");
|
||||||
@ -408,7 +418,7 @@ impl Config {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn hratls_key_path() -> Result<String, Error> {
|
pub fn hratls_key_path() -> Result<String, Error> {
|
||||||
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<String, Error> {
|
pub fn mrsigner_key_path() -> Result<String, Error> {
|
||||||
Ok(Self::path_dir()? + ("/app_signing_key.pem"))
|
Ok(Self::cli_dir_path()? + ("/app_signing_key.pem"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,9 +55,9 @@ pub fn handle_account(matches: &ArgMatches) {
|
|||||||
let path: String = path_subcommand.get_one::<String>("path").unwrap().clone();
|
let path: String = path_subcommand.get_one::<String>("path").unwrap().clone();
|
||||||
config::Config::set_ssh_pubkey_path(&path);
|
config::Config::set_ssh_pubkey_path(&path);
|
||||||
}
|
}
|
||||||
Some(("brain-url", path_subcommand)) => {
|
Some(("network", path_subcommand)) => {
|
||||||
let url: String = path_subcommand.get_one::<String>("url").unwrap().clone();
|
let name: String = path_subcommand.get_one::<String>("name").unwrap().clone();
|
||||||
config::Config::set_brain_url(&url);
|
config::Config::set_network(&name);
|
||||||
}
|
}
|
||||||
_ => cli_print(Ok(config::Config::get_account_data())),
|
_ => cli_print(Ok(config::Config::get_account_data())),
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ use crate::utils::sign_request;
|
|||||||
use detee_shared::general_proto::ReportNodeReq;
|
use detee_shared::general_proto::ReportNodeReq;
|
||||||
use log::{debug, info, warn};
|
use log::{debug, info, warn};
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
use tonic::transport::{Certificate, Channel, ClientTlsConfig};
|
||||||
|
|
||||||
pub mod proto {
|
pub mod proto {
|
||||||
pub use detee_shared::common_proto::*;
|
pub use detee_shared::common_proto::*;
|
||||||
@ -27,20 +28,40 @@ pub enum Error {
|
|||||||
InternalError(#[from] crate::utils::Error),
|
InternalError(#[from] crate::utils::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ConfigError(#[from] crate::config::Error),
|
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<BrainGeneralCliClient<Channel>, 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<AccountBalance, Error> {
|
pub async fn get_balance(account: &str) -> Result<AccountBalance, Error> {
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
|
||||||
let response =
|
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:?}");
|
log::info!("Received account from brain: {response:?}");
|
||||||
Ok(response.into_inner())
|
Ok(response.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn register_operator(escrow: u64, email: String) -> Result<(), Error> {
|
pub async fn register_operator(escrow: u64, email: String) -> Result<(), Error> {
|
||||||
debug!("Connecting to brain to register operator...");
|
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 {
|
.register_operator(sign_request(RegOperatorReq {
|
||||||
pubkey: Config::get_detee_wallet()?,
|
pubkey: Config::get_detee_wallet()?,
|
||||||
escrow,
|
escrow,
|
||||||
@ -52,15 +73,14 @@ pub async fn register_operator(escrow: u64, email: String) -> Result<(), Error>
|
|||||||
|
|
||||||
pub async fn inspect_operator(wallet: String) -> Result<InspectOperatorResp, Error> {
|
pub async fn inspect_operator(wallet: String) -> Result<InspectOperatorResp, Error> {
|
||||||
debug!("Getting information about operator {wallet} from brain.");
|
debug!("Getting information about operator {wallet} from brain.");
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
Ok(client().await?.inspect_operator(Pubkey { pubkey: wallet }).await?.into_inner())
|
||||||
Ok(client.inspect_operator(Pubkey { pubkey: wallet }).await?.into_inner())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_operators() -> Result<Vec<ListOperatorsResp>, Error> {
|
pub async fn list_operators() -> Result<Vec<ListOperatorsResp>, Error> {
|
||||||
debug!("Getting contracts from brain...");
|
debug!("Getting contracts from brain...");
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
|
||||||
let mut operators = Vec::new();
|
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 {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
Ok(op) => {
|
Ok(op) => {
|
||||||
@ -77,8 +97,8 @@ pub async fn list_operators() -> Result<Vec<ListOperatorsResp>, Error> {
|
|||||||
|
|
||||||
pub async fn kick_contract(contract_uuid: String, reason: String) -> Result<u64, Error> {
|
pub async fn kick_contract(contract_uuid: String, reason: String) -> Result<u64, Error> {
|
||||||
debug!("gRPC module: connecting to brain and kicking contract {contract_uuid} for reason: {reason}");
|
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 {
|
.kick_contract(sign_request(KickReq {
|
||||||
operator_wallet: Config::get_detee_wallet()?,
|
operator_wallet: Config::get_detee_wallet()?,
|
||||||
contract_uuid,
|
contract_uuid,
|
||||||
@ -91,8 +111,8 @@ pub async fn kick_contract(contract_uuid: String, reason: String) -> Result<u64,
|
|||||||
|
|
||||||
pub async fn ban_user(user_wallet: String) -> Result<(), Error> {
|
pub async fn ban_user(user_wallet: String) -> Result<(), Error> {
|
||||||
debug!("Connecting to brain to ban user...");
|
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 {
|
.ban_user(sign_request(BanUserReq {
|
||||||
operator_wallet: Config::get_detee_wallet()?,
|
operator_wallet: Config::get_detee_wallet()?,
|
||||||
user_wallet,
|
user_wallet,
|
||||||
@ -107,8 +127,8 @@ pub async fn report_node(
|
|||||||
reason: String,
|
reason: String,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
debug!("Getting contracts from brain...");
|
debug!("Getting contracts from brain...");
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
client()
|
||||||
client
|
.await?
|
||||||
.report_node(sign_request(ReportNodeReq {
|
.report_node(sign_request(ReportNodeReq {
|
||||||
admin_pubkey: Config::get_detee_wallet()?,
|
admin_pubkey: Config::get_detee_wallet()?,
|
||||||
node_pubkey,
|
node_pubkey,
|
||||||
@ -122,9 +142,9 @@ pub async fn report_node(
|
|||||||
// super admin
|
// super admin
|
||||||
|
|
||||||
pub async fn admin_list_accounts() -> Result<Vec<Account>, Error> {
|
pub async fn admin_list_accounts() -> Result<Vec<Account>, Error> {
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
|
||||||
let mut accounts = Vec::new();
|
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 {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
Ok(account) => {
|
Ok(account) => {
|
||||||
@ -141,9 +161,8 @@ pub async fn admin_list_accounts() -> Result<Vec<Account>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn admin_list_contracts() -> Result<Vec<VmContract>, Error> {
|
pub async fn admin_list_contracts() -> Result<Vec<VmContract>, Error> {
|
||||||
let mut client = BrainGeneralCliClient::connect(Config::get_brain_url()).await?;
|
|
||||||
let mut contracts = Vec::new();
|
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 {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
Ok(contract) => {
|
Ok(contract) => {
|
||||||
@ -160,15 +179,13 @@ pub async fn admin_list_contracts() -> Result<Vec<VmContract>, Error> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn admin_airdrop(pubkey: String, tokens: u64) -> 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 req = sign_request(AirdropReq { pubkey, tokens })?;
|
||||||
let _ = client.airdrop(req).await?;
|
let _ = client().await?.airdrop(req).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn admin_slash(pubkey: String, tokens: u64) -> Result<(), Error> {
|
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 req = sign_request(SlashReq { pubkey, tokens })?;
|
||||||
let _ = client.slash(req).await?;
|
let _ = client().await?.slash(req).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,7 @@ use detee_shared::app_proto::{
|
|||||||
};
|
};
|
||||||
use detee_shared::sgx::types::brain::AppDeployConfig;
|
use detee_shared::sgx::types::brain::AppDeployConfig;
|
||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
|
use tonic::transport::{Certificate, Channel, ClientTlsConfig};
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::Config;
|
||||||
use crate::sgx::utils::calculate_nanolp_for_app;
|
use crate::sgx::utils::calculate_nanolp_for_app;
|
||||||
@ -20,6 +21,10 @@ pub enum Error {
|
|||||||
InternalError(#[from] utils::Error),
|
InternalError(#[from] utils::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
ConfigError(#[from] crate::config::Error),
|
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<T> = std::result::Result<T, Error>;
|
type Result<T> = std::result::Result<T, Error>;
|
||||||
@ -60,6 +65,23 @@ impl crate::HumanOutput for AppContract {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn client() -> Result<BrainAppCliClient<Channel>> {
|
||||||
|
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<NewAppRes> {
|
pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result<NewAppRes> {
|
||||||
let resource = app_deploy_config.clone().resource;
|
let resource = app_deploy_config.clone().resource;
|
||||||
let mut req: NewAppReq = app_deploy_config.clone().into();
|
let mut req: NewAppReq = app_deploy_config.clone().into();
|
||||||
@ -77,21 +99,19 @@ pub async fn new_app(app_deploy_config: AppDeployConfig) -> Result<NewAppRes> {
|
|||||||
req.admin_pubkey = Config::get_detee_wallet()?;
|
req.admin_pubkey = Config::get_detee_wallet()?;
|
||||||
req.hratls_pubkey = Config::get_hratls_pubkey_hex()?;
|
req.hratls_pubkey = Config::get_hratls_pubkey_hex()?;
|
||||||
|
|
||||||
let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?;
|
let res = client().await?.deploy_app(sign_request(req)?).await?;
|
||||||
let res = daemon_serivce.deploy_app(sign_request(req)?).await?;
|
|
||||||
Ok(res.into_inner())
|
Ok(res.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_app(app_uuid: String) -> Result<()> {
|
pub async fn delete_app(app_uuid: String) -> Result<()> {
|
||||||
let admin_pubkey = Config::get_detee_wallet()?;
|
let admin_pubkey = Config::get_detee_wallet()?;
|
||||||
let delete_req = DelAppReq { uuid: app_uuid, admin_pubkey };
|
let delete_req = DelAppReq { uuid: app_uuid, admin_pubkey };
|
||||||
let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?;
|
let _ = client().await?.delete_app(sign_request(delete_req)?).await?;
|
||||||
let _ = daemon_serivce.delete_app(sign_request(delete_req)?).await?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn list_contracts(req: ListAppContractsReq) -> Result<Vec<AppContract>> {
|
pub async fn list_contracts(req: ListAppContractsReq) -> Result<Vec<AppContract>> {
|
||||||
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 res_stream = daemon_serivce.list_app_contracts(sign_request(req)?).await?.into_inner();
|
||||||
|
|
||||||
let mut app_contracts = vec![];
|
let mut app_contracts = vec![];
|
||||||
@ -111,17 +131,14 @@ pub async fn list_contracts(req: ListAppContractsReq) -> Result<Vec<AppContract>
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_one_app_node(req: AppNodeFilters) -> Result<AppNodeListResp> {
|
pub async fn get_one_app_node(req: AppNodeFilters) -> Result<AppNodeListResp> {
|
||||||
let mut daemon_serivce = BrainAppCliClient::connect(Config::get_brain_url()).await?;
|
let res = client().await?.get_one_app_node(sign_request(req)?).await?;
|
||||||
let res = daemon_serivce.get_one_app_node(sign_request(req)?).await?;
|
|
||||||
|
|
||||||
Ok(res.into_inner())
|
Ok(res.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_app_node_list(req: AppNodeFilters) -> Result<Vec<AppNodeListResp>> {
|
pub async fn get_app_node_list(req: AppNodeFilters) -> Result<Vec<AppNodeListResp>> {
|
||||||
log::debug!("Getting app nodes from brain...");
|
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 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 {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
match stream_update {
|
match stream_update {
|
||||||
|
@ -17,9 +17,9 @@ use crate::sgx::utils::hratls_url_and_mr_enclave_from_app_id;
|
|||||||
|
|
||||||
#[derive(thiserror::Error, Debug)]
|
#[derive(thiserror::Error, Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
#[error("Failed to connect to the dtpm: {0}")]
|
#[error("Failed to connect to DTPM: {0}")]
|
||||||
BrainConnection(#[from] tonic::transport::Error),
|
DtpmConnection(#[from] tonic::transport::Error),
|
||||||
#[error("Received error from dtpm: {}", _0.message())]
|
#[error("Received error from DTPM: {}", _0.message())]
|
||||||
ResponseStatus(#[from] tonic::Status),
|
ResponseStatus(#[from] tonic::Status),
|
||||||
#[error("Hex: {0}")]
|
#[error("Hex: {0}")]
|
||||||
HexDecode(#[from] hex::FromHexError),
|
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)?;
|
hex::decode_to_slice(Config::get_mrsigner()?, &mut mr_signer)?;
|
||||||
let mr_signers = vec![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(
|
let hratls_config = Arc::new(RwLock::new(
|
||||||
HRaTlsConfig::new()
|
HRaTlsConfig::new()
|
||||||
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(mr_signers))
|
.allow_instance_measurement(InstanceMeasurement::new().with_mrsigners(mr_signers))
|
||||||
|
@ -13,6 +13,7 @@ use proto::{
|
|||||||
use tokio_stream::StreamExt;
|
use tokio_stream::StreamExt;
|
||||||
use tonic::metadata::errors::InvalidMetadataValue;
|
use tonic::metadata::errors::InvalidMetadataValue;
|
||||||
use tonic::metadata::AsciiMetadataValue;
|
use tonic::metadata::AsciiMetadataValue;
|
||||||
|
use tonic::transport::{Certificate, Channel, ClientTlsConfig};
|
||||||
use tonic::Request;
|
use tonic::Request;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@ -35,7 +36,11 @@ pub enum Error {
|
|||||||
#[error("Could not find contract {0}")]
|
#[error("Could not find contract {0}")]
|
||||||
VmContractNotFound(String),
|
VmContractNotFound(String),
|
||||||
#[error(transparent)]
|
#[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 {
|
impl crate::HumanOutput for VmContract {
|
||||||
@ -78,6 +83,23 @@ impl crate::HumanOutput for VmNodeListResp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn client() -> Result<BrainVmCliClient<Channel>, 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<T: std::fmt::Debug>(req: T) -> Result<Request<T>, Error> {
|
fn sign_request<T: std::fmt::Debug>(req: T) -> Result<Request<T>, Error> {
|
||||||
let pubkey = Config::get_detee_wallet()?;
|
let pubkey = Config::get_detee_wallet()?;
|
||||||
let timestamp = chrono::Utc::now().to_rfc3339();
|
let timestamp = chrono::Utc::now().to_rfc3339();
|
||||||
@ -94,7 +116,7 @@ fn sign_request<T: std::fmt::Debug>(req: T) -> Result<Request<T>, Error> {
|
|||||||
|
|
||||||
pub async fn get_node_list(req: VmNodeFilters) -> Result<Vec<VmNodeListResp>, Error> {
|
pub async fn get_node_list(req: VmNodeFilters) -> Result<Vec<VmNodeListResp>, Error> {
|
||||||
debug!("Getting nodes from brain...");
|
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 nodes = Vec::new();
|
||||||
let mut grpc_stream = client.list_vm_nodes(sign_request(req)?).await?.into_inner();
|
let mut grpc_stream = client.list_vm_nodes(sign_request(req)?).await?.into_inner();
|
||||||
while let Some(stream_update) = grpc_stream.next().await {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
@ -113,13 +135,13 @@ pub async fn get_node_list(req: VmNodeFilters) -> Result<Vec<VmNodeListResp>, Er
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_one_node(req: VmNodeFilters) -> Result<VmNodeListResp, Error> {
|
pub async fn get_one_node(req: VmNodeFilters) -> Result<VmNodeListResp, Error> {
|
||||||
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?;
|
let response = client.get_one_vm_node(sign_request(req)?).await?;
|
||||||
Ok(response.into_inner())
|
Ok(response.into_inner())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn create_vm(req: NewVmReq) -> Result<NewVmResp, Error> {
|
pub async fn create_vm(req: NewVmReq) -> Result<NewVmResp, Error> {
|
||||||
let mut client = BrainVmCliClient::connect(Config::get_brain_url()).await?;
|
let mut client = client().await?;
|
||||||
debug!("Sending NewVmReq to brain: {req:?}");
|
debug!("Sending NewVmReq to brain: {req:?}");
|
||||||
match client.new_vm(sign_request(req)?).await {
|
match client.new_vm(sign_request(req)?).await {
|
||||||
Ok(resp) => Ok(resp.into_inner()),
|
Ok(resp) => Ok(resp.into_inner()),
|
||||||
@ -129,7 +151,7 @@ pub async fn create_vm(req: NewVmReq) -> Result<NewVmResp, Error> {
|
|||||||
|
|
||||||
pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>, Error> {
|
pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>, Error> {
|
||||||
debug!("Getting contracts from brain...");
|
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 contracts = Vec::new();
|
||||||
let mut grpc_stream = client.list_vm_contracts(sign_request(req)?).await?.into_inner();
|
let mut grpc_stream = client.list_vm_contracts(sign_request(req)?).await?.into_inner();
|
||||||
while let Some(stream_update) = grpc_stream.next().await {
|
while let Some(stream_update) = grpc_stream.next().await {
|
||||||
@ -148,7 +170,7 @@ pub async fn list_contracts(req: ListVmContractsReq) -> Result<Vec<VmContract>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn delete_vm(uuid: &str) -> Result<(), Error> {
|
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 req = DeleteVmReq { uuid: uuid.to_string(), admin_pubkey: Config::get_detee_wallet()? };
|
||||||
let result = client.delete_vm(sign_request(req)?).await;
|
let result = client.delete_vm(sign_request(req)?).await;
|
||||||
match result {
|
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> {
|
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 req = ExtendVmReq { admin_pubkey, uuid, locked_nano };
|
||||||
let result = client.extend_vm(sign_request(req)?).await;
|
let result = client.extend_vm(sign_request(req)?).await;
|
||||||
match result {
|
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<UpdateVmResp, Error> {
|
pub async fn update_vm(req: UpdateVmReq) -> Result<UpdateVmResp, Error> {
|
||||||
info!("Updating VM {req:?}");
|
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;
|
let result = client.update_vm(sign_request(req)?).await;
|
||||||
match result {
|
match result {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
|
Loading…
Reference in New Issue
Block a user