diff --git a/crates/auth/src/webview.rs b/crates/auth/src/webview.rs index 4b0c337..6d9def1 100644 --- a/crates/auth/src/webview.rs +++ b/crates/auth/src/webview.rs @@ -1,5 +1,5 @@ mod auth_messenger; -mod auth_response; +mod response_reader; mod webview_auth; #[cfg_attr(not(target_os = "macos"), path = "webview/unix.rs")] diff --git a/crates/auth/src/webview/macos.rs b/crates/auth/src/webview/macos.rs index 43c4395..4c20762 100644 --- a/crates/auth/src/webview/macos.rs +++ b/crates/auth/src/webview/macos.rs @@ -8,32 +8,29 @@ use objc2::{ use objc2_foundation::{NSError, NSHTTPURLResponse, NSString}; use wry::WebViewExtMacOS; -use super::{auth_messenger::AuthError, navigation_delegate::NavigationDelegate}; +use super::{auth_messenger::AuthError, navigation_delegate::NavigationDelegate, response_reader::ResponseReader}; pub struct AuthResponse { response: Option>, body: Option, } -impl AuthResponse { - pub fn url(&self) -> Option { +impl ResponseReader for AuthResponse { + fn url(&self) -> Option { let response = self.response.as_ref()?; let url = unsafe { response.URL().and_then(|url| url.absoluteString()) }; url.map(|u| u.to_string()) } - pub fn get_header(&self, key: &str) -> Option { + fn get_header(&self, key: &str) -> Option { let response = self.response.as_ref()?; let value = unsafe { response.valueForHTTPHeaderField(&NSString::from_str(key)) }; value.map(|v| v.to_string()) } - pub fn get_body(&self, cb: F) - where - F: FnOnce(anyhow::Result>>) + 'static, - { + fn get_body(&self, cb: Box>>) + 'static>) { if let Some(body) = self.body.as_deref() { cb(Ok(Some(Cow::Borrowed(body)))); } else { @@ -84,7 +81,7 @@ where let proto_delegate = ProtocolObject::from_ref(delegate.as_ref()); unsafe { wv.setNavigationDelegate(Some(proto_delegate)); - // The UI will freeze if we don't call this method + // The UI will freeze if we don't call this method, but it's not clear why. let _ = wv.navigationDelegate(); }; } diff --git a/crates/auth/src/webview/auth_response.rs b/crates/auth/src/webview/response_reader.rs similarity index 82% rename from crates/auth/src/webview/auth_response.rs rename to crates/auth/src/webview/response_reader.rs index 1b20aee..c8c111f 100644 --- a/crates/auth/src/webview/auth_response.rs +++ b/crates/auth/src/webview/response_reader.rs @@ -1,3 +1,5 @@ +use std::borrow::Cow; + use gpapi::{ auth::{AuthDataParseResult, SamlAuthData}, error::AuthDataParseError, @@ -7,17 +9,25 @@ use regex::Regex; use crate::webview::auth_messenger::AuthError; -use super::{auth_messenger::AuthResult, platform_impl::AuthResponse}; +use super::auth_messenger::AuthResult; -fn is_acs_endpoint(auth_response: &AuthResponse) -> bool { +pub trait ResponseReader { + fn url(&self) -> Option; + + fn get_header(&self, key: &str) -> Option; + + fn get_body(&self, cb: Box>>) + 'static>); +} + +fn is_acs_endpoint(auth_response: &impl ResponseReader) -> bool { auth_response.url().map_or(false, |url| url.ends_with("/SAML20/SP/ACS")) } -pub fn read_auth_data(auth_response: AuthResponse, cb: F) +pub fn read_auth_data(auth_response: &impl ResponseReader, cb: F) where F: Fn(AuthResult) + 'static, { - match read_from_headers(&auth_response) { + match read_from_headers(auth_response) { Ok(auth_data) => { info!("Found auth data in headers"); cb(Ok(auth_data)) @@ -26,8 +36,8 @@ where Err(header_err) => { info!("Failed to read auth data from headers: {}", header_err); - let is_acs_endpoint = is_acs_endpoint(&auth_response); - read_from_body(&auth_response, move |auth_result| { + let is_acs_endpoint = is_acs_endpoint(auth_response); + read_from_body(auth_response, move |auth_result| { // If the endpoint is `/SAML20/SP/ACS` and no auth data found in body, it should be considered as invalid let auth_result = auth_result.map_err(move |e| { info!("Failed to read auth data from body: {}", e); @@ -44,7 +54,7 @@ where } } -fn read_from_headers(auth_response: &AuthResponse) -> AuthDataParseResult { +fn read_from_headers(auth_response: &impl ResponseReader) -> AuthDataParseResult { let Some(status) = auth_response.get_header("saml-auth-status") else { info!("No SAML auth status found in headers"); return Err(AuthDataParseError::NotFound); @@ -65,11 +75,11 @@ fn read_from_headers(auth_response: &AuthResponse) -> AuthDataParseResult { }) } -fn read_from_body(auth_response: &AuthResponse, cb: F) +fn read_from_body(auth_response: &impl ResponseReader, cb: F) where F: FnOnce(AuthDataParseResult) + 'static, { - auth_response.get_body(|body| match body { + auth_response.get_body(Box::new(|body| match body { Ok(body) => { if let Some(html) = body { cb(read_from_html(&html)) @@ -79,7 +89,7 @@ where info!("Failed to read body: {}", err); cb(Err(AuthDataParseError::Invalid)) } - }); + })); } fn read_from_html(html: &str) -> AuthDataParseResult { diff --git a/crates/auth/src/webview/webview_auth.rs b/crates/auth/src/webview/webview_auth.rs index a5e5fc2..bd1bca7 100644 --- a/crates/auth/src/webview/webview_auth.rs +++ b/crates/auth/src/webview/webview_auth.rs @@ -7,7 +7,7 @@ use tao::{ }; use wry::WebViewBuilder; -use crate::{auth_prelogin, webview::auth_response::read_auth_data}; +use crate::{auth_prelogin, webview::response_reader::read_auth_data}; use super::platform_impl::connect_webview_response; @@ -98,7 +98,7 @@ impl<'a> WebviewAuthenticatorBuilder<'a> { connect_webview_response(&webview, |response| { // println!("Received response: {:?}", response.unwrap().url()); match response { - Ok(response) => read_auth_data(response, |auth_result| { + Ok(response) => read_auth_data(&response, |auth_result| { println!("Auth result: {:?}", auth_result); }), Err(err) => todo!(),