Files
leonwww/protocol/gurtca/src/main.rs
2025-09-07 20:11:28 +03:00

106 lines
2.9 KiB
Rust

use clap::{Parser, Subcommand};
use anyhow::Result;
mod challenges;
mod crypto;
mod client;
#[derive(Parser)]
#[command(name = "gurtca")]
#[command(about = "Gurted Certificate Authority CLI - Get TLS certificates for your domains")]
struct Cli {
#[command(subcommand)]
command: Commands,
#[arg(long, default_value = "gurt://dns.web")]
ca_url: String,
}
#[derive(Subcommand)]
enum Commands {
Request {
domain: String,
#[arg(long, default_value = "./certs")]
output: String,
},
GetCa {
#[arg(long, default_value = "./ca.crt")]
output: String,
},
}
#[tokio::main]
async fn main() -> Result<()> {
let cli = Cli::parse();
let client = client::GurtCAClient::new_with_ca_discovery(cli.ca_url).await?;
match cli.command {
Commands::Request { domain, output } => {
println!("🔐 Requesting certificate for: {}", domain);
request_certificate(&client, &domain, &output).await?;
},
Commands::GetCa { output } => {
println!("📋 Fetching CA certificate from server...");
get_ca_certificate(&client, &output).await?;
},
}
Ok(())
}
async fn request_certificate(
client: &client::GurtCAClient,
domain: &str,
output_dir: &str
) -> Result<()> {
println!("🔍 Verifying domain exists...");
if !client.verify_domain_exists(domain).await? {
anyhow::bail!("❌ Domain does not exist or is not approved: {}", domain);
}
println!("🔑 Generating key pair...");
let (private_key, csr) = crypto::generate_key_and_csr(domain)?;
println!("📝 Submitting certificate request...");
let challenge = client.request_certificate(domain, &csr).await?;
println!("🧩 Completing DNS challenge...");
challenges::complete_dns_challenge(&challenge, client).await?;
println!("⏳ Waiting for certificate issuance...");
let certificate = client.poll_certificate(&challenge.token).await?;
println!("💾 Saving certificate files...");
std::fs::create_dir_all(output_dir)?;
std::fs::write(
format!("{}/{}.crt", output_dir, domain),
certificate.cert_pem
)?;
std::fs::write(
format!("{}/{}.key", output_dir, domain),
private_key
)?;
println!("✅ Certificate successfully issued for: {}", domain);
println!("📁 Files saved to: {}", output_dir);
println!(" - Certificate: {}/{}.crt", output_dir, domain);
println!(" - Private Key: {}/{}.key", output_dir, domain);
Ok(())
}
async fn get_ca_certificate(
client: &client::GurtCAClient,
output_path: &str
) -> Result<()> {
let ca_cert = client.fetch_ca_certificate().await?;
std::fs::write(output_path, &ca_cert)?;
println!("✅ CA certificate saved to: {}", output_path);
Ok(())
}