use std::path::Path; use reqwest::multipart::{Form, Part}; use reqwest::{StatusCode, Url}; use tracing::{debug, error, info}; pub async fn sign_key(token: &str) -> Result<(), Box> { let url = crate::get_sshca_server_url()?; let pubkey = Path::new("/home/dustin/.ssh/id_ed25519.pub"); let pubkey_path = pubkey.to_owned(); let pubkey = std::fs::read_to_string(&pubkey_path)?; let mut url = Url::parse(&url).map_err(|e| format!("Invalid URL: {}", e))?; url.path_segments_mut() .map_err(|_| "Invalid URL: missing host")? .pop_if_empty() .push("user") .push("sign"); let form = Form::new().part( "pubkey", Part::bytes(pubkey.into_bytes()).file_name( pubkey_path .file_name() .ok_or("Invalid public key file path")? .to_str() .ok_or("Invalid public key file path")? .to_string(), ), ); let client = reqwest::Client::new(); info!( "Requesting SSH user certificate for {} with key {}", "-", pubkey_path.display() ); debug!("Request: POST {}", url); let res = client .post(url) .header("Authorization", format!("Bearer {}", token)) .multipart(form) .send() .await?; debug!("Response: {:?} {}", &res.version(), &res.status()); match res.error_for_status_ref() { Ok(_) => (), Err(e) if e.status() == Some(StatusCode::BAD_REQUEST) => { let msg = res.text().await.unwrap_or_else(|e| e.to_string()); error!("{}: {}", e, msg); return Err(format!("{}\n{}", e, msg).into()); } Err(e) => { error!("{}", e); return Err(e.into()); } }; let cert = res.text().await?; println!("{}", cert); Ok(()) }