diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index f36e3055..642a7ae7 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -416,7 +416,7 @@ namespace MinecraftClient else { // Validate cached session or login new session. - if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower) && Config.Main.General.AccountType != LoginType.Yggdrasil) + if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower) && Config.Main.General.AccountType != LoginType.yggdrasil) { session = SessionCache.Get(loginLower); result = ProtocolHandler.GetTokenValidation(session); @@ -447,7 +447,7 @@ namespace MinecraftClient if (result != ProtocolHandler.LoginResult.Success) { - ConsoleIO.WriteLine(string.Format(Translations.mcc_connecting, Config.Main.General.AccountType == LoginType.mojang ? "Minecraft.net" : "Microsoft")); + ConsoleIO.WriteLine(string.Format(Translations.mcc_connecting, Config.Main.General.AccountType == LoginType.mojang ? "Minecraft.net" : (Config.Main.General.AccountType == LoginType.microsoft ? "Microsoft" : Config.Main.General.AuthServer.Host))); result = ProtocolHandler.GetLogin(InternalConfig.Account.Login, InternalConfig.Account.Password, Config.Main.General.AccountType, out session); } @@ -649,6 +649,7 @@ namespace MinecraftClient ProtocolHandler.LoginResult.OtherError => Translations.error_login_network, ProtocolHandler.LoginResult.SSLError => Translations.error_login_ssl, ProtocolHandler.LoginResult.UserCancel => Translations.error_login_cancel, + ProtocolHandler.LoginResult.WrongSelection => Translations.error_login_blocked, _ => Translations.error_login_unknown, #pragma warning restore format // @formatter:on }; diff --git a/MinecraftClient/Protocol/Handlers/Protocol16.cs b/MinecraftClient/Protocol/Handlers/Protocol16.cs index aa4322fc..411fae2e 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol16.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol16.cs @@ -538,7 +538,7 @@ namespace MinecraftClient.Protocol.Handlers if (needCheckSession) { - if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash)) || (type == LoginType.Yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash))) + if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash)) || (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash))) { session.ServerIDhash = serverIDhash; session.ServerPublicKey = serverPublicKey; diff --git a/MinecraftClient/Protocol/Handlers/Protocol18.cs b/MinecraftClient/Protocol/Handlers/Protocol18.cs index 0262a0f7..e2182e19 100644 --- a/MinecraftClient/Protocol/Handlers/Protocol18.cs +++ b/MinecraftClient/Protocol/Handlers/Protocol18.cs @@ -2614,7 +2614,7 @@ namespace MinecraftClient.Protocol.Handlers { string serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey); - if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash) )|| (type == LoginType.Yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash))) + if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash) )|| (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash))) { session.ServerIDhash = serverIDhash; session.ServerPublicKey = serverPublicKey; diff --git a/MinecraftClient/Protocol/ProtocolHandler.cs b/MinecraftClient/Protocol/ProtocolHandler.cs index 159169f4..57e4492a 100644 --- a/MinecraftClient/Protocol/ProtocolHandler.cs +++ b/MinecraftClient/Protocol/ProtocolHandler.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Data.Odbc; using System.Globalization; using System.Linq; using System.Net.Security; @@ -11,6 +12,7 @@ using MinecraftClient.Protocol.Handlers; using MinecraftClient.Protocol.Handlers.Forge; using MinecraftClient.Protocol.Session; using MinecraftClient.Proxy; +using static MinecraftClient.Protocol.Microsoft; using static MinecraftClient.Settings; using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig; @@ -423,7 +425,7 @@ namespace MinecraftClient.Protocol return Protocol18Forge.ServerForceForge(protocol); } - public enum LoginResult { OtherError, ServiceUnavailable, SSLError, Success, WrongPassword, AccountMigrated, NotPremium, LoginRequired, InvalidToken, InvalidResponse, NullError, UserCancel }; + public enum LoginResult { OtherError, ServiceUnavailable, SSLError, Success, WrongPassword, AccountMigrated, NotPremium, LoginRequired, InvalidToken, InvalidResponse, NullError, UserCancel, WrongSelection }; public enum AccountType { Mojang, Microsoft }; /// @@ -446,7 +448,7 @@ namespace MinecraftClient.Protocol { return MojangLogin(user, pass, out session); } - else if (type == LoginType.Yggdrasil) + else if (type == LoginType.yggdrasil) { return YggdrasiLogin(user, pass, out session); } @@ -556,15 +558,47 @@ namespace MinecraftClient.Protocol else { Json.JSONData loginResponse = Json.ParseJson(result); - if (loginResponse.Properties.ContainsKey("accessToken") - && loginResponse.Properties.ContainsKey("selectedProfile") - && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("id") - && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("name")) + if (loginResponse.Properties.ContainsKey("accessToken")) { session.ID = loginResponse.Properties["accessToken"].StringValue; - session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue; - session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue; - return LoginResult.Success; + if (loginResponse.Properties.ContainsKey("selectedProfile") + && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("id") + && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("name")) + { + session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue; + session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue; + return LoginResult.Success; + } + else + { + string availablePlayers = ""; + foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray) + { + availablePlayers += " " + profile.Properties["name"].StringValue; + } + ConsoleIO.WriteLine(Translations.mcc_avaliable_players + availablePlayers); + + ConsoleIO.WriteLine(Translations.mcc_select_player); + string selectedPlayer = ConsoleIO.ReadLine(); + ConsoleIO.WriteLine(Translations.mcc_selected_player + selectedPlayer); + Json.JSONData selectedProfile = null; + foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray) + { + selectedProfile = profile.Properties["name"].StringValue == selectedPlayer ? profile : selectedProfile; + } + + if (selectedProfile != null) + { + session.PlayerID = selectedProfile.Properties["id"].StringValue; + session.PlayerName = selectedProfile.Properties["name"].StringValue; + SessionToken currentsession = session; + return GetNewYggdrasilToken(currentsession, out session); + } + else + { + return LoginResult.WrongSelection; + } + } } else return LoginResult.InvalidResponse; } @@ -795,6 +829,52 @@ namespace MinecraftClient.Protocol } } + public static LoginResult GetNewYggdrasilToken(SessionToken currentsession, out SessionToken session) + { + session = new SessionToken(); + try + { + string result = ""; + string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }"; + int code = DoHTTPSPost(Config.Main.General.AuthServer.Host, Config.Main.General.AuthServer.Port, "/api/yggdrasil/authserver/refresh", json_request, ref result); + if (code == 200) + { + if (result == null) + { + return LoginResult.NullError; + } + else + { + Json.JSONData loginResponse = Json.ParseJson(result); + if (loginResponse.Properties.ContainsKey("accessToken") + && loginResponse.Properties.ContainsKey("selectedProfile") + && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("id") + && loginResponse.Properties["selectedProfile"].Properties.ContainsKey("name")) + { + session.ID = loginResponse.Properties["accessToken"].StringValue; + session.PlayerID = loginResponse.Properties["selectedProfile"].Properties["id"].StringValue; + session.PlayerName = loginResponse.Properties["selectedProfile"].Properties["name"].StringValue; + return LoginResult.Success; + } + else return LoginResult.InvalidResponse; + } + } + else if (code == 403 && result.Contains("InvalidToken")) + { + return LoginResult.InvalidToken; + } + else + { + ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.error_auth, code)); + return LoginResult.OtherError; + } + } + catch + { + return LoginResult.OtherError; + } + } + /// /// Check session using Mojang's Yggdrasil authentication scheme. Allows to join an online-mode server /// diff --git a/MinecraftClient/Protocol/Session/SessionToken.cs b/MinecraftClient/Protocol/Session/SessionToken.cs index ffdeb14e..66bcb568 100644 --- a/MinecraftClient/Protocol/Session/SessionToken.cs +++ b/MinecraftClient/Protocol/Session/SessionToken.cs @@ -41,7 +41,7 @@ namespace MinecraftClient.Protocol.Session string serverHash = Crypto.CryptoHandler.GetServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey); if (type == LoginType.mojang && ProtocolHandler.SessionCheck(PlayerID, ID, serverHash)) return true; - if (type == LoginType.Yggdrasil && ProtocolHandler.YggdrasilSessionCheck(PlayerID, ID, serverHash)) + if (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(PlayerID, ID, serverHash)) return true; return false; } diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs index eec9c25d..cc82469c 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.Designer.cs @@ -1722,6 +1722,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Yggdrasil authlib server domain name and port.. + /// + internal static string Main_General_AuthlibServer { + get { + return ResourceManager.GetString("Main.General.AuthlibServer", resourceCulture); + } + } + /// /// Looks up a localized string similar to The address of the game server, "Host" can be filled in with domain name or IP address. (The "Port" field can be deleted, it will be resolved automatically). /// @@ -1741,7 +1750,7 @@ namespace MinecraftClient { } /// - /// Looks up a localized string similar to Account type: "mojang" OR "microsoft". Also affects interactive login in console.. + /// Looks up a localized string similar to Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console.. /// internal static string Main_General_server_info { get { diff --git a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx index 8ad6001f..ac175343 100644 --- a/MinecraftClient/Resources/ConfigComments/ConfigComments.resx +++ b/MinecraftClient/Resources/ConfigComments/ConfigComments.resx @@ -724,7 +724,7 @@ Usage examples: "/tell <mybot> connect Server1", "/connect Server2"Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once. - Account type: "mojang" OR "microsoft". Also affects interactive login in console. + Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console. Settings below are sent to the server and only affect server-side things like your skin. @@ -846,4 +846,7 @@ If the connection to the Minecraft game server is blocked by the firewall, set E Ignore invalid player name + + Yggdrasil authlib server domain name and port. + \ No newline at end of file diff --git a/MinecraftClient/Resources/Translations/Translations.Designer.cs b/MinecraftClient/Resources/Translations/Translations.Designer.cs index 08a5b472..693e44df 100644 --- a/MinecraftClient/Resources/Translations/Translations.Designer.cs +++ b/MinecraftClient/Resources/Translations/Translations.Designer.cs @@ -5373,6 +5373,15 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Avaliable players:. + /// + internal static string mcc_avaliable_players { + get { + return ResourceManager.GetString("mcc.avaliable_players", resourceCulture); + } + } + /// /// Looks up a localized string similar to The old MinecraftClient.ini has been backed up as {0}. /// @@ -5746,6 +5755,24 @@ namespace MinecraftClient { } } + /// + /// Looks up a localized string similar to Select a player from available players:. + /// + internal static string mcc_select_player { + get { + return ResourceManager.GetString("mcc.select_player", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Selected player:. + /// + internal static string mcc_selected_player { + get { + return ResourceManager.GetString("mcc.selected_player", resourceCulture); + } + } + /// /// Looks up a localized string similar to Server is in offline mode.. /// diff --git a/MinecraftClient/Resources/Translations/Translations.resx b/MinecraftClient/Resources/Translations/Translations.resx index 414b08cd..c2a82ea2 100644 --- a/MinecraftClient/Resources/Translations/Translations.resx +++ b/MinecraftClient/Resources/Translations/Translations.resx @@ -2121,4 +2121,13 @@ Logging in... Shift right-clicking slot {0} in window #{1} + + Avaliable players: + + + Selected player: + + + Select a player from available players: + \ No newline at end of file diff --git a/MinecraftClient/Settings.cs b/MinecraftClient/Settings.cs index 17e32afe..7982b057 100644 --- a/MinecraftClient/Settings.cs +++ b/MinecraftClient/Settings.cs @@ -498,7 +498,7 @@ namespace MinecraftClient public AuthlibServer AuthServer = new(string.Empty); - public enum LoginType { mojang, microsoft,Yggdrasil }; + public enum LoginType { mojang, microsoft,yggdrasil }; public enum LoginMethod { mcc, browser }; }