use anyhow::{Context, Result}; use clap::Parser; use dosh::auth::{build_bootstrap, encode_bootstrap, load_or_create_server_secret}; use dosh::config::load_server_config; use dosh::native::{host_public_key, host_public_key_line, load_or_create_host_key}; #[derive(Debug, Parser)] #[command( name = "dosh-auth", version = dosh::build_info::VERSION, long_version = dosh::build_info::LONG_VERSION )] struct Args { #[arg(long, default_value_t = 1)] protocol: u8, #[arg(long)] nonce: Option, #[arg(long)] host_key: bool, #[arg(long, default_value = "default")] session: String, #[arg(long, default_value = "read-write")] mode: String, #[arg(long, default_value = "80x24")] size: String, #[arg(long, default_value = "dev")] client_version: String, #[arg(long)] udp_host: Option, } fn main() -> Result<()> { let args = Args::parse(); anyhow::ensure!(args.protocol == 1, "unsupported protocol {}", args.protocol); let config = load_server_config(None)?; if args.host_key { let signing_key = load_or_create_host_key(&config)?; println!("{}", host_public_key_line(&host_public_key(&signing_key))); return Ok(()); } let secret = load_or_create_server_secret(&config)?; let nonce = parse_nonce(args.nonce.as_deref().context("--nonce is required")?)?; let size = parse_size(&args.size)?; let user = std::env::var("USER").unwrap_or_else(|_| "unknown".to_string()); let udp_host = args.udp_host.unwrap_or_else(|| "127.0.0.1".to_string()); let resp = build_bootstrap( &config, &secret, user, args.session, args.mode, size, nonce, udp_host, )?; println!("{}", encode_bootstrap(&resp)?); Ok(()) } fn parse_nonce(raw: &str) -> Result<[u8; 12]> { let bytes = base64::Engine::decode(&base64::engine::general_purpose::URL_SAFE_NO_PAD, raw) .context("decode nonce")?; anyhow::ensure!(bytes.len() == 12, "nonce must decode to 12 bytes"); let mut out = [0u8; 12]; out.copy_from_slice(&bytes); Ok(out) } fn parse_size(raw: &str) -> Result<(u16, u16)> { let (cols, rows) = raw.split_once('x').context("size must be COLSxROWS")?; Ok((cols.parse()?, rows.parse()?)) }