runewarp 0.1.0

Runewarp is an ingress tunneling tool for exposing local services without moving TLS termination to the edge. Clients connect out over QUIC, so you can publish services without putting your backend directly on the Internet or leaking your public IP.
Documentation
use std::path::PathBuf;

use clap::{Args, Parser, Subcommand};

const TOP_LEVEL_EXAMPLES: &str = "\
Examples:
  runewarp server
  runewarp client";

const SERVER_EXAMPLES: &str = "\
Examples:
  runewarp server
  runewarp server cert init --hostname tunnel.example.com";

const SERVER_CERT_EXAMPLES: &str = "\
Examples:
  runewarp server cert init --hostname tunnel.example.com
  runewarp server cert renew";

const CLIENT_EXAMPLES: &str = "\
Examples:
  runewarp client
  runewarp client --server-address tunnel.example.com --backend-address 127.0.0.1:443";

const CLIENT_IDENTITY_EXAMPLES: &str = "\
Examples:
  runewarp client identity init
  runewarp client identity show";

const CLIENT_IDENTITY_LEAF_EXAMPLES: &str = "\
Examples:
  runewarp client identity init --dir ./client-identity
  runewarp client identity show";

const CLIENT_PUBLIC_CERT_EXAMPLES: &str = "\
Examples:
  runewarp client public-cert init --hostname app.example.com
  runewarp client public-cert renew --hostname app.example.com";

const CLIENT_PUBLIC_CERT_ROTATE_CA_EXAMPLES: &str = "\
Examples:
  runewarp client public-cert rotate-ca
  runewarp client -c client.toml public-cert rotate-ca";

const SERVER_HEADER: &str = "Runewarp Server";
const SERVER_CERT_HEADER: &str = "Runewarp Server Certificates";
const CLIENT_HEADER: &str = "Runewarp Client";
const CLIENT_IDENTITY_HEADER: &str = "Runewarp Client Identity";
const CLIENT_PUBLIC_CERT_HEADER: &str = "Runewarp Public Hostname Certificates";

#[derive(Debug, Parser)]
#[command(
    name = "runewarp",
    about = "Runewarp: Public ingress. Private by design.",
    long_about = None,
    after_help = TOP_LEVEL_EXAMPLES
)]
pub struct Cli {
    #[command(subcommand)]
    pub command: Option<TopLevelCommand>,
}

#[derive(Debug, Subcommand)]
pub enum TopLevelCommand {
    /// Operate the Server runtime and setup commands.
    Server(ServerArgs),
    /// Operate the Client runtime and setup commands.
    Client(ClientArgs),
}

#[derive(Debug, Args)]
#[command(
    about = "Operate the Server runtime and setup commands",
    long_about = None,
    before_help = SERVER_HEADER,
    after_help = SERVER_EXAMPLES
)]
pub struct ServerArgs {
    /// Use an explicit config file instead of the default Runewarp config path.
    #[arg(short = 'c', long, value_name = "PATH", global = true)]
    pub config: Option<PathBuf>,
    #[command(subcommand)]
    pub command: Option<ServerSubcommand>,
}

#[derive(Debug, Subcommand)]
pub enum ServerSubcommand {
    /// Manage Server certificates.
    Cert(ServerCertArgs),
}

#[derive(Debug, Args)]
#[command(
    about = "Manage Server certificates",
    long_about = None,
    before_help = SERVER_CERT_HEADER,
    subcommand_required = true,
    arg_required_else_help = true,
    after_help = SERVER_CERT_EXAMPLES
)]
pub struct ServerCertArgs {
    #[command(subcommand)]
    pub command: ServerCertSubcommand,
}

#[derive(Debug, Subcommand)]
pub enum ServerCertSubcommand {
    /// Initialize Server certificates.
    Init(ServerCertInitArgs),
    /// Renew Server certificates.
    Renew(ServerCertDirArgs),
    /// Rotate the Server CA.
    RotateCa(ServerCertInitArgs),
}

#[derive(Debug, Args)]
#[command(before_help = SERVER_CERT_HEADER, after_help = SERVER_CERT_EXAMPLES)]
pub struct ServerCertInitArgs {
    /// Write certificate material into this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
    /// Use this Server hostname instead of reading it from config.
    #[arg(long, value_name = "HOSTNAME")]
    pub hostname: Option<String>,
}

#[derive(Debug, Args)]
#[command(before_help = SERVER_CERT_HEADER, after_help = SERVER_CERT_EXAMPLES)]
pub struct ServerCertDirArgs {
    /// Read and write certificate material in this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
}

