mirror of
https://github.com/yuezk/GlobalProtect-openconnect.git
synced 2025-05-20 07:26:58 -04:00
Refactor using Tauri (#278)
This commit is contained in:
96
crates/gpapi/src/process/auth_launcher.rs
Normal file
96
crates/gpapi/src/process/auth_launcher.rs
Normal file
@@ -0,0 +1,96 @@
|
||||
use std::process::Stdio;
|
||||
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::{auth::SamlAuthResult, credential::Credential, GP_AUTH_BINARY};
|
||||
|
||||
use super::command_traits::CommandExt;
|
||||
|
||||
pub struct SamlAuthLauncher<'a> {
|
||||
server: &'a str,
|
||||
user_agent: Option<&'a str>,
|
||||
saml_request: Option<&'a str>,
|
||||
hidpi: bool,
|
||||
fix_openssl: bool,
|
||||
clean: bool,
|
||||
}
|
||||
|
||||
impl<'a> SamlAuthLauncher<'a> {
|
||||
pub fn new(server: &'a str) -> Self {
|
||||
Self {
|
||||
server,
|
||||
user_agent: None,
|
||||
saml_request: None,
|
||||
hidpi: false,
|
||||
fix_openssl: false,
|
||||
clean: false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn user_agent(mut self, user_agent: &'a str) -> Self {
|
||||
self.user_agent = Some(user_agent);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn saml_request(mut self, saml_request: &'a str) -> Self {
|
||||
self.saml_request = Some(saml_request);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn hidpi(mut self, hidpi: bool) -> Self {
|
||||
self.hidpi = hidpi;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn fix_openssl(mut self, fix_openssl: bool) -> Self {
|
||||
self.fix_openssl = fix_openssl;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn clean(mut self, clean: bool) -> Self {
|
||||
self.clean = clean;
|
||||
self
|
||||
}
|
||||
|
||||
/// Launch the authenticator binary as the current user or SUDO_USER if available.
|
||||
pub async fn launch(self) -> anyhow::Result<Credential> {
|
||||
let mut auth_cmd = Command::new(GP_AUTH_BINARY);
|
||||
auth_cmd.arg(self.server);
|
||||
|
||||
if let Some(user_agent) = self.user_agent {
|
||||
auth_cmd.arg("--user-agent").arg(user_agent);
|
||||
}
|
||||
|
||||
if let Some(saml_request) = self.saml_request {
|
||||
auth_cmd.arg("--saml-request").arg(saml_request);
|
||||
}
|
||||
|
||||
if self.fix_openssl {
|
||||
auth_cmd.arg("--fix-openssl");
|
||||
}
|
||||
|
||||
if self.hidpi {
|
||||
auth_cmd.arg("--hidpi");
|
||||
}
|
||||
|
||||
if self.clean {
|
||||
auth_cmd.arg("--clean");
|
||||
}
|
||||
|
||||
let mut non_root_cmd = auth_cmd.into_non_root()?;
|
||||
let output = non_root_cmd
|
||||
.kill_on_drop(true)
|
||||
.stdout(Stdio::piped())
|
||||
.spawn()?
|
||||
.wait_with_output()
|
||||
.await?;
|
||||
|
||||
let auth_result: SamlAuthResult = serde_json::from_slice(&output.stdout)
|
||||
.map_err(|_| anyhow::anyhow!("Failed to parse auth data"))?;
|
||||
|
||||
match auth_result {
|
||||
SamlAuthResult::Success(auth_data) => Credential::try_from(auth_data),
|
||||
SamlAuthResult::Failure(msg) => Err(anyhow::anyhow!(msg)),
|
||||
}
|
||||
}
|
||||
}
|
64
crates/gpapi/src/process/command_traits.rs
Normal file
64
crates/gpapi/src/process/command_traits.rs
Normal file
@@ -0,0 +1,64 @@
|
||||
use anyhow::bail;
|
||||
use std::{env, ffi::OsStr};
|
||||
use tokio::process::Command;
|
||||
use users::{os::unix::UserExt, User};
|
||||
|
||||
pub trait CommandExt {
|
||||
fn new_pkexec<S: AsRef<OsStr>>(program: S) -> Command;
|
||||
fn into_non_root(self) -> anyhow::Result<Command>;
|
||||
}
|
||||
|
||||
impl CommandExt for Command {
|
||||
fn new_pkexec<S: AsRef<OsStr>>(program: S) -> Command {
|
||||
let mut cmd = Command::new("pkexec");
|
||||
cmd
|
||||
.arg("--disable-internal-agent")
|
||||
.arg("--user")
|
||||
.arg("root")
|
||||
.arg(program);
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
fn into_non_root(mut self) -> anyhow::Result<Command> {
|
||||
let user =
|
||||
get_non_root_user().map_err(|_| anyhow::anyhow!("{:?} cannot be run as root", self))?;
|
||||
|
||||
self
|
||||
.env("HOME", user.home_dir())
|
||||
.env("USER", user.name())
|
||||
.env("LOGNAME", user.name())
|
||||
.env("USERNAME", user.name())
|
||||
.uid(user.uid())
|
||||
.gid(user.primary_group_id());
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_non_root_user() -> anyhow::Result<User> {
|
||||
let current_user = whoami::username();
|
||||
|
||||
let user = if current_user == "root" {
|
||||
get_real_user()?
|
||||
} else {
|
||||
users::get_user_by_name(¤t_user)
|
||||
.ok_or_else(|| anyhow::anyhow!("User ({}) not found", current_user))?
|
||||
};
|
||||
|
||||
if user.uid() == 0 {
|
||||
bail!("Non-root user not found")
|
||||
}
|
||||
|
||||
Ok(user)
|
||||
}
|
||||
|
||||
fn get_real_user() -> anyhow::Result<User> {
|
||||
// Read the UID from SUDO_UID or PKEXEC_UID environment variable if available.
|
||||
let uid = match env::var("SUDO_UID") {
|
||||
Ok(uid) => uid.parse::<u32>()?,
|
||||
_ => env::var("PKEXEC_UID")?.parse::<u32>()?,
|
||||
};
|
||||
|
||||
users::get_user_by_uid(uid).ok_or_else(|| anyhow::anyhow!("User not found"))
|
||||
}
|
91
crates/gpapi/src/process/gui_launcher.rs
Normal file
91
crates/gpapi/src/process/gui_launcher.rs
Normal file
@@ -0,0 +1,91 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
path::PathBuf,
|
||||
process::{ExitStatus, Stdio},
|
||||
};
|
||||
|
||||
use tokio::{io::AsyncWriteExt, process::Command};
|
||||
|
||||
use crate::{utils::base64, GP_GUI_BINARY};
|
||||
|
||||
use super::command_traits::CommandExt;
|
||||
|
||||
pub struct GuiLauncher {
|
||||
program: PathBuf,
|
||||
api_key: Option<Vec<u8>>,
|
||||
minimized: bool,
|
||||
envs: Option<HashMap<String, String>>,
|
||||
}
|
||||
|
||||
impl Default for GuiLauncher {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl GuiLauncher {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
program: GP_GUI_BINARY.into(),
|
||||
api_key: None,
|
||||
minimized: false,
|
||||
envs: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn envs<T: Into<Option<HashMap<String, String>>>>(mut self, envs: T) -> Self {
|
||||
self.envs = envs.into();
|
||||
self
|
||||
}
|
||||
|
||||
pub fn api_key(mut self, api_key: Vec<u8>) -> Self {
|
||||
self.api_key = Some(api_key);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn minimized(mut self, minimized: bool) -> Self {
|
||||
self.minimized = minimized;
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn launch(&self) -> anyhow::Result<ExitStatus> {
|
||||
let mut cmd = Command::new(&self.program);
|
||||
|
||||
if let Some(envs) = &self.envs {
|
||||
cmd.env_clear();
|
||||
cmd.envs(envs);
|
||||
}
|
||||
|
||||
if self.api_key.is_some() {
|
||||
cmd.arg("--api-key-on-stdin");
|
||||
}
|
||||
|
||||
if self.minimized {
|
||||
cmd.arg("--minimized");
|
||||
}
|
||||
|
||||
let mut non_root_cmd = cmd.into_non_root()?;
|
||||
|
||||
let mut child = non_root_cmd
|
||||
.kill_on_drop(true)
|
||||
.stdin(Stdio::piped())
|
||||
.spawn()?;
|
||||
|
||||
let mut stdin = child
|
||||
.stdin
|
||||
.take()
|
||||
.ok_or_else(|| anyhow::anyhow!("Failed to open stdin"))?;
|
||||
|
||||
if let Some(api_key) = &self.api_key {
|
||||
let api_key = base64::encode(api_key);
|
||||
tokio::spawn(async move {
|
||||
stdin.write_all(api_key.as_bytes()).await.unwrap();
|
||||
drop(stdin);
|
||||
});
|
||||
}
|
||||
|
||||
let exit_status = child.wait().await?;
|
||||
|
||||
Ok(exit_status)
|
||||
}
|
||||
}
|
5
crates/gpapi/src/process/mod.rs
Normal file
5
crates/gpapi/src/process/mod.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
pub(crate) mod command_traits;
|
||||
|
||||
pub mod auth_launcher;
|
||||
pub mod gui_launcher;
|
||||
pub mod service_launcher;
|
72
crates/gpapi/src/process/service_launcher.rs
Normal file
72
crates/gpapi/src/process/service_launcher.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
use std::{
|
||||
fs::File,
|
||||
path::PathBuf,
|
||||
process::{ExitStatus, Stdio},
|
||||
};
|
||||
|
||||
use tokio::process::Command;
|
||||
|
||||
use crate::GP_SERVICE_BINARY;
|
||||
|
||||
use super::command_traits::CommandExt;
|
||||
|
||||
pub struct ServiceLauncher {
|
||||
program: PathBuf,
|
||||
minimized: bool,
|
||||
env_file: Option<String>,
|
||||
log_file: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for ServiceLauncher {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl ServiceLauncher {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
program: GP_SERVICE_BINARY.into(),
|
||||
minimized: false,
|
||||
env_file: None,
|
||||
log_file: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn minimized(mut self, minimized: bool) -> Self {
|
||||
self.minimized = minimized;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn env_file(mut self, env_file: &str) -> Self {
|
||||
self.env_file = Some(env_file.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn log_file(mut self, log_file: &str) -> Self {
|
||||
self.log_file = Some(log_file.to_string());
|
||||
self
|
||||
}
|
||||
|
||||
pub async fn launch(&self) -> anyhow::Result<ExitStatus> {
|
||||
let mut cmd = Command::new_pkexec(&self.program);
|
||||
|
||||
if self.minimized {
|
||||
cmd.arg("--minimized");
|
||||
}
|
||||
|
||||
if let Some(env_file) = &self.env_file {
|
||||
cmd.arg("--env-file").arg(env_file);
|
||||
}
|
||||
|
||||
if let Some(log_file) = &self.log_file {
|
||||
let log_file = File::create(log_file)?;
|
||||
let stdio = Stdio::from(log_file);
|
||||
cmd.stderr(stdio);
|
||||
}
|
||||
|
||||
let exit_status = cmd.kill_on_drop(true).spawn()?.wait().await?;
|
||||
|
||||
Ok(exit_status)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user