diff --git a/src/blocks/vpn.rs b/src/blocks/vpn.rs index f7f9bd1f26..272d106455 100644 --- a/src/blocks/vpn.rs +++ b/src/blocks/vpn.rs @@ -32,6 +32,9 @@ //! ## Mullvad //! Behind the scenes the mullvad driver uses the `mullvad` command line binary. In order for this to work properly the binary should be executable and mullvad daemon should be running. //! +//! ## Cloudflare WARP +//! Behind the scenes the WARP driver uses the `warp-cli` command line binary. Just ensure the binary is executable without root privileges. +//! //! # Example //! //! Shows the current vpn network state: @@ -71,6 +74,8 @@ mod nordvpn; use nordvpn::NordVpnDriver; mod mullvad; use mullvad::MullvadDriver; +mod warp; +use warp::WarpDriver; use super::prelude::*; @@ -80,6 +85,7 @@ pub enum DriverType { #[default] Nordvpn, Mullvad, + Warp, } #[derive(Deserialize, Debug, SmartDefault)] @@ -123,6 +129,7 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> { let driver: Box = match config.driver { DriverType::Nordvpn => Box::new(NordVpnDriver::new().await), DriverType::Mullvad => Box::new(MullvadDriver::new().await), + DriverType::Warp => Box::new(WarpDriver::new().await), }; loop { diff --git a/src/blocks/vpn/warp.rs b/src/blocks/vpn/warp.rs new file mode 100644 index 0000000000..e9a9084228 --- /dev/null +++ b/src/blocks/vpn/warp.rs @@ -0,0 +1,59 @@ +use std::process::Stdio; +use tokio::process::Command; + +use super::{Driver, Status}; +use crate::blocks::prelude::*; + +pub struct WarpDriver; + +impl WarpDriver { + pub async fn new() -> WarpDriver { + WarpDriver + } + + async fn run_network_command(arg: &str) -> Result<()> { + Command::new("warp-cli") + .args([arg]) + .stdin(Stdio::null()) + .stdout(Stdio::null()) + .spawn() + .error(format!("Problem running warp-cli command: {arg}"))? + .wait() + .await + .error(format!("Problem running warp-cli command: {arg}"))?; + Ok(()) + } +} + +#[async_trait] +impl Driver for WarpDriver { + async fn get_status(&self) -> Result { + let stdout = Command::new("warp-cli") + .args(["status"]) + .output() + .await + .error("Problem running warp-cli command")? + .stdout; + + let status = String::from_utf8(stdout).error("warp-cli produced non-UTF8 output")?; + + if status.contains("Status update: Disconnected") { + return Ok(Status::Disconnected); + } else if status.contains("Status update: Connected") { + return Ok(Status::Connected { + country: "".to_string(), // because warp-cli doesn't provide country/server info + country_flag: "".to_string(), // no country means no flag + }); + } + Ok(Status::Error) + } + + async fn toggle_connection(&self, status: &Status) -> Result<()> { + match status { + Status::Connected { .. } => Self::run_network_command("disconnect").await?, + Status::Disconnected => Self::run_network_command("connect").await?, + Status::Error => (), + } + Ok(()) + } +}