255 lines
7.5 KiB
Rust
255 lines
7.5 KiB
Rust
use std::error::Error;
|
|
use std::fs;
|
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
|
use clap::{Parser, Subcommand};
|
|
use ipnet::Ipv4Net;
|
|
use url::Url;
|
|
use crate::account::account_main;
|
|
use crate::host::host_main;
|
|
use crate::network::network_main;
|
|
use crate::org::org_main;
|
|
use crate::role::role_main;
|
|
|
|
pub mod account;
|
|
pub mod api;
|
|
pub mod network;
|
|
pub mod org;
|
|
pub mod role;
|
|
pub mod host;
|
|
|
|
#[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<Url>
|
|
}
|
|
|
|
#[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
|
|
},
|
|
/// Manage the roles associated with your trifid organization
|
|
Role {
|
|
#[command(subcommand)]
|
|
command: RoleCommands
|
|
},
|
|
/// Manage the hosts associated with your trifid network
|
|
Host {
|
|
#[command(subcommand)]
|
|
command: HostCommands
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
pub enum AccountCommands {
|
|
/// Create a new trifid account on the designated server
|
|
Create {
|
|
#[clap(short, long)]
|
|
email: String
|
|
},
|
|
/// Log into an existing account on the designated server
|
|
Login {
|
|
#[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
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
pub enum RoleCommands {
|
|
/// Create a role on your organization
|
|
Create {
|
|
#[clap(short, long)]
|
|
name: String,
|
|
#[clap(short, long)]
|
|
description: String,
|
|
/// A JSON string containing the firewall rules to add to this host
|
|
#[clap(short, long)]
|
|
rules_json: String
|
|
},
|
|
/// List all roles attached to your organization
|
|
List {},
|
|
/// Lookup a specific role by it's ID
|
|
Lookup {
|
|
#[clap(short, long)]
|
|
id: String
|
|
},
|
|
/// Delete a specific role by it's ID
|
|
Delete {
|
|
#[clap(short, long)]
|
|
id: String
|
|
},
|
|
/// Update a specific role by it's ID. Warning: any data not provided in this update will be removed - include all data you wish to remain
|
|
Update {
|
|
#[clap(short, long)]
|
|
id: String,
|
|
#[clap(short, long)]
|
|
description: String,
|
|
/// A JSON string containing the firewall rules to add to this host
|
|
#[clap(short, long)]
|
|
rules_json: String
|
|
}
|
|
}
|
|
|
|
#[derive(Subcommand, Debug)]
|
|
pub enum HostCommands {
|
|
/// Create a host on your network
|
|
Create {
|
|
#[clap(short, long)]
|
|
name: String,
|
|
#[clap(short = 'N', long)]
|
|
network_id: String,
|
|
#[clap(short, long)]
|
|
role_id: String,
|
|
#[clap(short, long)]
|
|
ip_address: Ipv4Addr,
|
|
#[clap(short, long)]
|
|
listen_port: Option<u16>,
|
|
#[clap(short = 'L', long)]
|
|
lighthouse: bool,
|
|
#[clap(short = 'R', long)]
|
|
relay: bool,
|
|
#[clap(short, long)]
|
|
static_address: Option<SocketAddrV4>
|
|
},
|
|
/// List all hosts on your network
|
|
List {},
|
|
/// Lookup a specific host by it's ID
|
|
Lookup {
|
|
#[clap(short, long)]
|
|
id: String
|
|
},
|
|
/// Delete a specific host by it's ID
|
|
Delete {
|
|
#[clap(short, long)]
|
|
id: String
|
|
},
|
|
/// Update a specific host by it's ID, changing the listen port and static addresses, as well as the name, ip and role. The name, ip and role updates will only work on trifid-api compatible servers.
|
|
Update {
|
|
#[clap(short, long)]
|
|
id: String,
|
|
#[clap(short, long)]
|
|
listen_port: Option<u16>,
|
|
#[clap(short, long)]
|
|
static_address: Option<SocketAddrV4>,
|
|
#[clap(short, long)]
|
|
name: Option<String>,
|
|
#[clap(short, long)]
|
|
role: Option<String>,
|
|
#[clap(short = 'I', long)]
|
|
ip: Option<Ipv4Addr>
|
|
},
|
|
/// Blocks the specified host from the network
|
|
Block {
|
|
#[clap(short, long)]
|
|
id: String
|
|
},
|
|
/// Enroll or re-enroll the host by generating an enrollment code
|
|
Enroll {
|
|
#[clap(short, long)]
|
|
id: String
|
|
}
|
|
}
|
|
|
|
#[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<dyn Error>> {
|
|
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,
|
|
Commands::Role { command } => role_main(command, server).await,
|
|
Commands::Host { command } => host_main(command, server).await
|
|
}
|
|
} |