Update format

This commit is contained in:
Kevin Yue 2024-01-28 05:11:46 -05:00
parent b2bb35994f
commit 196e91289c
24 changed files with 54 additions and 206 deletions

View File

@ -19,8 +19,8 @@ use tokio_util::sync::CancellationToken;
use webkit2gtk::{ use webkit2gtk::{
gio::Cancellable, gio::Cancellable,
glib::{GString, TimeSpan}, glib::{GString, TimeSpan},
LoadEvent, SettingsExt, TLSErrorsPolicy, URIResponse, URIResponseExt, WebContextExt, WebResource, LoadEvent, SettingsExt, TLSErrorsPolicy, URIResponse, URIResponseExt, WebContextExt, WebResource, WebResourceExt,
WebResourceExt, WebView, WebViewExt, WebsiteDataManagerExtManual, WebsiteDataTypes, WebView, WebViewExt, WebsiteDataManagerExtManual, WebsiteDataTypes,
}; };
enum AuthDataError { enum AuthDataError {
@ -216,9 +216,7 @@ impl<'a> AuthWindow<'a> {
if let Some(auth_result) = auth_result_rx.recv().await { if let Some(auth_result) = auth_result_rx.recv().await {
match auth_result { match auth_result {
Ok(auth_data) => return Ok(auth_data), Ok(auth_data) => return Ok(auth_data),
Err(AuthDataError::TlsError) => { Err(AuthDataError::TlsError) => bail!("TLS error: certificate verify failed"),
return Err(anyhow::anyhow!("TLS error: certificate verify failed"))
}
Err(AuthDataError::NotFound) => { Err(AuthDataError::NotFound) => {
info!("No auth data found, it may not be the /SAML20/SP/ACS endpoint"); info!("No auth data found, it may not be the /SAML20/SP/ACS endpoint");
@ -227,10 +225,7 @@ impl<'a> AuthWindow<'a> {
let window = Arc::clone(window); let window = Arc::clone(window);
let cancel_token = CancellationToken::new(); let cancel_token = CancellationToken::new();
raise_window_cancel_token raise_window_cancel_token.write().await.replace(cancel_token.clone());
.write()
.await
.replace(cancel_token.clone());
tokio::spawn(async move { tokio::spawn(async move {
let delay_secs = 1; let delay_secs = 1;

View File

@ -13,12 +13,7 @@ use tempfile::NamedTempFile;
use crate::auth_window::{portal_prelogin, AuthWindow}; use crate::auth_window::{portal_prelogin, AuthWindow};
const VERSION: &str = concat!( const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
env!("CARGO_PKG_VERSION"),
" (",
compile_time::date_str!(),
")"
);
#[derive(Parser, Clone)] #[derive(Parser, Clone)]
#[command(version = VERSION)] #[command(version = VERSION)]

View File

@ -9,12 +9,7 @@ use crate::{
launch_gui::{LaunchGuiArgs, LaunchGuiHandler}, launch_gui::{LaunchGuiArgs, LaunchGuiHandler},
}; };
const VERSION: &str = concat!( const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
env!("CARGO_PKG_VERSION"),
" (",
compile_time::date_str!(),
")"
);
pub(crate) struct SharedArgs { pub(crate) struct SharedArgs {
pub(crate) fix_openssl: bool, pub(crate) fix_openssl: bool,
@ -53,10 +48,7 @@ struct Cli {
#[command(subcommand)] #[command(subcommand)]
command: CliCommand, command: CliCommand,
#[arg( #[arg(long, help = "Get around the OpenSSL `unsafe legacy renegotiation` error")]
long,
help = "Get around the OpenSSL `unsafe legacy renegotiation` error"
)]
fix_openssl: bool, fix_openssl: bool,
#[arg(long, help = "Ignore the TLS errors")] #[arg(long, help = "Ignore the TLS errors")]
ignore_tls_errors: bool, ignore_tls_errors: bool,

View File

@ -21,17 +21,9 @@ use crate::{cli::SharedArgs, GP_CLIENT_LOCK_FILE};
pub(crate) struct ConnectArgs { pub(crate) struct ConnectArgs {
#[arg(help = "The portal server to connect to")] #[arg(help = "The portal server to connect to")]
server: String, server: String,
#[arg( #[arg(short, long, help = "The gateway to connect to, it will prompt if not specified")]
short,
long,
help = "The gateway to connect to, it will prompt if not specified"
)]
gateway: Option<String>, gateway: Option<String>,
#[arg( #[arg(short, long, help = "The username to use, it will prompt if not specified")]
short,
long,
help = "The username to use, it will prompt if not specified"
)]
user: Option<String>, user: Option<String>,
#[arg(long, short, help = "The VPNC script to use")] #[arg(long, short, help = "The VPNC script to use")]
script: Option<String>, script: Option<String>,
@ -174,11 +166,7 @@ impl<'a> ConnectHandler<'a> {
Ok(()) Ok(())
} }
async fn obtain_credential( async fn obtain_credential(&self, prelogin: &Prelogin, server: &str) -> anyhow::Result<Credential> {
&self,
prelogin: &Prelogin,
server: &str,
) -> anyhow::Result<Credential> {
let is_gateway = prelogin.is_gateway(); let is_gateway = prelogin.is_gateway();
match prelogin { match prelogin {

View File

@ -6,9 +6,7 @@ use clap::Parser;
use gpapi::{ use gpapi::{
process::gui_launcher::GuiLauncher, process::gui_launcher::GuiLauncher,
service::{request::WsRequest, vpn_state::VpnState}, service::{request::WsRequest, vpn_state::VpnState},
utils::{ utils::{crypto::generate_key, env_file, lock_file::LockFile, redact::Redaction, shutdown_signal},
crypto::generate_key, env_file, lock_file::LockFile, redact::Redaction, shutdown_signal,
},
GP_SERVICE_LOCK_FILE, GP_SERVICE_LOCK_FILE,
}; };
use log::{info, warn, LevelFilter}; use log::{info, warn, LevelFilter};
@ -16,12 +14,7 @@ use tokio::sync::{mpsc, watch};
use crate::{vpn_task::VpnTask, ws_server::WsServer}; use crate::{vpn_task::VpnTask, ws_server::WsServer};
const VERSION: &str = concat!( const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
env!("CARGO_PKG_VERSION"),
" (",
compile_time::date_str!(),
")"
);
#[derive(Parser)] #[derive(Parser)]
#[command(version = VERSION)] #[command(version = VERSION)]
@ -51,13 +44,7 @@ impl Cli {
let (vpn_state_tx, vpn_state_rx) = watch::channel(VpnState::Disconnected); let (vpn_state_tx, vpn_state_rx) = watch::channel(VpnState::Disconnected);
let mut vpn_task = VpnTask::new(ws_req_rx, vpn_state_tx); let mut vpn_task = VpnTask::new(ws_req_rx, vpn_state_tx);
let ws_server = WsServer::new( let ws_server = WsServer::new(api_key.clone(), ws_req_tx, vpn_state_rx, lock_file.clone(), redaction);
api_key.clone(),
ws_req_tx,
vpn_state_rx,
lock_file.clone(),
redaction,
);
let (shutdown_tx, mut shutdown_rx) = mpsc::channel::<()>(4); let (shutdown_tx, mut shutdown_rx) = mpsc::channel::<()>(4);
let shutdown_tx_clone = shutdown_tx.clone(); let shutdown_tx_clone = shutdown_tx.clone();
@ -76,11 +63,7 @@ impl Cli {
if no_gui { if no_gui {
info!("GUI is disabled"); info!("GUI is disabled");
} else { } else {
let envs = self let envs = self.env_file.as_ref().map(env_file::load_env_vars).transpose()?;
.env_file
.as_ref()
.map(env_file::load_env_vars)
.transpose()?;
let minimized = self.minimized; let minimized = self.minimized;

View File

@ -21,17 +21,11 @@ pub(crate) async fn active_gui(State(ctx): State<Arc<WsServerContext>>) -> impl
ctx.send_event(WsEvent::ActiveGui).await; ctx.send_event(WsEvent::ActiveGui).await;
} }
pub(crate) async fn auth_data( pub(crate) async fn auth_data(State(ctx): State<Arc<WsServerContext>>, body: String) -> impl IntoResponse {
State(ctx): State<Arc<WsServerContext>>,
body: String,
) -> impl IntoResponse {
ctx.send_event(WsEvent::AuthData(body)).await; ctx.send_event(WsEvent::AuthData(body)).await;
} }
pub(crate) async fn ws_handler( pub(crate) async fn ws_handler(ws: WebSocketUpgrade, State(ctx): State<Arc<WsServerContext>>) -> impl IntoResponse {
ws: WebSocketUpgrade,
State(ctx): State<Arc<WsServerContext>>,
) -> impl IntoResponse {
ws.on_upgrade(move |socket| handle_socket(socket, ctx)) ws.on_upgrade(move |socket| handle_socket(socket, ctx))
} }

View File

@ -98,12 +98,7 @@ impl WsServer {
lock_file: Arc<LockFile>, lock_file: Arc<LockFile>,
redaction: Arc<Redaction>, redaction: Arc<Redaction>,
) -> Self { ) -> Self {
let ctx = Arc::new(WsServerContext::new( let ctx = Arc::new(WsServerContext::new(api_key, ws_req_tx, vpn_state_rx, redaction));
api_key,
ws_req_tx,
vpn_state_rx,
redaction,
));
let cancel_token = CancellationToken::new(); let cancel_token = CancellationToken::new();
Self { Self {

View File

@ -27,11 +27,7 @@ impl SamlAuthResult {
} }
impl SamlAuthData { impl SamlAuthData {
pub fn new( pub fn new(username: String, prelogin_cookie: Option<String>, portal_userauthcookie: Option<String>) -> Self {
username: String,
prelogin_cookie: Option<String>,
portal_userauthcookie: Option<String>,
) -> Self {
Self { Self {
username, username,
prelogin_cookie, prelogin_cookie,
@ -78,13 +74,9 @@ impl SamlAuthData {
prelogin_cookie: &Option<String>, prelogin_cookie: &Option<String>,
portal_userauthcookie: &Option<String>, portal_userauthcookie: &Option<String>,
) -> bool { ) -> bool {
let username_valid = username let username_valid = username.as_ref().is_some_and(|username| !username.is_empty());
.as_ref()
.is_some_and(|username| !username.is_empty());
let prelogin_cookie_valid = prelogin_cookie.as_ref().is_some_and(|val| val.len() > 5); let prelogin_cookie_valid = prelogin_cookie.as_ref().is_some_and(|val| val.len() > 5);
let portal_userauthcookie_valid = portal_userauthcookie let portal_userauthcookie_valid = portal_userauthcookie.as_ref().is_some_and(|val| val.len() > 5);
.as_ref()
.is_some_and(|val| val.len() > 5);
username_valid && (prelogin_cookie_valid || portal_userauthcookie_valid) username_valid && (prelogin_cookie_valid || portal_userauthcookie_valid)
} }

View File

@ -112,11 +112,7 @@ pub struct CachedCredential {
} }
impl CachedCredential { impl CachedCredential {
pub fn new( pub fn new(username: String, password: Option<String>, auth_cookie: AuthCookieCredential) -> Self {
username: String,
password: Option<String>,
auth_cookie: AuthCookieCredential,
) -> Self {
Self { Self {
username, username,
password, password,
@ -193,8 +189,7 @@ impl Credential {
let mut params = HashMap::new(); let mut params = HashMap::new();
params.insert("user", self.username()); params.insert("user", self.username());
let (passwd, prelogin_cookie, portal_userauthcookie, portal_prelogonuserauthcookie) = match self let (passwd, prelogin_cookie, portal_userauthcookie, portal_prelogonuserauthcookie) = match self {
{
Credential::Password(cred) => (Some(cred.password()), None, None, None), Credential::Password(cred) => (Some(cred.password()), None, None, None),
Credential::PreloginCookie(cred) => (None, Some(cred.prelogin_cookie()), None, None), Credential::PreloginCookie(cred) => (None, Some(cred.prelogin_cookie()), None, None),
Credential::AuthCookie(cred) => ( Credential::AuthCookie(cred) => (
@ -213,10 +208,7 @@ impl Credential {
params.insert("passwd", passwd.unwrap_or_default()); params.insert("passwd", passwd.unwrap_or_default());
params.insert("prelogin-cookie", prelogin_cookie.unwrap_or_default()); params.insert("prelogin-cookie", prelogin_cookie.unwrap_or_default());
params.insert( params.insert("portal-userauthcookie", portal_userauthcookie.unwrap_or_default());
"portal-userauthcookie",
portal_userauthcookie.unwrap_or_default(),
);
params.insert( params.insert(
"portal-prelogonuserauthcookie", "portal-prelogonuserauthcookie",
portal_prelogonuserauthcookie.unwrap_or_default(), portal_prelogonuserauthcookie.unwrap_or_default(),

View File

@ -10,11 +10,7 @@ use crate::{
utils::{normalize_server, remove_url_scheme}, utils::{normalize_server, remove_url_scheme},
}; };
pub async fn gateway_login( pub async fn gateway_login(gateway: &str, cred: &Credential, gp_params: &GpParams) -> anyhow::Result<String> {
gateway: &str,
cred: &Credential,
gp_params: &GpParams,
) -> anyhow::Result<String> {
let url = normalize_server(gateway)?; let url = normalize_server(gateway)?;
let gateway = remove_url_scheme(&url); let gateway = remove_url_scheme(&url);
@ -70,11 +66,7 @@ fn build_gateway_token(doc: &Document, computer: &str) -> anyhow::Result<String>
Ok(token) Ok(token)
} }
fn read_args<'a>( fn read_args<'a>(args: &'a [String], index: usize, key: &'a str) -> anyhow::Result<(&'a str, &'a str)> {
args: &'a [String],
index: usize,
key: &'a str,
) -> anyhow::Result<(&'a str, &'a str)> {
args args
.get(index) .get(index)
.ok_or_else(|| anyhow::anyhow!("Failed to read {key} from args")) .ok_or_else(|| anyhow::anyhow!("Failed to read {key} from args"))

View File

@ -4,9 +4,7 @@ use super::{Gateway, PriorityRule};
pub(crate) fn parse_gateways(doc: &Document) -> Option<Vec<Gateway>> { pub(crate) fn parse_gateways(doc: &Document) -> Option<Vec<Gateway>> {
let node_gateways = doc.descendants().find(|n| n.has_tag_name("gateways"))?; let node_gateways = doc.descendants().find(|n| n.has_tag_name("gateways"))?;
let list_gateway = node_gateways let list_gateway = node_gateways.descendants().find(|n| n.has_tag_name("list"))?;
.descendants()
.find(|n| n.has_tag_name("list"))?;
let gateways = list_gateway let gateways = list_gateway
.children() .children()

View File

@ -79,21 +79,11 @@ impl PortalConfig {
} }
// If no gateway is found, return the gateway with the lowest priority // If no gateway is found, return the gateway with the lowest priority
preferred_gateway.unwrap_or_else(|| { preferred_gateway.unwrap_or_else(|| self.gateways.iter().min_by_key(|gateway| gateway.priority).unwrap())
self
.gateways
.iter()
.min_by_key(|gateway| gateway.priority)
.unwrap()
})
} }
} }
pub async fn retrieve_config( pub async fn retrieve_config(portal: &str, cred: &Credential, gp_params: &GpParams) -> anyhow::Result<PortalConfig> {
portal: &str,
cred: &Credential,
gp_params: &GpParams,
) -> anyhow::Result<PortalConfig> {
let portal = normalize_server(portal)?; let portal = normalize_server(portal)?;
let server = remove_url_scheme(&portal); let server = remove_url_scheme(&portal);
@ -116,24 +106,17 @@ pub async fn retrieve_config(
let status = res.status(); let status = res.status();
if status == StatusCode::NOT_FOUND { if status == StatusCode::NOT_FOUND {
bail!(PortalError::ConfigError( bail!(PortalError::ConfigError("Config endpoint not found".to_string()))
"Config endpoint not found".to_string()
))
} }
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
bail!("Portal config error: {}", status) bail!("Portal config error: {}", status)
} }
let res_xml = res let res_xml = res.text().await.map_err(|e| PortalError::ConfigError(e.to_string()))?;
.text()
.await
.map_err(|e| PortalError::ConfigError(e.to_string()))?;
if res_xml.is_empty() { if res_xml.is_empty() {
bail!(PortalError::ConfigError( bail!(PortalError::ConfigError("Empty portal config response".to_string()))
"Empty portal config response".to_string()
))
} }
let doc = Document::parse(&res_xml).map_err(|e| PortalError::ConfigError(e.to_string()))?; let doc = Document::parse(&res_xml).map_err(|e| PortalError::ConfigError(e.to_string()))?;
@ -144,8 +127,7 @@ pub async fn retrieve_config(
}); });
let user_auth_cookie = xml::get_child_text(&doc, "portal-userauthcookie").unwrap_or_default(); let user_auth_cookie = xml::get_child_text(&doc, "portal-userauthcookie").unwrap_or_default();
let prelogon_user_auth_cookie = let prelogon_user_auth_cookie = xml::get_child_text(&doc, "portal-prelogonuserauthcookie").unwrap_or_default();
xml::get_child_text(&doc, "portal-prelogonuserauthcookie").unwrap_or_default();
let config_digest = xml::get_child_text(&doc, "config-digest"); let config_digest = xml::get_child_text(&doc, "config-digest");
if gateways.is_empty() { if gateways.is_empty() {
@ -154,11 +136,7 @@ pub async fn retrieve_config(
Ok(PortalConfig { Ok(PortalConfig {
portal: server.to_string(), portal: server.to_string(),
auth_cookie: AuthCookieCredential::new( auth_cookie: AuthCookieCredential::new(cred.username(), &user_auth_cookie, &prelogon_user_auth_cookie),
cred.username(),
&user_auth_cookie,
&prelogon_user_auth_cookie,
),
config_cred: cred.clone(), config_cred: cred.clone(),
gateways, gateways,
config_digest, config_digest,

View File

@ -102,11 +102,7 @@ pub async fn prelogin(portal: &str, gp_params: &GpParams) -> anyhow::Result<Prel
let portal = normalize_server(portal)?; let portal = normalize_server(portal)?;
let is_gateway = gp_params.is_gateway(); let is_gateway = gp_params.is_gateway();
let path = if is_gateway { let path = if is_gateway { "ssl-vpn" } else { "global-protect" };
"ssl-vpn"
} else {
"global-protect"
};
let prelogin_url = format!("{portal}/{}/prelogin.esp", path); let prelogin_url = format!("{portal}/{}/prelogin.esp", path);
let mut params = gp_params.to_params(); let mut params = gp_params.to_params();
@ -115,11 +111,7 @@ pub async fn prelogin(portal: &str, gp_params: &GpParams) -> anyhow::Result<Prel
params.insert("default-browser", "1"); params.insert("default-browser", "1");
} }
params.retain(|k, _| { params.retain(|k, _| REQUIRED_PARAMS.iter().any(|required_param| required_param == k));
REQUIRED_PARAMS
.iter()
.any(|required_param| required_param == k)
});
let client = Client::builder() let client = Client::builder()
.danger_accept_invalid_certs(gp_params.ignore_tls_errors()) .danger_accept_invalid_certs(gp_params.ignore_tls_errors())
@ -130,9 +122,7 @@ pub async fn prelogin(portal: &str, gp_params: &GpParams) -> anyhow::Result<Prel
let status = res.status(); let status = res.status();
if status == StatusCode::NOT_FOUND { if status == StatusCode::NOT_FOUND {
bail!(PortalError::PreloginError( bail!(PortalError::PreloginError("Prelogin endpoint not found".to_string()))
"Prelogin endpoint not found".to_string()
))
} }
if status.is_client_error() || status.is_server_error() { if status.is_client_error() || status.is_server_error() {
@ -144,8 +134,7 @@ pub async fn prelogin(portal: &str, gp_params: &GpParams) -> anyhow::Result<Prel
.await .await
.map_err(|e| PortalError::PreloginError(e.to_string()))?; .map_err(|e| PortalError::PreloginError(e.to_string()))?;
let prelogin = let prelogin = parse_res_xml(res_xml, is_gateway).map_err(|e| PortalError::PreloginError(e.to_string()))?;
parse_res_xml(res_xml, is_gateway).map_err(|e| PortalError::PreloginError(e.to_string()))?;
Ok(prelogin) Ok(prelogin)
} }
@ -170,9 +159,7 @@ fn parse_res_xml(res_xml: String, is_gateway: bool) -> anyhow::Result<Prelogin>
// Check if the prelogin response is SAML // Check if the prelogin response is SAML
if saml_method.is_some() && saml_request.is_some() { if saml_method.is_some() && saml_request.is_some() {
let saml_request = base64::decode_to_string(&saml_request.unwrap())?; let saml_request = base64::decode_to_string(&saml_request.unwrap())?;
let support_default_browser = saml_default_browser let support_default_browser = saml_default_browser.map(|s| s.to_lowercase() == "yes").unwrap_or(false);
.map(|s| s.to_lowercase() == "yes")
.unwrap_or(false);
let saml_prelogin = SamlPrelogin { let saml_prelogin = SamlPrelogin {
region, region,
@ -188,8 +175,8 @@ fn parse_res_xml(res_xml: String, is_gateway: bool) -> anyhow::Result<Prelogin>
let label_password = xml::get_child_text(&doc, "password-label"); let label_password = xml::get_child_text(&doc, "password-label");
// Check if the prelogin response is standard login // Check if the prelogin response is standard login
if label_username.is_some() && label_password.is_some() { if label_username.is_some() && label_password.is_some() {
let auth_message = xml::get_child_text(&doc, "authentication-message") let auth_message =
.unwrap_or(String::from("Please enter the login credentials")); xml::get_child_text(&doc, "authentication-message").unwrap_or(String::from("Please enter the login credentials"));
let standard_prelogin = StandardPrelogin { let standard_prelogin = StandardPrelogin {
region, region,
is_gateway, is_gateway,

View File

@ -129,7 +129,7 @@ impl<'a> SamlAuthLauncher<'a> {
.wait_with_output() .wait_with_output()
.await?; .await?;
let auth_result: SamlAuthResult = serde_json::from_slice(&output.stdout) let auth_result = serde_json::from_slice::<SamlAuthResult>(&output.stdout)
.map_err(|_| anyhow::anyhow!("Failed to parse auth data"))?; .map_err(|_| anyhow::anyhow!("Failed to parse auth data"))?;
match auth_result { match auth_result {

View File

@ -21,8 +21,7 @@ impl CommandExt for Command {
} }
fn into_non_root(mut self) -> anyhow::Result<Command> { fn into_non_root(mut self) -> anyhow::Result<Command> {
let user = let user = get_non_root_user().map_err(|_| anyhow::anyhow!("{:?} cannot be run as root", self))?;
get_non_root_user().map_err(|_| anyhow::anyhow!("{:?} cannot be run as root", self))?;
self self
.env("HOME", user.home_dir()) .env("HOME", user.home_dir())
@ -42,8 +41,7 @@ fn get_non_root_user() -> anyhow::Result<User> {
let user = if current_user == "root" { let user = if current_user == "root" {
get_real_user()? get_real_user()?
} else { } else {
uzers::get_user_by_name(&current_user) uzers::get_user_by_name(&current_user).ok_or_else(|| anyhow::anyhow!("User ({}) not found", current_user))?
.ok_or_else(|| anyhow::anyhow!("User ({}) not found", current_user))?
}; };
if user.uid() == 0 { if user.uid() == 0 {

View File

@ -66,10 +66,7 @@ impl GuiLauncher {
let mut non_root_cmd = cmd.into_non_root()?; let mut non_root_cmd = cmd.into_non_root()?;
let mut child = non_root_cmd let mut child = non_root_cmd.kill_on_drop(true).stdin(Stdio::piped()).spawn()?;
.kill_on_drop(true)
.stdin(Stdio::piped())
.spawn()?;
let mut stdin = child let mut stdin = child
.stdin .stdin

View File

@ -58,10 +58,7 @@ impl ConnectArgs {
} }
pub fn openconnect_os(&self) -> Option<String> { pub fn openconnect_os(&self) -> Option<String> {
self self.os.as_ref().map(|os| os.to_openconnect_os().to_string())
.os
.as_ref()
.map(|os| os.to_openconnect_os().to_string())
} }
} }

View File

@ -30,9 +30,7 @@ pub fn normalize_server(server: &str) -> anyhow::Result<String> {
.host_str() .host_str()
.ok_or(anyhow::anyhow!("Invalid server URL: missing host"))?; .ok_or(anyhow::anyhow!("Invalid server URL: missing host"))?;
let port: String = normalized_url let port: String = normalized_url.port().map_or("".into(), |port| format!(":{}", port));
.port()
.map_or("".into(), |port| format!(":{}", port));
let normalized_url = format!("{}://{}{}", scheme, host, port); let normalized_url = format!("{}://{}{}", scheme, host, port);

View File

@ -115,12 +115,7 @@ pub fn redact_uri(uri: &str) -> String {
.map(|query| format!("?{}", query)) .map(|query| format!("?{}", query))
.unwrap_or_default(); .unwrap_or_default();
return format!( return format!("{}://[**********]{}{}", url.scheme(), url.path(), redacted_query);
"{}://[**********]{}{}",
url.scheme(),
url.path(),
redacted_query
);
} }
let redacted_query = redact_query(url.query()); let redacted_query = redact_query(url.query());
@ -165,10 +160,7 @@ mod tests {
redaction.add_value("foo").unwrap(); redaction.add_value("foo").unwrap();
assert_eq!( assert_eq!(redaction.redact_str("hello, foo, bar"), "hello, [**********], bar");
redaction.redact_str("hello, foo, bar"),
"hello, [**********], bar"
);
} }
#[test] #[test]

View File

@ -2,9 +2,7 @@ use tokio::signal;
pub async fn shutdown_signal() { pub async fn shutdown_signal() {
let ctrl_c = async { let ctrl_c = async {
signal::ctrl_c() signal::ctrl_c().await.expect("failed to install Ctrl+C handler");
.await
.expect("failed to install Ctrl+C handler");
}; };
#[cfg(unix)] #[cfg(unix)]

View File

@ -5,8 +5,5 @@ fn main() {
println!("cargo:rerun-if-changed=src/ffi/vpn.h"); println!("cargo:rerun-if-changed=src/ffi/vpn.h");
// Compile the vpn.c file // Compile the vpn.c file
cc::Build::new() cc::Build::new().file("src/ffi/vpn.c").include("src/ffi").compile("vpn");
.file("src/ffi/vpn.c")
.include("src/ffi")
.compile("vpn");
} }

View File

@ -20,10 +20,7 @@ pub(crate) struct ConnectOptions {
#[link(name = "vpn")] #[link(name = "vpn")]
extern "C" { extern "C" {
#[link_name = "vpn_connect"] #[link_name = "vpn_connect"]
fn vpn_connect( fn vpn_connect(options: *const ConnectOptions, callback: extern "C" fn(i32, *mut c_void)) -> c_int;
options: *const ConnectOptions,
callback: extern "C" fn(i32, *mut c_void),
) -> c_int;
#[link_name = "vpn_disconnect"] #[link_name = "vpn_disconnect"]
fn vpn_disconnect(); fn vpn_disconnect();

View File

@ -27,11 +27,7 @@ impl Vpn {
} }
pub fn connect(&self, on_connected: impl FnOnce() + 'static + Send + Sync) -> i32 { pub fn connect(&self, on_connected: impl FnOnce() + 'static + Send + Sync) -> i32 {
self self.callback.write().unwrap().replace(Box::new(on_connected));
.callback
.write()
.unwrap()
.replace(Box::new(on_connected));
let options = self.build_connect_options(); let options = self.build_connect_options();
ffi::connect(&options) ffi::connect(&options)
@ -107,10 +103,7 @@ impl VpnBuilder {
pub fn build(self) -> Vpn { pub fn build(self) -> Vpn {
let user_agent = self.user_agent.unwrap_or_default(); let user_agent = self.user_agent.unwrap_or_default();
let script = self let script = self.script.or_else(find_default_vpnc_script).unwrap_or_default();
.script
.or_else(find_default_vpnc_script)
.unwrap_or_default();
let os = self.os.unwrap_or("linux".to_string()); let os = self.os.unwrap_or("linux".to_string());
Vpn { Vpn {

View File

@ -1,4 +1,4 @@
max_width = 100 max_width = 120
hard_tabs = false hard_tabs = false
tab_spaces = 2 tab_spaces = 2
newline_style = "Unix" newline_style = "Unix"