use std::error::Error; use std::fs; use clap::{Parser, Subcommand}; use ipnet::Ipv4Net; use url::Url; use crate::account::account_main; use crate::network::network_main; use crate::org::org_main; pub mod account; pub mod api; pub mod network; pub mod org; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] #[command(propagate_version = true)] pub struct Args { #[command(subcommand)] command: Commands, #[clap(short, long, env = "TFCLI_SERVER")] /// The base URL of your trifid-api instance. Defaults to the value in $XDG_CONFIG_HOME/tfcli-server-url.conf or the TFCLI_SERVER environment variable. server: Option } #[derive(Subcommand, Debug)] pub enum Commands { /// Manage your trifid account Account { #[command(subcommand)] command: AccountCommands }, /// Manage the networks associated with your trifid account Network { #[command(subcommand)] command: NetworkCommands }, /// Manage the organization associated with your trifid account Org { #[command(subcommand)] command: OrgCommands } } #[derive(Subcommand, Debug)] pub enum AccountCommands { /// Create a new trifid account on the designated server Create { #[clap(short, long)] email: String }, /// Log in to your account with a magic-link token acquired via email or the trifid-api logs. MagicLink { #[clap(short, long)] magic_link_token: String }, /// Create a new TOTP authenticator on this account to enable authorizing with 2fa and performing all management tasks. MfaSetup {}, /// Finish creating a new TOTP authenticator by inputting the code shown on your authenticator app. MfaSetupFinish { #[clap(short, long)] code: String, #[clap(short, long)] token: String }, /// Create a new short-lived authentication token by inputting the code shown on your authenticator app. Mfa { #[clap(short, long)] code: String } } #[derive(Subcommand, Debug)] pub enum NetworkCommands { /// List all networks associated with your trifid account. List {}, /// Lookup a specific network by ID. Lookup { #[clap(short, long)] id: String } } #[derive(Subcommand, Debug)] pub enum OrgCommands { /// Create an organization on your trifid-api server. NOTE: This command ONLY works on trifid-api servers. It will NOT work on original DN servers. Create { #[clap(short, long)] cidr: Ipv4Net } } #[tokio::main] async fn main() { match main2().await { Ok(_) => (), Err(e) => { eprintln!("There was an error during execution: {}", e); std::process::exit(1); } } } async fn main2() -> Result<(), Box> { let args = Args::parse(); // find server let server; if let Some(srv) = args.server { server = srv; // Environment variable or CLI takes precedence over config file } else { let srv_url_file = dirs::config_dir().unwrap().join("tfcli-server-url.conf"); if !srv_url_file.exists() { eprintln!("[error] no server URL available: '-s/--server' not provided, TFCLI_SERVER not set, and {} does not exist", srv_url_file.display()); eprintln!("[error] please set a server url via any of these mechanisms and try again"); std::process::exit(1); } let url_s = fs::read_to_string(&srv_url_file)?; let url = match Url::parse(&url_s) { Ok(u) => u, Err(e) => { eprintln!("[error] unable to parse the URL in {}", srv_url_file.display()); eprintln!("[error] urlparse returned error '{}'", e); eprintln!("[error] please correct the error and try again"); std::process::exit(1); } }; server = url; } match args.command { Commands::Account { command } => account_main(command, server).await, Commands::Network { command } => network_main(command, server).await, Commands::Org { command } => org_main(command, server).await } }