Skip to content

[feat] Support Cloudflare Warp in vpn block #2149

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/blocks/vpn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -71,6 +74,8 @@ mod nordvpn;
use nordvpn::NordVpnDriver;
mod mullvad;
use mullvad::MullvadDriver;
mod warp;
use warp::WarpDriver;

use super::prelude::*;

Expand All @@ -80,6 +85,7 @@ pub enum DriverType {
#[default]
Nordvpn,
Mullvad,
Warp,
}

#[derive(Deserialize, Debug, SmartDefault)]
Expand Down Expand Up @@ -123,6 +129,7 @@ pub async fn run(config: &Config, api: &CommonApi) -> Result<()> {
let driver: Box<dyn Driver> = 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 {
Expand Down
59 changes: 59 additions & 0 deletions src/blocks/vpn/warp.rs
Original file line number Diff line number Diff line change
@@ -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<Status> {
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(())
}
}