feat: gpauth support macos

This commit is contained in:
Kevin Yue
2025-01-05 23:42:03 +08:00
parent 0c9b8e6c63
commit af9b026b14
40 changed files with 961 additions and 824 deletions

View File

@@ -1,21 +1,19 @@
use std::borrow::Cow;
use auth::{auth_prelogin, Authenticator, BrowserAuthenticator};
use auth::{auth_prelogin, BrowserAuthenticator};
use clap::Parser;
use gpapi::{
auth::{SamlAuthData, SamlAuthResult},
clap::{args::Os, handle_error, Args},
clap::{args::Os, handle_error, Args, InfoLevelVerbosity},
gp_params::{ClientOs, GpParams},
utils::{normalize_server, openssl},
GP_USER_AGENT,
};
use log::{info, LevelFilter};
use log::info;
use serde_json::json;
use tempfile::NamedTempFile;
const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
#[derive(Parser, Clone)]
#[derive(Parser)]
#[command(
version = VERSION,
author,
@@ -33,7 +31,7 @@ const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::dat
See 'gpauth -h' for more information.
"
)]
pub(crate) struct Cli {
struct Cli {
#[arg(help = "The portal server to authenticate")]
server: String,
@@ -75,6 +73,9 @@ pub(crate) struct Cli {
#[cfg(feature = "webview-auth")]
#[arg(long, help = "Clean the cache of the embedded browser")]
pub clean: bool,
#[command(flatten)]
verbose: InfoLevelVerbosity,
}
impl Args for Cli {
@@ -110,28 +111,26 @@ impl Cli {
let openssl_conf = self.prepare_env()?;
let server = normalize_server(&self.server)?;
let server: &'static str = Box::leak(server.into_boxed_str());
let gp_params: &'static GpParams = Box::leak(Box::new(self.build_gp_params()));
let gp_params = self.build_gp_params();
let auth_request = match self.saml_request.as_deref() {
Some(auth_request) => Cow::Borrowed(auth_request),
None => Cow::Owned(auth_prelogin(server, gp_params).await?),
Some(auth_request) => auth_request.to_string(),
None => auth_prelogin(&server, &gp_params).await?,
};
let auth_request: &'static str = Box::leak(auth_request.into_owned().into_boxed_str());
let authenticator = Authenticator::new(&server, gp_params).with_auth_request(&auth_request);
#[cfg(feature = "webview-auth")]
let browser = self
.browser
.as_deref()
.or_else(|| self.default_browser.then_some("default"));
.or_else(|| self.default_browser.then(|| "default"));
#[cfg(not(feature = "webview-auth"))]
let browser = self.browser.as_deref().or(Some("default"));
if browser.is_some() {
let auth_result = authenticator.browser_authenticate(browser).await;
if let Some(browser) = browser {
let authenticator = BrowserAuthenticator::new(&auth_request, browser);
let auth_result = authenticator.authenticate().await;
print_auth_result(auth_result);
// explicitly drop openssl_conf to avoid the unused variable warning
@@ -140,7 +139,7 @@ impl Cli {
}
#[cfg(feature = "webview-auth")]
crate::webview_auth::authenticate(&self, authenticator, openssl_conf)?;
crate::webview_auth::authenticate(server, gp_params, auth_request, self.clean, openssl_conf).await?;
Ok(())
}
@@ -158,14 +157,16 @@ impl Cli {
}
}
fn init_logger() {
env_logger::builder().filter_level(LevelFilter::Info).init();
fn init_logger(cli: &Cli) {
env_logger::builder()
.filter_level(cli.verbose.log_level_filter())
.init();
}
pub async fn run() {
let cli = Cli::parse();
init_logger();
init_logger(&cli);
info!("gpauth started: {}", VERSION);
if let Err(err) = cli.run().await {

View File

@@ -1,6 +1,7 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
mod cli;
#[cfg(feature = "webview-auth")]
mod webview_auth;

View File

@@ -1,23 +1,28 @@
use auth::{Authenticator, WebviewAuthenticator};
use auth::WebviewAuthenticator;
use gpapi::gp_params::GpParams;
use log::info;
use tauri::RunEvent;
use tempfile::NamedTempFile;
use crate::cli::{print_auth_result, Cli};
use crate::cli::print_auth_result;
pub fn authenticate(
cli: &Cli,
authenticator: Authenticator<'static>,
pub async fn authenticate(
server: String,
gp_params: GpParams,
auth_request: String,
clean: bool,
mut openssl_conf: Option<NamedTempFile>,
) -> anyhow::Result<()> {
let authenticator = authenticator.with_clean(cli.clean);
tauri::Builder::default()
.setup(move |app| {
let app_handle = app.handle().clone();
tauri::async_runtime::spawn(async move {
let auth_result = authenticator.webview_authenticate(&app_handle).await;
let authenticator = WebviewAuthenticator::new(&server, &gp_params)
.with_auth_request(&auth_request)
.with_clean(clean);
let auth_result = authenticator.authenticate(&app_handle).await;
print_auth_result(auth_result);
// Ensure the app exits after the authentication process

View File

@@ -2,10 +2,10 @@ use std::{env::temp_dir, fs::File};
use clap::{Parser, Subcommand};
use gpapi::{
clap::{handle_error, Args},
clap::{handle_error, Args, InfoLevelVerbosity},
utils::openssl,
};
use log::{info, LevelFilter};
use log::info;
use tempfile::NamedTempFile;
use crate::{
@@ -16,9 +16,10 @@ use crate::{
const VERSION: &str = concat!(env!("CARGO_PKG_VERSION"), " (", compile_time::date_str!(), ")");
pub(crate) struct SharedArgs {
pub(crate) struct SharedArgs<'a> {
pub(crate) fix_openssl: bool,
pub(crate) ignore_tls_errors: bool,
pub(crate) verbose: &'a InfoLevelVerbosity,
}
#[derive(Subcommand)]
@@ -60,6 +61,9 @@ struct Cli {
fix_openssl: bool,
#[arg(long, help = "Ignore the TLS errors")]
ignore_tls_errors: bool,
#[command(flatten)]
verbose: InfoLevelVerbosity,
}
impl Args for Cli {
@@ -89,6 +93,7 @@ impl Cli {
let shared_args = SharedArgs {
fix_openssl: self.fix_openssl,
ignore_tls_errors: self.ignore_tls_errors,
verbose: &self.verbose,
};
if self.ignore_tls_errors {
@@ -103,12 +108,12 @@ impl Cli {
}
}
fn init_logger(command: &CliCommand) {
fn init_logger(cli: &Cli) {
let mut builder = env_logger::builder();
builder.filter_level(LevelFilter::Info);
builder.filter_level(cli.verbose.log_level_filter());
// Output the log messages to a file if the command is the auth callback
if let CliCommand::LaunchGui(args) = command {
if let CliCommand::LaunchGui(args) = &cli.command {
let auth_data = args.auth_data.as_deref().unwrap_or_default();
if !auth_data.is_empty() {
if let Ok(log_file) = File::create(temp_dir().join("gpcallback.log")) {
@@ -124,7 +129,7 @@ fn init_logger(command: &CliCommand) {
pub(crate) async fn run() {
let cli = Cli::parse();
init_logger(&cli.command);
init_logger(&cli);
info!("gpclient started: {}", VERSION);

View File

@@ -128,7 +128,7 @@ impl ConnectArgs {
pub(crate) struct ConnectHandler<'a> {
args: &'a ConnectArgs,
shared_args: &'a SharedArgs,
shared_args: &'a SharedArgs<'a>,
latest_key_password: RefCell<Option<String>>,
}
@@ -364,7 +364,8 @@ impl<'a> ConnectHandler<'a> {
.os_version(Some(&os_version))
.fix_openssl(self.shared_args.fix_openssl)
.ignore_tls_errors(self.shared_args.ignore_tls_errors)
.browser(browser);
.browser(browser)
.verbose(self.shared_args.verbose);
#[cfg(feature = "webview-auth")]
let use_default_browser = prelogin.support_default_browser() && self.args.default_browser;

View File

@@ -10,7 +10,7 @@ license.workspace = true
tauri-build = { version = "2", features = [] }
[dependencies]
gpapi = { path = "../../../crates/gpapi", features = ["tauri"] }
gpapi = { path = "../../../crates/gpapi", features = ["tauri", "clap"] }
tauri.workspace = true
tokio.workspace = true

View File

@@ -1,6 +1,9 @@
use clap::Parser;
use gpapi::utils::{base64, env_utils};
use log::{info, LevelFilter};
use gpapi::{
clap::InfoLevelVerbosity,
utils::{base64, env_utils},
};
use log::info;
use crate::app::App;
@@ -15,6 +18,9 @@ struct Cli {
#[arg(long, default_value = env!("CARGO_PKG_VERSION"), help = "The version of the GUI")]
gui_version: String,
#[command(flatten)]
verbose: InfoLevelVerbosity,
}
impl Cli {
@@ -41,14 +47,16 @@ impl Cli {
}
}
fn init_logger() {
env_logger::builder().filter_level(LevelFilter::Info).init();
fn init_logger(cli: &Cli) {
env_logger::builder()
.filter_level(cli.verbose.log_level_filter())
.init();
}
pub fn run() {
let cli = Cli::parse();
init_logger();
init_logger(&cli);
info!("gpgui-helper started: {}", VERSION);
if let Err(e) = cli.run() {

View File

@@ -5,7 +5,7 @@ edition.workspace = true
license.workspace = true
[dependencies]
gpapi = { path = "../../crates/gpapi" }
gpapi = { path = "../../crates/gpapi", features = ["clap"] }
openconnect = { path = "../../crates/openconnect" }
clap.workspace = true
anyhow.workspace = true

View File

@@ -3,13 +3,14 @@ use std::{collections::HashMap, io::Write};
use anyhow::bail;
use clap::Parser;
use gpapi::clap::InfoLevelVerbosity;
use gpapi::{
process::gui_launcher::GuiLauncher,
service::{request::WsRequest, vpn_state::VpnState},
utils::{crypto::generate_key, env_utils, lock_file::LockFile, redact::Redaction, shutdown_signal},
GP_SERVICE_LOCK_FILE,
};
use log::{info, warn, LevelFilter};
use log::{info, warn};
use tokio::sync::{mpsc, watch};
use crate::{vpn_task::VpnTask, ws_server::WsServer};
@@ -26,6 +27,9 @@ struct Cli {
#[cfg(debug_assertions)]
#[clap(long)]
no_gui: bool,
#[command(flatten)]
verbose: InfoLevelVerbosity,
}
impl Cli {
@@ -102,12 +106,12 @@ impl Cli {
}
}
fn init_logger() -> Arc<Redaction> {
fn init_logger(cli: &Cli) -> Arc<Redaction> {
let redaction = Arc::new(Redaction::new());
let redaction_clone = Arc::clone(&redaction);
// let target = Box::new(File::create("log.txt").expect("Can't create file"));
env_logger::builder()
.filter_level(LevelFilter::Info)
.filter_level(cli.verbose.log_level_filter())
.format(move |buf, record| {
let timestamp = buf.timestamp();
writeln!(
@@ -153,7 +157,7 @@ async fn launch_gui(envs: Option<HashMap<String, String>>, api_key: Vec<u8>, mut
pub async fn run() {
let mut cli = Cli::parse();
let redaction = init_logger();
let redaction = init_logger(&cli);
info!("gpservice started: {}", VERSION);
if let Err(e) = cli.run(redaction).await {