From 8a2b2cedc3165a5f5b442fa2b555931857d58d3b Mon Sep 17 00:00:00 2001 From: Brentspine Date: Mon, 15 Dec 2025 01:43:08 +0100 Subject: [PATCH] fix(auth): Hopefully fix some issues regarding login by replacing dodgy webview check --- .../src/commands/minecraft_auth_command.rs | 88 ++++++++++++------- 1 file changed, 55 insertions(+), 33 deletions(-) diff --git a/src-tauri/src/commands/minecraft_auth_command.rs b/src-tauri/src/commands/minecraft_auth_command.rs index 252a485b..bc4f43cc 100644 --- a/src-tauri/src/commands/minecraft_auth_command.rs +++ b/src-tauri/src/commands/minecraft_auth_command.rs @@ -3,9 +3,13 @@ use crate::minecraft::minecraft_auth::Credentials; use crate::state::state_manager::State; use chrono::{Duration, Utc}; use tauri::plugin::TauriPlugin; -use tauri::Manager; +use tauri::{Manager, WindowEvent}; use tauri::{Runtime, UserAttentionType}; use uuid::Uuid; +use tokio::sync::oneshot; +use std::sync::Arc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::Mutex; //TODO das wäre geiler aber habs noch nicht hinbekommen //Error during login: minecraft_auth.begin_login not allowed. Plugin not found @@ -21,8 +25,19 @@ pub fn init() -> TauriPlugin { .build() } +fn extract_code(u: &url::Url) -> Option { + let is_callback = u.as_str().starts_with("https://login.live.com/oauth20_desktop.srf"); + if !is_callback { + return None; + } + + u.query_pairs() + .find(|(k, _)| k == "code") + .map(|(_, v)| v.into_owned()) +} + /// Begin the Minecraft login flow -/// Returns a URL that the user needs to visit to sign in +/// Returns Some(Credentials) if login was successful, None if cancelled or timed out #[tauri::command] pub async fn begin_login( app: tauri::AppHandle, @@ -38,6 +53,12 @@ pub async fn begin_login( window.close().map_err(|e| AppError::Other(e.to_string()))?; } + // We can try creating a fancy oneshot cancellation system, but I was too stupid to get it working. 50ms polling is fine ig + // https://gist.github.com/brentspine/c6335b53b529edba94755d8e9947e43c + // Oneshot->Send Once; Mutex->Safe sharing; Arc->Multiple ownership + // let (cancel_tx, cancel_rx) = oneshot::channel::<()>(); + // let cancel_tx = Arc::new(Mutex::new(Some(cancel_tx))); + // Create a new window for the sign-in process let window = tauri::WebviewWindowBuilder::new( @@ -47,11 +68,24 @@ pub async fn begin_login( AppError::AccountError("Error parsing auth redirect URL".to_string()) })?), ) - .title("Sign into Minecraft") - .always_on_top(true) - .center() - .build() - .map_err(|e| AppError::Other(e.to_string()))?; + .title("Sign into Minecraft") + .always_on_top(true) + .center() + .build() + .map_err(|e| AppError::Other(e.to_string()))?; + + let cancelled = Arc::new(AtomicBool::new(false)); + let cancelled2 = Arc::clone(&cancelled); + + window.on_window_event(move |e| { + let is_close = + matches!(e, WindowEvent::CloseRequested { .. }) || + matches!(e, WindowEvent::Destroyed); + + if is_close { + cancelled2.store(true, Ordering::Relaxed); + } + }); window .request_user_attention(Some(UserAttentionType::Critical)) @@ -59,41 +93,29 @@ pub async fn begin_login( let start = Utc::now(); - // Wait for the user to complete the login (10 minutes = 600 seconds) while (Utc::now() - start) < Duration::seconds(600) { - if window.title().is_err() { - // User closed the window, cancelling flow - window.close().map_err(|e| AppError::Other(e.to_string()))?; + if cancelled.load(Ordering::Relaxed) { return Ok(None); } - if let Ok(url) = window.url() { - if url - .as_str() - .starts_with("https://login.live.com/oauth20_desktop.srf") - { - if let Some((_, code)) = url.query_pairs().find(|x| x.0 == "code") { - window.close().map_err(|e| AppError::Other(e.to_string()))?; - - // Complete the login flow with the code - let account = State::get() - .await? - .minecraft_account_manager_v2 - .login_finish(&code, flow) - .await?; - - // Add the account to the manager - //state.minecraft_account_manager.add_account(account.clone()).await?; - - return Ok(Some(account)); - } - } + let url = window.url().ok(); + let code = url.as_ref().and_then(extract_code); + + if let Some(code) = code { + let _ = window.close(); + let account = State::get() + .await? + .minecraft_account_manager_v2 + .login_finish(&code, flow) + .await?; + + return Ok(Some(account)); } tokio::time::sleep(std::time::Duration::from_millis(50)).await; } - window.close().map_err(|e| AppError::Other(e.to_string()))?; + let _ = window.close(); Ok(None) }