secretumvault/src/main.rs

268 lines
8.6 KiB
Rust
Raw Normal View History

2025-12-22 21:34:01 +00:00
#[cfg(feature = "cli")]
use std::path::PathBuf;
#[cfg(feature = "cli")]
use std::sync::Arc;
2025-12-22 21:34:01 +00:00
#[cfg(feature = "cli")]
use clap::Parser;
2025-12-22 21:34:01 +00:00
#[cfg(feature = "cli")]
use secretumvault::cli::{Cli, Command, OperatorCommand, SecretCommand};
#[cfg(feature = "cli")]
use secretumvault::config::VaultConfig;
#[cfg(feature = "cli")]
use secretumvault::core::VaultCore;
#[tokio::main]
#[cfg(feature = "cli")]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let cli = Cli::parse();
// Set up logging
tracing_subscriber::fmt()
.with_max_level(
cli.log_level
.parse::<tracing::Level>()
.unwrap_or(tracing::Level::INFO),
)
.init();
// Determine config path
let config_path = cli.config.unwrap_or_else(|| PathBuf::from("svault.toml"));
match cli.command {
Command::Server { address, port } => server_command(&config_path, &address, port).await?,
Command::Operator(cmd) => operator_command(&config_path, cmd).await?,
Command::Secret(cmd) => secret_command(cmd).await?,
}
Ok(())
}
#[cfg(feature = "cli")]
async fn server_command(
config_path: &PathBuf,
_address: &str,
_port: u16,
) -> Result<(), Box<dyn std::error::Error>> {
tracing::info!("Loading configuration from {:?}", config_path);
let config = VaultConfig::from_file(config_path)?;
let _vault = Arc::new(VaultCore::from_config(&config).await?);
tracing::info!("Vault initialized successfully");
#[cfg(feature = "server")]
{
eprintln!(
"Note: Server mode via CLI is limited. Use library API with --features server for \
full functionality including TLS."
);
2025-12-22 21:34:01 +00:00
eprintln!("Server feature not fully implemented in CLI mode.");
std::process::exit(1);
}
#[cfg(not(feature = "server"))]
{
tracing::error!("Server feature not enabled. Compile with --features server");
return Ok(());
}
#[allow(unreachable_code)]
Ok(())
}
#[cfg(feature = "cli")]
async fn operator_command(
config_path: &PathBuf,
cmd: OperatorCommand,
) -> Result<(), Box<dyn std::error::Error>> {
tracing::info!("Loading configuration from {:?}", config_path);
let config = VaultConfig::from_file(config_path)?;
let vault = Arc::new(VaultCore::from_config(&config).await?);
tracing::info!("Vault loaded successfully");
match cmd {
OperatorCommand::Init { shares, threshold } => {
tracing::info!(
"Initializing vault with {} shares, {} threshold",
shares,
threshold
);
match secretumvault::cli::commands::init_vault(&vault, shares, threshold).await {
Ok(share_list) => {
secretumvault::cli::commands::print_init_result(&share_list, threshold as u64);
tracing::info!("Vault initialized successfully");
}
Err(e) => {
tracing::error!("Failed to initialize vault: {}", e);
return Err(format!("Init failed: {}", e).into());
}
}
}
OperatorCommand::Unseal { shares } => {
tracing::info!("Unsealing vault with {} shares", shares.len());
match secretumvault::cli::commands::unseal_vault(&vault, &shares).await {
Ok(success) => {
if success {
println!("✓ Vault unsealed successfully!");
tracing::info!("Vault unsealed");
} else {
println!("✗ Vault is still sealed (more shares needed?)");
tracing::warn!("Vault still sealed");
}
}
Err(e) => {
tracing::error!("Failed to unseal vault: {}", e);
return Err(format!("Unseal failed: {}", e).into());
}
}
}
OperatorCommand::Seal => {
tracing::info!("Sealing vault");
match secretumvault::cli::commands::seal_vault(&vault).await {
Ok(()) => {
println!("✓ Vault sealed successfully!");
tracing::info!("Vault sealed");
}
Err(e) => {
tracing::error!("Failed to seal vault: {}", e);
return Err(format!("Seal failed: {}", e).into());
}
}
}
OperatorCommand::Status => {
tracing::info!("Checking vault status");
match secretumvault::cli::commands::vault_status(&vault).await {
Ok((sealed, initialized)) => {
secretumvault::cli::commands::print_status(sealed, initialized);
}
Err(e) => {
tracing::error!("Failed to get vault status: {}", e);
return Err(format!("Status check failed: {}", e).into());
}
}
}
}
Ok(())
}
#[cfg(feature = "cli")]
async fn secret_command(cmd: SecretCommand) -> Result<(), Box<dyn std::error::Error>> {
use secretumvault::cli::client::VaultClient;
match cmd {
SecretCommand::Read {
path,
address,
port,
token,
} => {
tracing::info!("Reading secret from {}:{}: {}", address, port, path);
let client = VaultClient::new(&address, port, token);
match client.read_secret(&path).await {
Ok(data) => {
println!("{}", serde_json::to_string_pretty(&data)?);
tracing::info!("Secret read successfully");
}
Err(e) => {
tracing::error!("Failed to read secret: {}", e);
return Err(format!("Read failed: {}", e).into());
}
}
}
SecretCommand::Write {
path,
data,
address,
port,
token,
} => {
tracing::info!("Writing secret to {}:{}: {}", address, port, path);
let client = VaultClient::new(&address, port, token);
let payload: serde_json::Value = serde_json::from_str(&data)?;
match client.write_secret(&path, &payload).await {
Ok(response) => {
println!("✓ Secret written successfully!");
if let Some(data) = response.get("data") {
println!("{}", serde_json::to_string_pretty(data)?);
}
tracing::info!("Secret written successfully");
}
Err(e) => {
tracing::error!("Failed to write secret: {}", e);
return Err(format!("Write failed: {}", e).into());
}
}
}
SecretCommand::Delete {
path,
address,
port,
token,
} => {
tracing::info!("Deleting secret from {}:{}: {}", address, port, path);
let client = VaultClient::new(&address, port, token);
match client.delete_secret(&path).await {
Ok(()) => {
println!("✓ Secret deleted successfully!");
tracing::info!("Secret deleted successfully");
}
Err(e) => {
tracing::error!("Failed to delete secret: {}", e);
return Err(format!("Delete failed: {}", e).into());
}
}
}
SecretCommand::List {
path,
address,
port,
token,
} => {
tracing::info!("Listing secrets at {}:{}: {}", address, port, path);
let client = VaultClient::new(&address, port, token);
match client.list_secrets(&path).await {
Ok(keys) => {
println!("\nSecrets at {}:", path);
println!("━━━━━━━━━━━━━━━━━━━━━━");
for key in keys {
println!(" {}", key);
}
println!();
tracing::info!("Secrets listed successfully");
}
Err(e) => {
tracing::error!("Failed to list secrets: {}", e);
return Err(format!("List failed: {}", e).into());
}
}
}
}
Ok(())
}
#[cfg(not(feature = "cli"))]
fn main() {
eprintln!("CLI feature not enabled. Compile with --features cli");
std::process::exit(1);
}