diff --git a/crates/sshx/src/controller.rs b/crates/sshx/src/controller.rs index 5eff767..49a3bcc 100644 --- a/crates/sshx/src/controller.rs +++ b/crates/sshx/src/controller.rs @@ -1,6 +1,7 @@ //! Network gRPC client allowing server control of terminals. use std::collections::HashMap; +use std::convert::TryFrom; use std::pin::pin; use anyhow::{Context, Result}; @@ -43,6 +44,21 @@ pub struct Controller { output_tx: mpsc::Sender, /// Owned receiving end of the `output_tx` channel. output_rx: mpsc::Receiver, + auth_token: Option, +} + +fn add_auth_header_to_request( + mut req: tonic::Request, + auth_token: &Option, +) -> tonic::Request { + if let Some(token) = auth_token { + if let Ok(auth_value) = + tonic::metadata::MetadataValue::try_from(format!("Bearer {}", token)) + { + req.metadata_mut().insert("authorization", auth_value); + } + } + req } impl Controller { @@ -52,6 +68,7 @@ impl Controller { name: &str, runner: Runner, enable_readers: bool, + auth_token: &Option, ) -> Result { debug!(%origin, "connecting to server"); let encryption_key = rand_alphanumeric(14); // 83.3 bits of entropy @@ -86,6 +103,7 @@ impl Controller { name: name.into(), write_password_hash, }; + let req = add_auth_header_to_request(tonic::Request::new(req), auth_token); let mut resp = client.open(req).await?.into_inner(); resp.url = resp.url + "#" + &encryption_key; @@ -108,6 +126,7 @@ impl Controller { shells_tx: HashMap::new(), output_tx, output_rx, + auth_token: auth_token.clone(), }) } @@ -280,6 +299,7 @@ impl Controller { name: self.name.clone(), token: self.token.clone(), }; + let req = add_auth_header_to_request(tonic::Request::new(req), &self.auth_token); let mut client = Self::connect(&self.origin).await?; client.close(req).await?; Ok(()) diff --git a/crates/sshx/src/main.rs b/crates/sshx/src/main.rs index d91f50e..24f3062 100644 --- a/crates/sshx/src/main.rs +++ b/crates/sshx/src/main.rs @@ -31,6 +31,10 @@ struct Args { /// editors. #[clap(long)] enable_readers: bool, + + /// Authentication token (sent as Authorization header) + #[arg(long, env = "SSHX_AUTH_TOKEN")] + pub auth_token: Option, } fn print_greeting(shell: &str, controller: &Controller) { @@ -90,7 +94,14 @@ async fn start(args: Args) -> Result<()> { }); let runner = Runner::Shell(shell.clone()); - let mut controller = Controller::new(&args.server, &name, runner, args.enable_readers).await?; + let mut controller = Controller::new( + &args.server, + &name, + runner, + args.enable_readers, + &args.auth_token, + ) + .await?; if args.quiet { if let Some(write_url) = controller.write_url() { println!("{}", write_url);