From a52e28191e7bc6baf78106c411c87134a7ba3db8 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Thu, 5 Feb 2026 12:17:09 -0800 Subject: [PATCH] Improve auth error feedback with specific failure reasons, version mismatch details, and connection timeout --- include/ui/auth_screen.hpp | 3 +++ src/auth/auth_handler.cpp | 8 ++++---- src/auth/auth_opcodes.cpp | 42 +++++++++++++++++++++----------------- src/ui/auth_screen.cpp | 29 +++++++++++++++++++++++--- 4 files changed, 56 insertions(+), 26 deletions(-) diff --git a/include/ui/auth_screen.hpp b/include/ui/auth_screen.hpp index 8181244b..e8630b3f 100644 --- a/include/ui/auth_screen.hpp +++ b/include/ui/auth_screen.hpp @@ -53,6 +53,9 @@ private: // Status std::string statusMessage; bool statusIsError = false; + std::string failureReason; // Specific reason from auth handler + float authTimer = 0.0f; // Timeout tracker + static constexpr float AUTH_TIMEOUT = 10.0f; // Callbacks std::function onSuccess; diff --git a/src/auth/auth_handler.cpp b/src/auth/auth_handler.cpp index ee55705d..acdb5146 100644 --- a/src/auth/auth_handler.cpp +++ b/src/auth/auth_handler.cpp @@ -105,7 +105,7 @@ void AuthHandler::handleLogonChallengeResponse(network::Packet& packet) { LogonChallengeResponse response; if (!LogonChallengeResponseParser::parse(packet, response)) { - fail("Failed to parse LOGON_CHALLENGE response"); + fail("Server sent an invalid response - it may use an incompatible protocol version"); return; } @@ -140,18 +140,18 @@ void AuthHandler::handleLogonProofResponse(network::Packet& packet) { LogonProofResponse response; if (!LogonProofResponseParser::parse(packet, response)) { - fail("Failed to parse LOGON_PROOF response"); + fail("Server sent an invalid login response - it may use an incompatible protocol"); return; } if (!response.isSuccess()) { - fail("LOGON_PROOF failed: invalid proof"); + fail("Login failed - incorrect username or password"); return; } // Verify server proof if (!srp->verifyServerProof(response.M2)) { - fail("Server proof verification failed"); + fail("Server identity verification failed - the server may be running an incompatible version"); return; } diff --git a/src/auth/auth_opcodes.cpp b/src/auth/auth_opcodes.cpp index 303de55f..85946a28 100644 --- a/src/auth/auth_opcodes.cpp +++ b/src/auth/auth_opcodes.cpp @@ -6,25 +6,29 @@ namespace auth { const char* getAuthResultString(AuthResult result) { switch (result) { case AuthResult::SUCCESS: return "Success"; - case AuthResult::UNKNOWN0: return "Unknown Error 0"; - case AuthResult::UNKNOWN1: return "Unknown Error 1"; - case AuthResult::ACCOUNT_BANNED: return "Account Banned"; - case AuthResult::ACCOUNT_INVALID: return "Account Invalid"; - case AuthResult::PASSWORD_INVALID: return "Password Invalid"; - case AuthResult::ALREADY_ONLINE: return "Already Online"; - case AuthResult::OUT_OF_CREDIT: return "Out of Credit"; - case AuthResult::BUSY: return "Server Busy"; - case AuthResult::BUILD_INVALID: return "Build Invalid"; - case AuthResult::BUILD_UPDATE: return "Build Update Required"; - case AuthResult::INVALID_SERVER: return "Invalid Server"; - case AuthResult::ACCOUNT_SUSPENDED: return "Account Suspended"; - case AuthResult::ACCESS_DENIED: return "Access Denied"; - case AuthResult::SURVEY: return "Survey Required"; - case AuthResult::PARENTAL_CONTROL: return "Parental Control"; - case AuthResult::LOCK_ENFORCED: return "Lock Enforced"; - case AuthResult::TRIAL_EXPIRED: return "Trial Expired"; - case AuthResult::BATTLE_NET: return "Battle.net Error"; - default: return "Unknown"; + case AuthResult::UNKNOWN0: return "Unknown error (0x01)"; + case AuthResult::UNKNOWN1: return "Unknown error (0x02)"; + case AuthResult::ACCOUNT_BANNED: return "This account has been banned"; + case AuthResult::ACCOUNT_INVALID: return "Account not found - check your username"; + case AuthResult::PASSWORD_INVALID: return "Incorrect password"; + case AuthResult::ALREADY_ONLINE: return "This account is already logged in"; + case AuthResult::OUT_OF_CREDIT: return "Account out of credit/time"; + case AuthResult::BUSY: return "Server is busy - try again later"; + case AuthResult::BUILD_INVALID: + return "Version mismatch - this client is WotLK 3.3.5a (build 12340). " + "The server requires a different client version"; + case AuthResult::BUILD_UPDATE: + return "Client update required - the server expects a different build version. " + "This client only supports WotLK 3.3.5a (build 12340)"; + case AuthResult::INVALID_SERVER: return "Invalid server"; + case AuthResult::ACCOUNT_SUSPENDED: return "This account has been suspended"; + case AuthResult::ACCESS_DENIED: return "Access denied"; + case AuthResult::SURVEY: return "Survey required"; + case AuthResult::PARENTAL_CONTROL: return "Blocked by parental controls"; + case AuthResult::LOCK_ENFORCED: return "Account locked - check your email"; + case AuthResult::TRIAL_EXPIRED: return "Trial period has expired"; + case AuthResult::BATTLE_NET: return "Battle.net error"; + default: return "Unknown error"; } } diff --git a/src/ui/auth_screen.cpp b/src/ui/auth_screen.cpp index dd6ff70c..774ba888 100644 --- a/src/ui/auth_screen.cpp +++ b/src/ui/auth_screen.cpp @@ -56,7 +56,12 @@ void AuthScreen::render(auth::AuthHandler& authHandler) { // Connect button if (authenticating) { - ImGui::Text("Authenticating..."); + authTimer += ImGui::GetIO().DeltaTime; + + // Show progress with elapsed time + char progressBuf[128]; + snprintf(progressBuf, sizeof(progressBuf), "Authenticating... (%.0fs)", authTimer); + ImGui::Text("%s", progressBuf); // Check authentication status auto state = authHandler.getState(); @@ -69,8 +74,16 @@ void AuthScreen::render(auth::AuthHandler& authHandler) { onSuccess(); } } else if (state == auth::AuthState::FAILED) { - setStatus("Authentication failed", true); + if (!failureReason.empty()) { + setStatus(failureReason, true); + } else { + setStatus("Authentication failed", true); + } authenticating = false; + } else if (authTimer >= AUTH_TIMEOUT) { + setStatus("Connection timed out - server did not respond", true); + authenticating = false; + authHandler.disconnect(); } } else { if (ImGui::Button("Connect", ImVec2(120, 0))) { @@ -131,14 +144,24 @@ void AuthScreen::attemptAuth(auth::AuthHandler& authHandler) { ss << "Connecting to " << hostname << ":" << port << "..."; setStatus(ss.str(), false); + // Wire up failure callback to capture specific error reason + failureReason.clear(); + authHandler.setOnFailure([this](const std::string& reason) { + failureReason = reason; + }); + if (authHandler.connect(hostname, static_cast(port))) { authenticating = true; + authTimer = 0.0f; setStatus("Connected, authenticating...", false); // Send authentication credentials authHandler.authenticate(username, password); } else { - setStatus("Failed to connect to server", true); + std::stringstream errSs; + errSs << "Failed to connect to " << hostname << ":" << port + << " - check that the server is online and the address is correct"; + setStatus(errSs.str(), true); } }