// SPDX-License-Identifier: Apache-2.0 use anyhow::Result; use ed25519_dalek::SigningKey; use lazy_static::lazy_static; use log::{info, warn}; use rand::Rng; use sha2::{Digest, Sha256}; use std::{ fs::File, io::{Read, Write}, sync::LazyLock, }; pub(crate) const DETEE_ROOT_CA: &str = "/etc/detee/root_ca.pem"; pub(crate) const BRAIN_STAGING_URLS: [&str; 3] = ["https://184.107.169.199:49092", "https://149.22.95.1:47855", "https://149.36.48.99:48843"]; pub(crate) const BRAIN_TESTING_URLS: [&str; 3] = ["https://184.107.169.199:45223", "https://149.22.95.1:44522", "https://149.36.48.99:48638"]; pub(crate) const VM_BOOT_DIR: &str = "/var/lib/detee/boot/"; pub(crate) const USED_RESOURCES: &str = "/etc/detee/daemon/used_resources.yaml"; pub(crate) const VM_CONFIG_DIR: &str = "/etc/detee/daemon/vms/"; pub(crate) const SECRET_KEY_PATH: &str = "/etc/detee/daemon/node_secret_key.pem"; pub(crate) const DAEMON_CONFIG_PATH: &str = "/etc/detee/daemon/config.yaml"; pub(crate) const START_VM_SCRIPT: &str = "/usr/local/bin/detee/start_qemu_vm.sh"; // TODO: research if other CPU types provide better performance pub(crate) const QEMU_VM_CPU_TYPE: &str = "EPYC-v4"; // If you modify this, also modify scripts/start_qemu_vm.sh pub(crate) const OVMF_HASH: &str = "0346619257269b9a61ee003e197d521b8e2283483070d163a34940d6a1d40d76"; pub(crate) const OVMF_URL: &str = "https://drive.google.com/uc?export=download&id=1V-vLkaiLaGmFSjrN84Z6nELQOxKNAoSJ"; pub static BRAIN_STAGING: LazyLock<(&str, &str)> = LazyLock::new(|| { (BRAIN_STAGING_URLS[rand::thread_rng().gen_range(0..BRAIN_STAGING_URLS.len())], "staging-brain") }); pub static BRAIN_TESTING: LazyLock<(&str, &str)> = LazyLock::new(|| { (BRAIN_TESTING_URLS[rand::thread_rng().gen_range(0..BRAIN_TESTING_URLS.len())], "testnet-brain") }); lazy_static! { pub static ref PUBLIC_KEY: String = get_public_key(); pub static ref IP_INFO: IPInfo = get_ip_info().unwrap(); } fn create_secret_key() -> Result { let key_path = SECRET_KEY_PATH; info!("Creating new secret key at {}", key_path); let sk = ed25519_dalek::SigningKey::generate(&mut rand_core::OsRng); let private_key_string = bs58::encode(sk.to_bytes()).into_string(); let mut file = File::create(key_path)?; file.write_all(private_key_string.as_bytes())?; Ok(sk) } fn load_secret_key() -> Result { let secret_key_string = match std::fs::read_to_string(SECRET_KEY_PATH) { Ok(secret_key_pem) => secret_key_pem, Err(e) => { warn!("Could not load secret key due to error: {e:?}"); return Ok(create_secret_key()?); } }; Ok(SigningKey::from_bytes( &bs58::decode(secret_key_string) .into_vec()? .try_into() .map_err(|_| bs58::decode::Error::BufferTooSmall)?, )) } pub fn sign_message(msg: &str) -> Result { use ed25519_dalek::Signer; let key = load_secret_key()?; Ok(bs58::encode(key.sign(msg.as_bytes()).to_bytes()).into_string()) } pub fn get_public_key() -> String { let pubkey = bs58::encode(load_secret_key().unwrap().verifying_key().to_bytes()).into_string(); log::info!("Loaded the following public key: {pubkey}"); pubkey } #[derive(serde::Deserialize, Clone)] pub struct IPInfo { pub country: String, pub region: String, pub city: String, pub ip: String, } fn get_ip_info() -> anyhow::Result { let body = reqwest::blocking::get("https://ipinfo.io/".to_string())?.text()?; info!("Got the following data from ipinfo.io: {body}"); Ok(serde_json::de::from_str(&body)?) } pub fn compute_sha256>(path: P) -> Result { let mut file = File::open(path)?; let mut hasher = Sha256::new(); let mut buffer = [0u8; 8192]; loop { let bytes_read = file.read(&mut buffer)?; if bytes_read == 0 { break; } hasher.update(&buffer[..bytes_read]); } let result = hasher.finalize(); Ok(format!("{:x}", result)) }