use clap::Parser;
use fastcert::Result;
const AFTER_HELP: &str = "\
EXAMPLES:
$ fastcert --install
Install the local CA in the system trust store.
$ fastcert example.org
Generate \"example.org.pem\" and \"example.org-key.pem\".
$ fastcert example.com myapp.dev localhost 127.0.0.1 ::1
Generate \"example.com+4.pem\" and \"example.com+4-key.pem\".
$ fastcert \"*.example.it\"
Generate \"_wildcard.example.it.pem\" and \"_wildcard.example.it-key.pem\".
$ fastcert --uninstall
Uninstall the local CA (but do not delete it).
ENVIRONMENT:
CAROOT
Set the CA certificate and key storage location. (This allows
maintaining multiple local CAs in parallel.)
TRUST_STORES
A comma-separated list of trust stores to install the local
root CA into. Options are: \"system\", \"java\" and \"nss\" (includes
Firefox). Autodetected by default.
";
#[derive(Parser, Debug)]
#[command(name = "fastcert")]
#[command(version)]
#[command(about = "A simple zero-config tool to make locally-trusted development certificates")]
#[command(after_help = AFTER_HELP)]
struct Cli {
#[arg(long)]
install: bool,
#[arg(long)]
uninstall: bool,
#[arg(long = "CAROOT")]
caroot: bool,
#[arg(long = "cert-file", value_name = "FILE")]
cert_file: Option<String>,
#[arg(long = "key-file", value_name = "FILE")]
key_file: Option<String>,
#[arg(long = "p12-file", value_name = "FILE")]
p12_file: Option<String>,
#[arg(long)]
client: bool,
#[arg(long)]
ecdsa: bool,
#[arg(long)]
pkcs12: bool,
#[arg(long, value_name = "CSR")]
csr: Option<String>,
#[arg(short, long)]
verbose: bool,
#[arg(long)]
debug: bool,
#[arg(short, long)]
quiet: bool,
#[arg(value_name = "DOMAINS")]
domains: Vec<String>,
}
fn main() -> Result<()> {
let cli = Cli::parse();
if cli.verbose {
unsafe {
std::env::set_var("RSCERT_VERBOSE", "1");
}
}
if cli.debug {
unsafe {
std::env::set_var("RSCERT_DEBUG", "1");
std::env::set_var("RSCERT_VERBOSE", "1");
}
}
if cli.quiet {
unsafe {
std::env::set_var("RSCERT_QUIET", "1");
}
}
if cli.caroot {
if cli.install || cli.uninstall {
eprintln!("ERROR: you can't set --install/--uninstall and --CAROOT at the same time");
std::process::exit(1);
}
println!("{}", fastcert::ca::get_caroot()?);
return Ok(());
}
if cli.install && cli.uninstall {
eprintln!("ERROR: you can't set --install and --uninstall at the same time");
std::process::exit(1);
}
if cli.csr.is_some() {
if cli.pkcs12 || cli.ecdsa || cli.client {
eprintln!("ERROR: can only combine --csr with --install and --cert-file");
std::process::exit(1);
}
if !cli.domains.is_empty() {
eprintln!("ERROR: can't specify extra arguments when using --csr");
std::process::exit(1);
}
}
if !cli.install && !cli.uninstall && cli.domains.is_empty() && cli.csr.is_none() {
Cli::parse_from(["fastcert", "--help"]);
return Ok(());
}
if cli.install {
fastcert::ca::install()?;
if cli.domains.is_empty() && cli.csr.is_none() {
return Ok(());
}
}
if cli.uninstall {
fastcert::ca::uninstall()?;
return Ok(());
}
if let Some(csr_path) = cli.csr {
fastcert::cert::generate_from_csr(&csr_path, cli.cert_file.as_deref())?;
return Ok(());
}
if !cli.domains.is_empty() {
fastcert::cert::generate_certificate(
&cli.domains,
cli.cert_file.as_deref(),
cli.key_file.as_deref(),
cli.p12_file.as_deref(),
cli.client,
cli.ecdsa,
cli.pkcs12,
)?;
}
Ok(())
}