diff --git a/README.md b/README.md index 6cda4d0..584a169 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,12 @@ pub fn run() { ### TypeScript ```typescript -import { start, cancel, onUrl, onInvalidUrl } from '@fabianlars/tauri-plugin-oauth'; +import { + start, + cancel, + onUrl, + onInvalidUrl, +} from "@fabianlars/tauri-plugin-oauth"; async function startOAuthFlow() { try { @@ -75,15 +80,14 @@ async function startOAuthFlow() { // Set up listeners for OAuth results await onUrl((url) => { - console.log('Received OAuth URL:', url); + console.log("Received OAuth URL:", url); // Handle the OAuth redirect }); // Initiate your OAuth flow here // ... - } catch (error) { - console.error('Error starting OAuth server:', error); + console.error("Error starting OAuth server:", error); } } @@ -91,9 +95,9 @@ async function startOAuthFlow() { async function stopOAuthServer() { try { await cancel(port); - console.log('OAuth server stopped'); + console.log("OAuth server stopped"); } catch (error) { - console.error('Error stopping OAuth server:', error); + console.error("Error stopping OAuth server:", error); } } ``` @@ -102,12 +106,15 @@ async function stopOAuthServer() { You can configure the plugin behavior using the `OauthConfig` struct: +If you set the `redirect_uri` field, the plugin will redirect to the provided URL after the OAuth process is complete instead of returning the `response` content. + ```rust use tauri_plugin_oauth::OauthConfig; let config = OauthConfig { ports: Some(vec![8000, 8001, 8002]), response: Some("OAuth process completed. You can close this window.".into()), + redirect_uri: Some("http://tauri.localhost/homepage".into()), }; start_with_config(config, |url| { @@ -125,7 +132,7 @@ start_with_config(config, |url| { ## Contributing -Contributions are always welcome! Please feel free to submit a Pull Request. +Contributions are always welcome! Please feel free to submit a Pull Request. ## License diff --git a/src/lib.rs b/src/lib.rs index cac1300..88a813b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,45 @@ pub struct OauthConfig { /// /// Default: `"Please return to the app."`. pub response: Option>, + + /// The redirect uri to use for the oauth provider. + /// If this argument is provided, the server will redirect to the provided uri instead of return a htpp 200 response. + /// + /// Default: None + pub redirect_uri: Option>, +} + +fn handle_connection_with_redirect( + mut conn: TcpStream, + redirect_uri: &str, + port: u16, +) -> Option { + let mut buffer = [0; 4048]; + if let Err(io_err) = conn.read(&mut buffer) { + log::error!("Error reading incoming connection: {}", io_err.to_string()); + }; + if buffer[..4] == EXIT { + return Some(String::new()); + } + + let mut headers = [httparse::EMPTY_HEADER; 32]; + let mut request = httparse::Request::new(&mut headers); + request.parse(&buffer).ok()?; + + let path = request.path.unwrap_or_default(); + + // TODO: Test if unwrapping here is safe (enough). + conn.write_all( + format!( + "HTTP/1.1 302 Found\r\nLocation: {}\r\nContent-Length: 0\r\n\r\n", + redirect_uri + ) + .as_bytes(), + ) + .unwrap(); + conn.flush().unwrap(); + let url = format!("http://{}:{}{}", "127.0.0.1", port, path); + return Some(url); } /// Starts the localhost (using 127.0.0.1) server. Returns the port its listening on. @@ -83,7 +122,20 @@ pub fn start_with_config( for conn in listener.incoming() { match conn { Ok(conn) => { - if let Some(url) = handle_connection(conn, config.response.as_deref(), port) { + if let Some(redirect_uri) = &config.redirect_uri { + if let Some(url) = + handle_connection_with_redirect(conn, redirect_uri.as_ref(), port) + { + // Using an empty string to communicate that a shutdown was requested. + if !url.is_empty() { + handler(url); + } + // TODO: Check if exiting here is always okay. + break; + } + } else if let Some(url) = + handle_connection(conn, config.response.as_deref(), port) + { // Using an empty string to communicate that a shutdown was requested. if !url.is_empty() { handler(url);