agnos 0.1.1

Obtain (wildcard) certificates from let's encrypt using dns-01 without the need for API access to your DNS provider.
Documentation
use std::io::Write;

use agnos::{config::Config, main_logic::create_restricted_file};
use clap::{Arg, ArgAction};

fn main() -> anyhow::Result<()> {
    let mut stdin_lines = std::io::stdin().lines();
    let cli_ops = clap::command!()
        .about("Generate non existing private accounts keys from agnos' configuration.")
        .arg_required_else_help(true)
        .arg(
            Arg::new("config")
                .required(true)
                .action(ArgAction::Set)
                .value_name("config.toml")
                .help("Path to the configuration file."),
        )
        .arg(
            Arg::new("key-size")
                .long("key-size")
                .action(ArgAction::Set)
                .default_value("4096")
                .help("Size in bits of the RSA private key.")
                .value_parser(clap::value_parser!(u32)),
        )
        .arg(
            Arg::new("no-confirm")
                .long("no-confirm")
                .action(ArgAction::SetTrue)
                .help("Do not prompt user and create all non-existing keys."),
        )
        .get_matches();
    let key_size = cli_ops.get_one("key-size").unwrap();
    let no_confirm = cli_ops.get_flag("no-confirm");
    let config_file = std::fs::read_to_string(cli_ops.get_one::<String>("config").unwrap())?;
    let config: Config = toml::from_str(&config_file)?;
    'accounts_loop: for account in config.accounts {
        if !account.private_key_path.exists() {
            println!(
                "Private key for account <{}> expected to be located at {} does not exist.",
                account.email,
                account.private_key_path.display()
            );
            if !no_confirm {
                'input_loop: loop {
                    print!("Do you want to create it? (y(es) | n(o) -- default: yes)? ");
                    std::io::stdout().flush()?;
                    let l = match stdin_lines.next() {
                        None => return Ok(()),
                        Some(l) => l?,
                    };
                    match l.trim() {
                        "" | "y" | "yes" | "Y" | "YES" => break 'input_loop,
                        "n" | "no" | "N" | "NO" => continue 'accounts_loop,
                        _ => continue 'input_loop,
                    }
                }
            }
            print!("Generating private key... ");
            std::io::stdout().flush()?;
            let key = openssl::rsa::Rsa::generate(*key_size)?;
            let pem = key.private_key_to_pem()?;
            let mut key_file: std::fs::File = create_restricted_file(account.private_key_path)?;
            key_file.write_all(&pem)?;
            println!("Private key generated!")
        }
    }
    Ok(())
}