#[derive(Debug, Args)]
#[command(
    about = "Operate the Client runtime and setup commands",
    long_about = None,
    before_help = CLIENT_HEADER,
    after_help = CLIENT_EXAMPLES
)]
pub struct ClientArgs {
    /// Use an explicit config file instead of the default Runewarp config path.
    #[arg(short = 'c', long, value_name = "PATH", global = true)]
    pub config: Option<PathBuf>,
    /// Override the configured Server address for the runtime Client command.
    #[arg(long, value_name = "HOSTNAME[:PORT]")]
    pub server_address: Option<String>,
    /// Supply a catch-all backend address for the runtime Client command.
    #[arg(long, value_name = "ADDRESS")]
    pub backend_address: Option<String>,
    #[command(subcommand)]
    pub command: Option<ClientSubcommand>,
}

#[derive(Debug, Subcommand)]
pub enum ClientSubcommand {
    /// Manage Client identity.
    Identity(ClientIdentityArgs),
    /// Manage Public hostname certificates.
    PublicCert(ClientPublicCertArgs),
}

#[derive(Debug, Args)]
#[command(
    about = "Manage Public hostname certificates",
    long_about = None,
    before_help = CLIENT_PUBLIC_CERT_HEADER,
    subcommand_required = true,
    arg_required_else_help = true,
    after_help = CLIENT_PUBLIC_CERT_EXAMPLES
)]
pub struct ClientPublicCertArgs {
    #[command(subcommand)]
    pub command: ClientPublicCertSubcommand,
}

#[derive(Debug, Subcommand)]
pub enum ClientPublicCertSubcommand {
    /// Initialize Public hostname certificates.
    Init(ClientPublicCertInitArgs),
    /// Renew Public hostname certificates.
    Renew(ClientPublicCertRenewArgs),
    /// Rotate the Public hostname CA.
    RotateCa(ClientPublicCertDirArgs),
}

#[derive(Debug, Args)]
#[command(before_help = CLIENT_PUBLIC_CERT_HEADER, after_help = CLIENT_PUBLIC_CERT_EXAMPLES)]
pub struct ClientPublicCertInitArgs {
    /// Write Public hostname certificate material into this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
    /// Issue a certificate for this Public hostname.
    #[arg(long, value_name = "HOSTNAME")]
    pub hostname: Option<String>,
}

#[derive(Debug, Args)]
#[command(before_help = CLIENT_PUBLIC_CERT_HEADER, after_help = CLIENT_PUBLIC_CERT_EXAMPLES)]
pub struct ClientPublicCertRenewArgs {
    /// Read and write Public hostname certificate material in this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
    /// Hostname whose leaf certificate should be renewed. When omitted, all
    /// terminating hostnames from the config file are renewed.
    #[arg(long, value_name = "HOSTNAME")]
    pub hostname: Option<String>,
}

#[derive(Debug, Args)]
#[command(before_help = CLIENT_PUBLIC_CERT_HEADER, after_help = CLIENT_PUBLIC_CERT_ROTATE_CA_EXAMPLES)]
pub struct ClientPublicCertDirArgs {
    /// Read and write Public hostname certificate material in this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
}

#[derive(Debug, Args)]
#[command(
    about = "Manage Client identity",
    long_about = None,
    before_help = CLIENT_IDENTITY_HEADER,
    subcommand_required = true,
    arg_required_else_help = true,
    after_help = CLIENT_IDENTITY_EXAMPLES
)]
pub struct ClientIdentityArgs {
    #[command(subcommand)]
    pub command: ClientIdentitySubcommand,
}

#[derive(Debug, Subcommand)]
pub enum ClientIdentitySubcommand {
    /// Initialize Client identity.
    Init(ClientIdentityDirArgs),
    /// Renew Client identity certificates.
    Renew(ClientIdentityDirArgs),
    /// Rotate Client identity.
    Rotate(ClientIdentityDirArgs),
    /// Show the Client identity fingerprint.
    Show(ClientIdentityDirArgs),
}

#[derive(Debug, Args)]
#[command(before_help = CLIENT_IDENTITY_HEADER, after_help = CLIENT_IDENTITY_LEAF_EXAMPLES)]
pub struct ClientIdentityDirArgs {
    /// Read and write Client identity material in this directory.
    #[arg(long = "dir", value_name = "DIR")]
    pub dir: Option<PathBuf>,
}