mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	refactor: refine auth window
This commit is contained in:
		| @@ -1,20 +1,21 @@ | ||||
| use log::{debug, warn}; | ||||
| use regex::Regex; | ||||
| use serde::{Deserialize, Serialize}; | ||||
| use std::sync::{Arc}; | ||||
| use tauri::{AppHandle, Manager, WindowBuilder, WindowEvent::CloseRequested, WindowUrl}; | ||||
| use url::Url; | ||||
| use std::{sync::Arc, time::Duration}; | ||||
| use tauri::EventHandler; | ||||
| use tauri::{AppHandle, Manager, Window, WindowBuilder, WindowEvent::CloseRequested, WindowUrl}; | ||||
| use tokio::sync::{mpsc, Mutex}; | ||||
| use tokio::time::timeout; | ||||
| use webkit2gtk::{ | ||||
|     gio::Cancellable, glib::GString, traits::WebViewExt, LoadEvent, URIResponseExt, WebResource, | ||||
|     WebResourceExt, | ||||
| }; | ||||
|  | ||||
| const AUTH_WINDOW_LABEL: &str = "auth_window"; | ||||
| const AUTH_SUCCESS_EVENT: &str = "auth-success"; | ||||
| const AUTH_ERROR_EVENT: &str = "auth-error"; | ||||
| const AUTH_CANCEL_EVENT: &str = "auth-cancel"; | ||||
| const AUTH_REQUEST_EVENT: &str = "auth-request"; | ||||
|  | ||||
| #[derive(Debug, Deserialize)] | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
| pub(crate) enum SamlBinding { | ||||
|     #[serde(rename = "REDIRECT")] | ||||
|     Redirect, | ||||
| @@ -22,30 +23,33 @@ pub(crate) enum SamlBinding { | ||||
|     Post, | ||||
| } | ||||
|  | ||||
| pub(crate) struct AuthOptions { | ||||
| #[derive(Debug, Clone, Deserialize)] | ||||
| pub(crate) struct AuthRequest { | ||||
|     #[serde(alias = "samlBinding")] | ||||
|     saml_binding: SamlBinding, | ||||
|     saml_request: String, | ||||
|     user_agent: String, | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Deserialize)] | ||||
| struct AuthRequestPayload { | ||||
|     #[serde(alias = "samlRequest")] | ||||
|     saml_request: String, | ||||
| } | ||||
|  | ||||
| impl AuthOptions { | ||||
|     pub fn new(saml_binding: SamlBinding, saml_request: String, user_agent: String) -> Self { | ||||
| impl AuthRequest { | ||||
|     pub fn new(saml_binding: SamlBinding, saml_request: String) -> Self { | ||||
|         Self { | ||||
|             saml_binding, | ||||
|             saml_request, | ||||
|             user_agent, | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| impl TryFrom<Option<&str>> for AuthRequest { | ||||
|     type Error = serde_json::Error; | ||||
|  | ||||
|     fn try_from(value: Option<&str>) -> Result<Self, Self::Error> { | ||||
|         serde_json::from_str(value.unwrap_or("{}")) | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize)] | ||||
| pub struct AuthData { | ||||
| pub(crate) struct AuthData { | ||||
|     username: Option<String>, | ||||
|     prelogin_cookie: Option<String>, | ||||
|     portal_userauthcookie: Option<String>, | ||||
| @@ -72,183 +76,261 @@ impl AuthData { | ||||
|  | ||||
| #[derive(Debug)] | ||||
| enum AuthError { | ||||
|     NotFound, | ||||
|     Invalid, | ||||
|     TokenNotFound, | ||||
|     TokenInvalid, | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| struct AuthEventEmitter { | ||||
|     app_handle: AppHandle, | ||||
| enum AuthEvent { | ||||
|     Request(AuthRequest), | ||||
|     Success(AuthData), | ||||
|     Error(AuthError), | ||||
|     Cancel, | ||||
| } | ||||
|  | ||||
| impl AuthEventEmitter { | ||||
|     fn new(app_handle: AppHandle) -> Self { | ||||
|         Self { app_handle } | ||||
|     } | ||||
| pub(crate) async fn saml_login( | ||||
|     auth_request: AuthRequest, | ||||
|     ua: &str, | ||||
|     app_handle: &AppHandle, | ||||
| ) -> tauri::Result<Option<AuthData>> { | ||||
|     let (event_tx, event_rx) = mpsc::channel::<AuthEvent>(8); | ||||
|     let window = build_window(app_handle, ua)?; | ||||
|     setup_webview(&window, event_tx.clone())?; | ||||
|     let handler_id = setup_window(&window, event_tx); | ||||
|  | ||||
|     fn emit_success(&self, saml_result: AuthData) { | ||||
|         self.app_handle.emit_all(AUTH_SUCCESS_EVENT, saml_result); | ||||
|         if let Some(window) = self.app_handle.get_window(AUTH_WINDOW_LABEL) { | ||||
|             window.close(); | ||||
|     match process(&window, event_rx, auth_request).await { | ||||
|         Ok(auth_data) => { | ||||
|             window.unlisten(handler_id); | ||||
|             Ok(auth_data) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn emit_error(&self, error: String) { | ||||
|         self.app_handle.emit_all(AUTH_ERROR_EVENT, error); | ||||
|     } | ||||
|  | ||||
|     fn emit_cancel(&self) { | ||||
|         self.app_handle.emit_all(AUTH_CANCEL_EVENT, ()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| #[derive(Debug)] | ||||
| pub(crate) struct AuthWindow { | ||||
|     event_emitter: Arc<AuthEventEmitter>, | ||||
|     app_handle: AppHandle, | ||||
|     saml_binding: SamlBinding, | ||||
|     user_agent: String, | ||||
| } | ||||
|  | ||||
| impl AuthWindow { | ||||
|     pub fn new(app_handle: AppHandle, saml_binding: SamlBinding, user_agent: String) -> Self { | ||||
|         Self { | ||||
|             event_emitter: Arc::new(AuthEventEmitter::new(app_handle.clone())), | ||||
|             app_handle, | ||||
|             saml_binding, | ||||
|             user_agent, | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     pub fn process(&self, saml_request: String) -> tauri::Result<()> { | ||||
|         let url = self.window_url(&saml_request)?; | ||||
|         let window = WindowBuilder::new(&self.app_handle, AUTH_WINDOW_LABEL, url) | ||||
|             .title("GlobalProtect Login") | ||||
|             .user_agent(&self.user_agent) | ||||
|             .always_on_top(true) | ||||
|             .focused(true) | ||||
|             .center() | ||||
|             .build()?; | ||||
|  | ||||
|         let event_emitter = self.event_emitter.clone(); | ||||
|         let is_post = matches!(self.saml_binding, SamlBinding::Post); | ||||
|  | ||||
|         window.with_webview(move |wv| { | ||||
|             let wv = wv.inner(); | ||||
|             // Load SAML request as HTML if POST binding is used | ||||
|             if is_post { | ||||
|                 wv.load_html(&saml_request, None); | ||||
|             } | ||||
|             wv.connect_load_changed(move |wv, event| { | ||||
|                 if LoadEvent::Finished == event { | ||||
|                     if let Some(uri) = wv.uri() { | ||||
|                         if uri.is_empty() { | ||||
|                             println!("Empty URI"); | ||||
|                             event_emitter.emit_error("Empty URI".to_string()); | ||||
|                             return; | ||||
|                         } else { | ||||
|                             println!("Loaded URI: {}", uri); | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     if let Some(main_res) = wv.main_resource() { | ||||
|                         AuthResultParser::new(&event_emitter).parse(&main_res); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         })?; | ||||
|  | ||||
|         let event_emitter = self.event_emitter.clone(); | ||||
|         window.on_window_event(move |event| { | ||||
|             if let CloseRequested { .. } = event { | ||||
|                 event_emitter.emit_cancel(); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         let window_clone = window.clone(); | ||||
|         window.listen_global(AUTH_REQUEST_EVENT, move |event| { | ||||
|             let auth_request_payload: AuthRequestPayload = serde_json::from_str(event.payload().unwrap()).unwrap(); | ||||
|             let saml_request = auth_request_payload.saml_request; | ||||
|  | ||||
|             window_clone.with_webview(move |wv| { | ||||
|                 let wv = wv.inner(); | ||||
|                 if is_post { | ||||
|                     // Load SAML request as HTML if POST binding is used | ||||
|                     wv.load_html(&saml_request, None); | ||||
|                 } else { | ||||
|                     println!("Redirecting to SAML request URL: {}", saml_request); | ||||
|                     // Redirect to SAML request URL if REDIRECT binding is used | ||||
|                     wv.load_uri(&saml_request); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         Ok(()) | ||||
|     } | ||||
|  | ||||
|     fn window_url(&self, saml_request: &String) -> tauri::Result<WindowUrl> { | ||||
|         match self.saml_binding { | ||||
|             SamlBinding::Redirect => match Url::parse(saml_request) { | ||||
|                 Ok(url) => Ok(WindowUrl::External(url)), | ||||
|                 Err(err) => Err(tauri::Error::InvalidUrl(err)), | ||||
|             }, | ||||
|             SamlBinding::Post => Ok(WindowUrl::App("auth.html".into())), | ||||
|         Err(err) => { | ||||
|             window.unlisten(handler_id); | ||||
|             Err(err) | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| struct AuthResultParser<'a> { | ||||
|     event_emitter: &'a Arc<AuthEventEmitter>, | ||||
| fn build_window(app_handle: &AppHandle, ua: &str) -> tauri::Result<Window> { | ||||
|     let url = WindowUrl::App("auth.html".into()); | ||||
|     WindowBuilder::new(app_handle, AUTH_WINDOW_LABEL, url) | ||||
|         .visible(false) | ||||
|         .title("GlobalProtect Login") | ||||
|         .user_agent(ua) | ||||
|         .always_on_top(true) | ||||
|         .focused(true) | ||||
|         .center() | ||||
|         .build() | ||||
| } | ||||
|  | ||||
| impl<'a> AuthResultParser<'a> { | ||||
|     fn new(event_emitter: &'a Arc<AuthEventEmitter>) -> Self { | ||||
|         Self { event_emitter } | ||||
|     } | ||||
| fn setup_webview(window: &Window, event_tx: mpsc::Sender<AuthEvent>) -> tauri::Result<()> { | ||||
|     window.with_webview(move |wv| { | ||||
|         let wv = wv.inner(); | ||||
|         let event_tx = event_tx.clone(); | ||||
|  | ||||
|     fn parse(&self, main_res: &WebResource) { | ||||
|         if let Some(response) = main_res.response() { | ||||
|             if let Some(saml_result) = read_auth_result_from_response(&response) { | ||||
|                 // Got SAML result from HTTP headers | ||||
|                 println!("SAML result: {:?}", saml_result); | ||||
|                 self.event_emitter.emit_success(saml_result); | ||||
|         wv.connect_load_changed(move |wv, event| { | ||||
|             if LoadEvent::Finished != event { | ||||
|                 debug!("Skipping load event: {:?}", event); | ||||
|                 return; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         let event_emitter = self.event_emitter.clone(); | ||||
|         main_res.data(Cancellable::NONE, move |data| { | ||||
|             if let Ok(data) = data { | ||||
|                 let html = String::from_utf8_lossy(&data); | ||||
|                 match read_auth_result_from_html(&html) { | ||||
|                     Ok(saml_result) => { | ||||
|                         // Got SAML result from HTML | ||||
|                         println!("SAML result: {:?}", saml_result); | ||||
|                         event_emitter.emit_success(saml_result); | ||||
|                         return; | ||||
|                     } | ||||
|                     Err(AuthError::Invalid) => { | ||||
|                         // Invalid SAML result | ||||
|                         println!("Invalid SAML result"); | ||||
|                         event_emitter.emit_error("Invalid SAML result".to_string()) | ||||
|                     } | ||||
|                     Err(AuthError::NotFound) => { | ||||
|                         let has_form = html.contains("</form>"); | ||||
|                         if has_form { | ||||
|                             // SAML form found | ||||
|                             println!("SAML form found"); | ||||
|                         } else { | ||||
|                             // No SAML form found | ||||
|                             println!("No SAML form found"); | ||||
|                         } | ||||
|                     }, | ||||
|             let uri = wv.uri().unwrap_or("".into()); | ||||
|             // Empty URI indicates that an error occurred | ||||
|             if uri.is_empty() { | ||||
|                 warn!("Empty URI"); | ||||
|                 if let Err(err) = event_tx.blocking_send(AuthEvent::Error(AuthError::TokenInvalid)) | ||||
|                 { | ||||
|                     println!("Error sending event: {}", err); | ||||
|                 } | ||||
|                 return; | ||||
|             } | ||||
|             // TODO, redact URI | ||||
|             debug!("Loaded URI: {}", uri); | ||||
|  | ||||
|             if let Some(main_res) = wv.main_resource() { | ||||
|                 // AuthDataParser::new(&window_tx_clone).parse(&main_res); | ||||
|                 parse_auth_data(&main_res, event_tx.clone()); | ||||
|             } else { | ||||
|                 warn!("No main_resource"); | ||||
|             } | ||||
|         }); | ||||
|  | ||||
|         wv.connect_load_failed(|_wv, event, err_msg, err| { | ||||
|             println!("Load failed: {:?}, {}, {:?}", event, err_msg, err); | ||||
|             false | ||||
|         }); | ||||
|     }) | ||||
| } | ||||
|  | ||||
| fn setup_window(window: &Window, event_tx: mpsc::Sender<AuthEvent>) -> EventHandler { | ||||
|     let event_tx_clone = event_tx.clone(); | ||||
|     window.on_window_event(move |event| { | ||||
|         if let CloseRequested { api, .. } = event { | ||||
|             api.prevent_close(); | ||||
|             if let Err(err) = event_tx_clone.blocking_send(AuthEvent::Cancel) { | ||||
|                 println!("Error sending event: {}", err) | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     window.open_devtools(); | ||||
|  | ||||
|     window.listen_global(AUTH_REQUEST_EVENT, move |event| { | ||||
|         if let Ok(payload) = TryInto::<AuthRequest>::try_into(event.payload()) { | ||||
|             debug!("---------Received auth request"); | ||||
|  | ||||
|             let event_tx = event_tx.clone(); | ||||
|             let _ = tokio::spawn(async move { | ||||
|                 if let Err(err) = event_tx.send(AuthEvent::Request(payload)).await { | ||||
|                     warn!("Error sending event: {}", err); | ||||
|                 } | ||||
|             }); | ||||
|         } | ||||
|     }) | ||||
| } | ||||
|  | ||||
| async fn process( | ||||
|     window: &Window, | ||||
|     event_rx: mpsc::Receiver<AuthEvent>, | ||||
|     auth_request: AuthRequest, | ||||
| ) -> tauri::Result<Option<AuthData>> { | ||||
|     process_request(window, auth_request)?; | ||||
|  | ||||
|     let (close_tx, close_rx) = mpsc::channel::<()>(1); | ||||
|  | ||||
|     tokio::spawn(show_window_after_timeout(window.clone(), close_rx)); | ||||
|     process_auth_event(&window, event_rx, close_tx).await | ||||
| } | ||||
|  | ||||
| fn process_request(window: &Window, auth_request: AuthRequest) -> tauri::Result<()> { | ||||
|     let saml_request = auth_request.saml_request; | ||||
|     let is_post = matches!(auth_request.saml_binding, SamlBinding::Post); | ||||
|  | ||||
|     window.with_webview(move |wv| { | ||||
|         let wv = wv.inner(); | ||||
|         if is_post { | ||||
|             // Load SAML request as HTML if POST binding is used | ||||
|             wv.load_html(&saml_request, None); | ||||
|         } else { | ||||
|             println!("Redirecting to SAML request URL: {}", saml_request); | ||||
|             // Redirect to SAML request URL if REDIRECT binding is used | ||||
|             wv.load_uri(&saml_request); | ||||
|         } | ||||
|     }) | ||||
| } | ||||
|  | ||||
| async fn show_window_after_timeout(window: Window, mut close_rx: mpsc::Receiver<()>) { | ||||
|     // Show the window after 10 seconds | ||||
|     let duration = Duration::from_secs(10); | ||||
|     if let Err(_) = timeout(duration, close_rx.recv()).await { | ||||
|         println!("Final show window"); | ||||
|         show_window(&window); | ||||
|     } else { | ||||
|         println!("Window closed, cancel the final show window"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn read_auth_result_from_response(response: &webkit2gtk::URIResponse) -> Option<AuthData> { | ||||
| async fn process_auth_event( | ||||
|     window: &Window, | ||||
|     mut event_rx: mpsc::Receiver<AuthEvent>, | ||||
|     close_tx: mpsc::Sender<()>, | ||||
| ) -> tauri::Result<Option<AuthData>> { | ||||
|     let (cancel_timeout_tx, cancel_timeout_rx) = mpsc::channel::<()>(1); | ||||
|     let cancel_timeout_rx = Arc::new(Mutex::new(cancel_timeout_rx)); | ||||
|  | ||||
|     async fn close_window(window: &Window, close_tx: mpsc::Sender<()>) { | ||||
|         if let Err(err) = window.close() { | ||||
|             println!("Error closing window: {}", err); | ||||
|         } | ||||
|         if let Err(err) = close_tx.send(()).await { | ||||
|             warn!("Error sending the close event: {:?}", err); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     loop { | ||||
|         if let Some(auth_event) = event_rx.recv().await { | ||||
|             match auth_event { | ||||
|                 AuthEvent::Request(auth_request) => { | ||||
|                     println!("Got auth request: {:?}", auth_request); | ||||
|                     process_request(&window, auth_request)?; | ||||
|                 } | ||||
|                 AuthEvent::Success(auth_data) => { | ||||
|                     close_window(window, close_tx).await; | ||||
|                     return Ok(Some(auth_data)); | ||||
|                 } | ||||
|                 AuthEvent::Cancel => { | ||||
|                     close_window(window, close_tx).await; | ||||
|                     return Ok(None); | ||||
|                 } | ||||
|                 AuthEvent::Error(AuthError::TokenInvalid) => { | ||||
|                     if let Err(err) = cancel_timeout_tx.send(()).await { | ||||
|                         println!("Error sending event: {}", err); | ||||
|                     } | ||||
|                     if let Err(err) = | ||||
|                         window.emit_all(AUTH_ERROR_EVENT, "Invalid SAML result".to_string()) | ||||
|                     { | ||||
|                         warn!("Error emitting auth-error event: {:?}", err); | ||||
|                     } | ||||
|                 } | ||||
|                 AuthEvent::Error(AuthError::TokenNotFound) => { | ||||
|                     let cancel_timeout_rx = cancel_timeout_rx.clone(); | ||||
|                     tokio::spawn(handle_token_not_found(window.clone(), cancel_timeout_rx)); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| async fn handle_token_not_found(window: Window, cancel_timeout_rx: Arc<Mutex<mpsc::Receiver<()>>>) { | ||||
|     // Tokens not found, show the window in 5 seconds | ||||
|     match cancel_timeout_rx.try_lock() { | ||||
|         Ok(mut cancel_timeout_rx) => { | ||||
|             println!("Scheduling timeout"); | ||||
|             let duration = Duration::from_secs(5); | ||||
|             if let Err(_) = timeout(duration, cancel_timeout_rx.recv()).await { | ||||
|                 println!("Show window after timeout"); | ||||
|                 show_window(&window); | ||||
|             } else { | ||||
|                 println!("Cancel timeout"); | ||||
|             } | ||||
|         } | ||||
|         Err(_) => { | ||||
|             println!("Timeout already scheduled"); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn parse_auth_data(main_res: &WebResource, event_tx: mpsc::Sender<AuthEvent>) { | ||||
|     if let Some(response) = main_res.response() { | ||||
|         if let Some(saml_result) = read_auth_data_from_response(&response) { | ||||
|             // Got SAML result from HTTP headers | ||||
|             println!("SAML result: {:?}", saml_result); | ||||
|             send_auth_data(&event_tx, saml_result); | ||||
|             return; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     let event_tx = event_tx.clone(); | ||||
|     main_res.data(Cancellable::NONE, move |data| { | ||||
|         if let Ok(data) = data { | ||||
|             let html = String::from_utf8_lossy(&data); | ||||
|             match read_auth_data_from_html(&html) { | ||||
|                 Ok(saml_result) => { | ||||
|                     // Got SAML result from HTML | ||||
|                     println!("SAML result: {:?}", saml_result); | ||||
|                     send_auth_data(&event_tx, saml_result); | ||||
|                 } | ||||
|                 Err(err) => { | ||||
|                     println!("Auth error: {:?}", err); | ||||
|                     if let Err(err) = event_tx.blocking_send(AuthEvent::Error(err)) { | ||||
|                         println!("Error sending event: {}", err) | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     }); | ||||
| } | ||||
|  | ||||
| fn read_auth_data_from_response(response: &webkit2gtk::URIResponse) -> Option<AuthData> { | ||||
|     response.http_headers().and_then(|mut headers| { | ||||
|         let saml_result = AuthData::new( | ||||
|             headers.get("saml-username").map(GString::into), | ||||
| @@ -264,14 +346,13 @@ fn read_auth_result_from_response(response: &webkit2gtk::URIResponse) -> Option< | ||||
|     }) | ||||
| } | ||||
|  | ||||
| fn read_auth_result_from_html(html: &str) -> Result<AuthData, AuthError> { | ||||
| fn read_auth_data_from_html(html: &str) -> Result<AuthData, AuthError> { | ||||
|     let saml_auth_status = parse_xml_tag(html, "saml-auth-status"); | ||||
|      | ||||
|  | ||||
|     match saml_auth_status { | ||||
|         Some(status) if status == "1" => extract_auth_data(html).ok_or(AuthError::Invalid), | ||||
|         Some(status) if status == "-1" => Err(AuthError::Invalid), | ||||
|         _ => Err(AuthError::NotFound), | ||||
|         Some(status) if status == "1" => extract_auth_data(html).ok_or(AuthError::TokenInvalid), | ||||
|         Some(status) if status == "-1" => Err(AuthError::TokenInvalid), | ||||
|         _ => Err(AuthError::TokenNotFound), | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -295,3 +376,22 @@ fn parse_xml_tag(html: &str, tag: &str) -> Option<String> { | ||||
|         .and_then(|captures| captures.get(1)) | ||||
|         .map(|m| m.as_str().to_string()) | ||||
| } | ||||
|  | ||||
| fn send_auth_data(event_tx: &mpsc::Sender<AuthEvent>, saml_result: AuthData) { | ||||
|     if let Err(err) = event_tx.blocking_send(AuthEvent::Success(saml_result)) { | ||||
|         println!("Error sending event: {}", err) | ||||
|     } | ||||
| } | ||||
|  | ||||
| fn show_window(window: &Window) { | ||||
|     match window.is_visible() { | ||||
|         Ok(true) => { | ||||
|             println!("Window is already visible"); | ||||
|         } | ||||
|         _ => { | ||||
|             if let Err(err) = window.show() { | ||||
|                 println!("Error showing window: {}", err); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,7 +3,7 @@ | ||||
|     windows_subsystem = "windows" | ||||
| )] | ||||
|  | ||||
| use auth::{SamlBinding, AuthWindow}; | ||||
| use auth::{AuthData, AuthRequest, SamlBinding}; | ||||
| use env_logger::Env; | ||||
| use gpcommon::{Client, ServerApiError, VpnStatus}; | ||||
| use serde::Serialize; | ||||
| @@ -37,13 +37,9 @@ async fn saml_login( | ||||
|     binding: SamlBinding, | ||||
|     request: String, | ||||
|     app_handle: AppHandle, | ||||
| ) -> tauri::Result<()> { | ||||
|     let auth_window = AuthWindow::new(app_handle, binding, String::from("PAN GlobalProtect")); | ||||
|     if let Err(err) = auth_window.process(request) { | ||||
|         println!("Error processing auth window: {}", err); | ||||
|         return Err(err); | ||||
|     } | ||||
|     Ok(()) | ||||
| ) -> tauri::Result<Option<AuthData>> { | ||||
|     let ua = "PAN GlobalProtect"; | ||||
|     auth::saml_login(AuthRequest::new(binding, request), ua, &app_handle).await | ||||
| } | ||||
|  | ||||
| #[derive(Debug, Clone, Serialize)] | ||||
|   | ||||
		Reference in New Issue
	
	Block a user