mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-10-14 21:22:49 +00:00
[skip ci] Add Yggdrasil Login (authlib-injector support)
Add Yggdrasil Login (authlib-injector support)
This commit is contained in:
commit
c6da4e2ac3
10 changed files with 2287 additions and 2027 deletions
|
|
@ -416,7 +416,7 @@ namespace MinecraftClient
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Validate cached session or login new session.
|
// Validate cached session or login new session.
|
||||||
if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower))
|
if (Config.Main.Advanced.SessionCache != CacheType.none && SessionCache.Contains(loginLower) && Config.Main.General.AccountType != LoginType.yggdrasil)
|
||||||
{
|
{
|
||||||
session = SessionCache.Get(loginLower);
|
session = SessionCache.Get(loginLower);
|
||||||
result = ProtocolHandler.GetTokenValidation(session);
|
result = ProtocolHandler.GetTokenValidation(session);
|
||||||
|
|
@ -447,7 +447,7 @@ namespace MinecraftClient
|
||||||
|
|
||||||
if (result != ProtocolHandler.LoginResult.Success)
|
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);
|
result = ProtocolHandler.GetLogin(InternalConfig.Account.Login, InternalConfig.Account.Password, Config.Main.General.AccountType, out session);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -455,7 +455,7 @@ namespace MinecraftClient
|
||||||
SessionCache.Store(loginLower, session);
|
SessionCache.Store(loginLower, session);
|
||||||
|
|
||||||
if (result == ProtocolHandler.LoginResult.Success)
|
if (result == ProtocolHandler.LoginResult.Success)
|
||||||
session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck());
|
session.SessionPreCheckTask = Task.Factory.StartNew(() => session.SessionPreCheck(Config.Main.General.AccountType));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result == ProtocolHandler.LoginResult.Success)
|
if (result == ProtocolHandler.LoginResult.Success)
|
||||||
|
|
@ -649,6 +649,7 @@ namespace MinecraftClient
|
||||||
ProtocolHandler.LoginResult.OtherError => Translations.error_login_network,
|
ProtocolHandler.LoginResult.OtherError => Translations.error_login_network,
|
||||||
ProtocolHandler.LoginResult.SSLError => Translations.error_login_ssl,
|
ProtocolHandler.LoginResult.SSLError => Translations.error_login_ssl,
|
||||||
ProtocolHandler.LoginResult.UserCancel => Translations.error_login_cancel,
|
ProtocolHandler.LoginResult.UserCancel => Translations.error_login_cancel,
|
||||||
|
ProtocolHandler.LoginResult.WrongSelection => Translations.error_login_blocked,
|
||||||
_ => Translations.error_login_unknown,
|
_ => Translations.error_login_unknown,
|
||||||
#pragma warning restore format // @formatter:on
|
#pragma warning restore format // @formatter:on
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ using MinecraftClient.Protocol.Session;
|
||||||
using MinecraftClient.Proxy;
|
using MinecraftClient.Proxy;
|
||||||
using MinecraftClient.Scripting;
|
using MinecraftClient.Scripting;
|
||||||
using static MinecraftClient.Settings;
|
using static MinecraftClient.Settings;
|
||||||
|
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Handlers
|
namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
|
|
@ -504,7 +505,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
else if (Settings.Config.Logging.DebugMessages)
|
else if (Settings.Config.Logging.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_handshake, serverID));
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_handshake, serverID));
|
||||||
|
|
||||||
return StartEncryption(uuid, username, sessionID, token, serverID, PublicServerkey, session);
|
return StartEncryption(uuid, username, sessionID, Config.Main.General.AccountType, token, serverID, PublicServerkey, session);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -513,7 +514,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool StartEncryption(string uuid, string username, string sessionID, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
|
private bool StartEncryption(string uuid, string username, string sessionID, LoginType type, byte[] token, string serverIDhash, byte[] serverPublicKey, SessionToken session)
|
||||||
{
|
{
|
||||||
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
|
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
|
||||||
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
|
byte[] secretKey = CryptoHandler.ClientAESPrivateKey ?? CryptoHandler.GenerateAESPrivateKey();
|
||||||
|
|
@ -537,7 +538,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
|
|
||||||
if (needCheckSession)
|
if (needCheckSession)
|
||||||
{
|
{
|
||||||
if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
|
if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash)) || (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash)))
|
||||||
{
|
{
|
||||||
session.ServerIDhash = serverIDhash;
|
session.ServerIDhash = serverIDhash;
|
||||||
session.ServerPublicKey = serverPublicKey;
|
session.ServerPublicKey = serverPublicKey;
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@ using MinecraftClient.Proxy;
|
||||||
using MinecraftClient.Scripting;
|
using MinecraftClient.Scripting;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using static MinecraftClient.Settings;
|
using static MinecraftClient.Settings;
|
||||||
|
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Handlers
|
namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
|
|
@ -2568,7 +2569,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
string serverID = dataTypes.ReadNextString(packetData);
|
string serverID = dataTypes.ReadNextString(packetData);
|
||||||
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
|
byte[] serverPublicKey = dataTypes.ReadNextByteArray(packetData);
|
||||||
byte[] token = dataTypes.ReadNextByteArray(packetData);
|
byte[] token = dataTypes.ReadNextByteArray(packetData);
|
||||||
return StartEncryption(handler.GetUserUuidStr(), handler.GetSessionID(), token, serverID,
|
return StartEncryption(handler.GetUserUuidStr(), handler.GetSessionID(), Config.Main.General.AccountType, token, serverID,
|
||||||
serverPublicKey, playerKeyPair, session);
|
serverPublicKey, playerKeyPair, session);
|
||||||
}
|
}
|
||||||
else if (packetID == 0x02) //Login successful
|
else if (packetID == 0x02) //Login successful
|
||||||
|
|
@ -2593,7 +2594,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// Start network encryption. Automatically called by Login() if the server requests encryption.
|
/// Start network encryption. Automatically called by Login() if the server requests encryption.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if encryption was successful</returns>
|
/// <returns>True if encryption was successful</returns>
|
||||||
private bool StartEncryption(string uuid, string sessionID, byte[] token, string serverIDhash,
|
private bool StartEncryption(string uuid, string sessionID, LoginType type, byte[] token, string serverIDhash,
|
||||||
byte[] serverPublicKey, PlayerKeyPair? playerKeyPair, SessionToken session)
|
byte[] serverPublicKey, PlayerKeyPair? playerKeyPair, SessionToken session)
|
||||||
{
|
{
|
||||||
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
|
RSACryptoServiceProvider RSAService = CryptoHandler.DecodeRSAPublicKey(serverPublicKey)!;
|
||||||
|
|
@ -2619,7 +2620,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
string serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey);
|
string serverHash = CryptoHandler.GetServerHash(serverIDhash, serverPublicKey, secretKey);
|
||||||
|
|
||||||
if (ProtocolHandler.SessionCheck(uuid, sessionID, serverHash))
|
if ((type == LoginType.mojang && ProtocolHandler.SessionCheck(uuid, sessionID, serverHash) )|| (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(uuid, sessionID, serverHash)))
|
||||||
{
|
{
|
||||||
session.ServerIDhash = serverIDhash;
|
session.ServerIDhash = serverIDhash;
|
||||||
session.ServerPublicKey = serverPublicKey;
|
session.ServerPublicKey = serverPublicKey;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Data.Odbc;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Security;
|
using System.Net.Security;
|
||||||
|
|
@ -11,6 +12,7 @@ using MinecraftClient.Protocol.Handlers;
|
||||||
using MinecraftClient.Protocol.Handlers.Forge;
|
using MinecraftClient.Protocol.Handlers.Forge;
|
||||||
using MinecraftClient.Protocol.Session;
|
using MinecraftClient.Protocol.Session;
|
||||||
using MinecraftClient.Proxy;
|
using MinecraftClient.Proxy;
|
||||||
|
using static MinecraftClient.Protocol.Microsoft;
|
||||||
using static MinecraftClient.Settings;
|
using static MinecraftClient.Settings;
|
||||||
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
|
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
|
||||||
|
|
||||||
|
|
@ -134,7 +136,7 @@ namespace MinecraftClient.Protocol
|
||||||
if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1)
|
if (Array.IndexOf(supportedVersions_Protocol16, ProtocolVersion) > -1)
|
||||||
return new Protocol16Handler(Client, ProtocolVersion, Handler);
|
return new Protocol16Handler(Client, ProtocolVersion, Handler);
|
||||||
|
|
||||||
int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763 };
|
int[] supportedVersions_Protocol18 = { 4, 5, 47, 107, 108, 109, 110, 210, 315, 316, 335, 338, 340, 393, 401, 404, 477, 480, 485, 490, 498, 573, 575, 578, 735, 736, 751, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763};
|
||||||
|
|
||||||
if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1)
|
if (Array.IndexOf(supportedVersions_Protocol18, ProtocolVersion) > -1)
|
||||||
return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo);
|
return new Protocol18Handler(Client, ProtocolVersion, Handler, forgeInfo);
|
||||||
|
|
@ -423,7 +425,7 @@ namespace MinecraftClient.Protocol
|
||||||
return Protocol18Forge.ServerForceForge(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 };
|
public enum AccountType { Mojang, Microsoft };
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -446,7 +448,11 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
return MojangLogin(user, pass, out session);
|
return MojangLogin(user, pass, out session);
|
||||||
}
|
}
|
||||||
else throw new InvalidOperationException("Account type must be Mojang or Microsoft");
|
else if (type == LoginType.yggdrasil)
|
||||||
|
{
|
||||||
|
return YggdrasiLogin(user, pass, out session);
|
||||||
|
}
|
||||||
|
else throw new InvalidOperationException("Account type must be Mojang or Microsoft or valid authlib 3rd Servers!");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -464,7 +470,7 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
|
string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
|
||||||
int code = DoHTTPSPost("authserver.mojang.com", "/authenticate", json_request, ref result);
|
int code = DoHTTPSPost("authserver.mojang.com",443, "/authenticate", json_request, ref result);
|
||||||
if (code == 200)
|
if (code == 200)
|
||||||
{
|
{
|
||||||
if (result.Contains("availableProfiles\":[]}"))
|
if (result.Contains("availableProfiles\":[]}"))
|
||||||
|
|
@ -534,7 +540,116 @@ namespace MinecraftClient.Protocol
|
||||||
return LoginResult.OtherError;
|
return LoginResult.OtherError;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
private static LoginResult YggdrasiLogin(string user, string pass, out SessionToken session)
|
||||||
|
{
|
||||||
|
session = new SessionToken() { ClientID = Guid.NewGuid().ToString().Replace("-", "") };
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
string json_request = "{\"agent\": { \"name\": \"Minecraft\", \"version\": 1 }, \"username\": \"" + JsonEncode(user) + "\", \"password\": \"" + JsonEncode(pass) + "\", \"clientToken\": \"" + JsonEncode(session.ClientID) + "\" }";
|
||||||
|
int code = DoHTTPSPost(Config.Main.General.AuthServer.Host,Config.Main.General.AuthServer.Port, "/api/yggdrasil/authserver/authenticate", json_request, ref result);
|
||||||
|
if (code == 200)
|
||||||
|
{
|
||||||
|
if (result.Contains("availableProfiles\":[]}"))
|
||||||
|
{
|
||||||
|
return LoginResult.NotPremium;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Json.JSONData loginResponse = Json.ParseJson(result);
|
||||||
|
if (loginResponse.Properties.ContainsKey("accessToken"))
|
||||||
|
{
|
||||||
|
session.ID = loginResponse.Properties["accessToken"].StringValue;
|
||||||
|
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 availableProfiles = "";
|
||||||
|
foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray)
|
||||||
|
{
|
||||||
|
availableProfiles += " " + profile.Properties["name"].StringValue;
|
||||||
|
}
|
||||||
|
ConsoleIO.WriteLine(Translations.mcc_avaliable_profiles + availableProfiles);
|
||||||
|
|
||||||
|
ConsoleIO.WriteLine(Translations.mcc_select_profile);
|
||||||
|
string selectedProfileName = ConsoleIO.ReadLine();
|
||||||
|
ConsoleIO.WriteLine(Translations.mcc_selected_profile + " " + selectedProfileName);
|
||||||
|
Json.JSONData? selectedProfile = null;
|
||||||
|
foreach (Json.JSONData profile in loginResponse.Properties["availableProfiles"].DataArray)
|
||||||
|
{
|
||||||
|
selectedProfile = profile.Properties["name"].StringValue == selectedProfileName ? 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (code == 403)
|
||||||
|
{
|
||||||
|
if (result.Contains("UserMigratedException"))
|
||||||
|
{
|
||||||
|
return LoginResult.AccountMigrated;
|
||||||
|
}
|
||||||
|
else return LoginResult.WrongPassword;
|
||||||
|
}
|
||||||
|
else if (code == 503)
|
||||||
|
{
|
||||||
|
return LoginResult.ServiceUnavailable;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.error_http_code, code));
|
||||||
|
return LoginResult.OtherError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (System.Security.Authentication.AuthenticationException e)
|
||||||
|
{
|
||||||
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
|
||||||
|
}
|
||||||
|
return LoginResult.SSLError;
|
||||||
|
}
|
||||||
|
catch (System.IO.IOException e)
|
||||||
|
{
|
||||||
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
|
||||||
|
}
|
||||||
|
if (e.Message.Contains("authentication"))
|
||||||
|
{
|
||||||
|
return LoginResult.SSLError;
|
||||||
|
}
|
||||||
|
else return LoginResult.OtherError;
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + e.ToString());
|
||||||
|
}
|
||||||
|
return LoginResult.OtherError;
|
||||||
|
}
|
||||||
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sign-in to Microsoft Account without using browser. Only works if 2FA is disabled.
|
/// Sign-in to Microsoft Account without using browser. Only works if 2FA is disabled.
|
||||||
/// Might not work well in some rare cases.
|
/// Might not work well in some rare cases.
|
||||||
|
|
@ -675,7 +790,53 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }";
|
string json_request = "{ \"accessToken\": \"" + JsonEncode(currentsession.ID) + "\", \"clientToken\": \"" + JsonEncode(currentsession.ClientID) + "\", \"selectedProfile\": { \"id\": \"" + JsonEncode(currentsession.PlayerID) + "\", \"name\": \"" + JsonEncode(currentsession.PlayerName) + "\" } }";
|
||||||
int code = DoHTTPSPost("authserver.mojang.com", "/refresh", json_request, ref result);
|
int code = DoHTTPSPost("authserver.mojang.com",443, "/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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (code == 200)
|
||||||
{
|
{
|
||||||
if (result == null)
|
if (result == null)
|
||||||
|
|
@ -727,7 +888,19 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid + "\",\"serverId\":\"" + serverhash + "\"}";
|
string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid + "\",\"serverId\":\"" + serverhash + "\"}";
|
||||||
int code = DoHTTPSPost("sessionserver.mojang.com", "/session/minecraft/join", json_request, ref result);
|
int code = DoHTTPSPost("sessionserver.mojang.com",443, "/session/minecraft/join", json_request, ref result);
|
||||||
|
return (code >= 200 && code < 300);
|
||||||
|
}
|
||||||
|
catch { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool YggdrasilSessionCheck(string uuid, string accesstoken, string serverhash)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string result = "";
|
||||||
|
string json_request = "{\"accessToken\":\"" + accesstoken + "\",\"selectedProfile\":\"" + uuid + "\",\"serverId\":\"" + serverhash + "\"}";
|
||||||
|
int code = DoHTTPSPost(Config.Main.General.AuthServer.Host, Config.Main.General.AuthServer.Port, "/api/yggdrasil/sessionserver/session/minecraft/join", json_request, ref result);
|
||||||
return (code >= 200 && code < 300);
|
return (code >= 200 && code < 300);
|
||||||
}
|
}
|
||||||
catch { return false; }
|
catch { return false; }
|
||||||
|
|
@ -747,7 +920,7 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
|
string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
|
||||||
DoHTTPSGet("pc.realms.minecraft.net", "/worlds", cookies, ref result);
|
DoHTTPSGet("pc.realms.minecraft.net", 443,"/worlds", cookies, ref result);
|
||||||
Json.JSONData realmsWorlds = Json.ParseJson(result);
|
Json.JSONData realmsWorlds = Json.ParseJson(result);
|
||||||
if (realmsWorlds.Properties.ContainsKey("servers")
|
if (realmsWorlds.Properties.ContainsKey("servers")
|
||||||
&& realmsWorlds.Properties["servers"].Type == Json.JSONData.DataType.Array
|
&& realmsWorlds.Properties["servers"].Type == Json.JSONData.DataType.Array
|
||||||
|
|
@ -808,7 +981,7 @@ namespace MinecraftClient.Protocol
|
||||||
{
|
{
|
||||||
string result = "";
|
string result = "";
|
||||||
string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
|
string cookies = String.Format("sid=token:{0}:{1};user={2};version={3}", accesstoken, uuid, username, Program.MCHighestVersion);
|
||||||
int statusCode = DoHTTPSGet("pc.realms.minecraft.net", "/worlds/v1/" + worldId + "/join/pc", cookies, ref result);
|
int statusCode = DoHTTPSGet("pc.realms.minecraft.net",443, "/worlds/v1/" + worldId + "/join/pc", cookies, ref result);
|
||||||
if (statusCode == 200)
|
if (statusCode == 200)
|
||||||
{
|
{
|
||||||
Json.JSONData serverAddress = Json.ParseJson(result);
|
Json.JSONData serverAddress = Json.ParseJson(result);
|
||||||
|
|
@ -845,7 +1018,7 @@ namespace MinecraftClient.Protocol
|
||||||
/// <param name="cookies">Cookies for making the request</param>
|
/// <param name="cookies">Cookies for making the request</param>
|
||||||
/// <param name="result">Request result</param>
|
/// <param name="result">Request result</param>
|
||||||
/// <returns>HTTP Status code</returns>
|
/// <returns>HTTP Status code</returns>
|
||||||
private static int DoHTTPSGet(string host, string endpoint, string cookies, ref string result)
|
private static int DoHTTPSGet(string host,int port, string endpoint, string cookies, ref string result)
|
||||||
{
|
{
|
||||||
List<String> http_request = new()
|
List<String> http_request = new()
|
||||||
{
|
{
|
||||||
|
|
@ -860,7 +1033,7 @@ namespace MinecraftClient.Protocol
|
||||||
"",
|
"",
|
||||||
""
|
""
|
||||||
};
|
};
|
||||||
return DoHTTPSRequest(http_request, host, ref result);
|
return DoHTTPSRequest(http_request, host,port, ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -871,7 +1044,7 @@ namespace MinecraftClient.Protocol
|
||||||
/// <param name="request">Request payload</param>
|
/// <param name="request">Request payload</param>
|
||||||
/// <param name="result">Request result</param>
|
/// <param name="result">Request result</param>
|
||||||
/// <returns>HTTP Status code</returns>
|
/// <returns>HTTP Status code</returns>
|
||||||
private static int DoHTTPSPost(string host, string endpoint, string request, ref string result)
|
private static int DoHTTPSPost(string host, int port, string endpoint, string request, ref string result)
|
||||||
{
|
{
|
||||||
List<String> http_request = new()
|
List<String> http_request = new()
|
||||||
{
|
{
|
||||||
|
|
@ -884,7 +1057,7 @@ namespace MinecraftClient.Protocol
|
||||||
"",
|
"",
|
||||||
request
|
request
|
||||||
};
|
};
|
||||||
return DoHTTPSRequest(http_request, host, ref result);
|
return DoHTTPSRequest(http_request, host,port, ref result);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -895,7 +1068,7 @@ namespace MinecraftClient.Protocol
|
||||||
/// <param name="host">Host to connect to</param>
|
/// <param name="host">Host to connect to</param>
|
||||||
/// <param name="result">Request result</param>
|
/// <param name="result">Request result</param>
|
||||||
/// <returns>HTTP Status code</returns>
|
/// <returns>HTTP Status code</returns>
|
||||||
private static int DoHTTPSRequest(List<string> headers, string host, ref string result)
|
private static int DoHTTPSRequest(List<string> headers, string host,int port, ref string result)
|
||||||
{
|
{
|
||||||
string? postResult = null;
|
string? postResult = null;
|
||||||
int statusCode = 520;
|
int statusCode = 520;
|
||||||
|
|
@ -907,7 +1080,7 @@ namespace MinecraftClient.Protocol
|
||||||
if (Settings.Config.Logging.DebugMessages)
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.debug_request, host));
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.debug_request, host));
|
||||||
|
|
||||||
TcpClient client = ProxyHandler.NewTcpClient(host, 443, true);
|
TcpClient client = ProxyHandler.NewTcpClient(host, port, true);
|
||||||
SslStream stream = new(client.GetStream());
|
SslStream stream = new(client.GetStream());
|
||||||
stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, true); // Enable TLS 1.2. Hotfix for #1780
|
stream.AuthenticateAsClient(host, null, SslProtocols.Tls12, true); // Enable TLS 1.2. Hotfix for #1780
|
||||||
|
|
||||||
|
|
@ -928,8 +1101,15 @@ namespace MinecraftClient.Protocol
|
||||||
|
|
||||||
if (raw_result.StartsWith("HTTP/1.1"))
|
if (raw_result.StartsWith("HTTP/1.1"))
|
||||||
{
|
{
|
||||||
postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..];
|
|
||||||
statusCode = int.Parse(raw_result.Split(' ')[1], NumberStyles.Any, CultureInfo.CurrentCulture);
|
statusCode = int.Parse(raw_result.Split(' ')[1], NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||||
|
if (statusCode != 204)
|
||||||
|
{
|
||||||
|
postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..].Split("\r\n")[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
postResult = "No Content";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else statusCode = 520; //Web server is returning an unknown error
|
else statusCode = 520; //Web server is returning an unknown error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ using System.IO;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MinecraftClient.Scripting;
|
using MinecraftClient.Scripting;
|
||||||
|
using static MinecraftClient.Settings.MainConfigHealper.MainConfig.GeneralConfig;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.Session
|
namespace MinecraftClient.Protocol.Session
|
||||||
{
|
{
|
||||||
|
|
@ -32,13 +33,15 @@ namespace MinecraftClient.Protocol.Session
|
||||||
ServerPublicKey = null;
|
ServerPublicKey = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool SessionPreCheck()
|
public bool SessionPreCheck(LoginType type)
|
||||||
{
|
{
|
||||||
if (ID == string.Empty || PlayerID == String.Empty || ServerPublicKey == null)
|
if (ID == string.Empty || PlayerID == String.Empty || ServerPublicKey == null)
|
||||||
return false;
|
return false;
|
||||||
Crypto.CryptoHandler.ClientAESPrivateKey ??= Crypto.CryptoHandler.GenerateAESPrivateKey();
|
Crypto.CryptoHandler.ClientAESPrivateKey ??= Crypto.CryptoHandler.GenerateAESPrivateKey();
|
||||||
string serverHash = Crypto.CryptoHandler.GetServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey);
|
string serverHash = Crypto.CryptoHandler.GetServerHash(ServerIDhash, ServerPublicKey, Crypto.CryptoHandler.ClientAESPrivateKey);
|
||||||
if (ProtocolHandler.SessionCheck(PlayerID, ID, serverHash))
|
if (type == LoginType.mojang && ProtocolHandler.SessionCheck(PlayerID, ID, serverHash))
|
||||||
|
return true;
|
||||||
|
if (type == LoginType.yggdrasil && ProtocolHandler.YggdrasilSessionCheck(PlayerID, ID, serverHash))
|
||||||
return true;
|
return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1130,7 +1130,7 @@ namespace MinecraftClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Allow IP aliases, such as "localhost" or if using containers then the container name can be used...
|
/// Looks up a localized string similar to Allow IP aliases, such as "localhost" or if using containers then the container name can be used....
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string ChatBot_WebSocketBot_AllowIpAlias {
|
internal static string ChatBot_WebSocketBot_AllowIpAlias {
|
||||||
get {
|
get {
|
||||||
|
|
@ -1732,6 +1732,15 @@ namespace MinecraftClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Yggdrasil authlib server domain name and port..
|
||||||
|
/// </summary>
|
||||||
|
internal static string Main_General_AuthlibServer {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Main.General.AuthlibServer", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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).
|
/// 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).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -1751,7 +1760,7 @@ namespace MinecraftClient {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 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..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
internal static string Main_General_server_info {
|
internal static string Main_General_server_info {
|
||||||
get {
|
get {
|
||||||
|
|
|
||||||
|
|
@ -724,7 +724,7 @@ Usage examples: "/tell <mybot> connect Server1", "/connect Server2"</value
|
||||||
<value>Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.</value>
|
<value>Microsoft Account sign-in method: "mcc" OR "browser". If the login always fails, please try to use the "browser" once.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="Main.General.server_info" xml:space="preserve">
|
<data name="Main.General.server_info" xml:space="preserve">
|
||||||
<value>Account type: "mojang" OR "microsoft". Also affects interactive login in console.</value>
|
<value>Account type: "mojang" OR "microsoft" OR "yggdrasil". Also affects interactive login in console.</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="MCSettings" xml:space="preserve">
|
<data name="MCSettings" xml:space="preserve">
|
||||||
<value>Settings below are sent to the server and only affect server-side things like your skin.</value>
|
<value>Settings below are sent to the server and only affect server-side things like your skin.</value>
|
||||||
|
|
@ -849,4 +849,7 @@ If the connection to the Minecraft game server is blocked by the firewall, set E
|
||||||
<data name="Main.Advanced.ignore_invalid_playername" xml:space="preserve">
|
<data name="Main.Advanced.ignore_invalid_playername" xml:space="preserve">
|
||||||
<value>Ignore invalid player name</value>
|
<value>Ignore invalid player name</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Main.General.AuthlibServer" xml:space="preserve">
|
||||||
|
<value>Yggdrasil authlib server domain name and port.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -5382,6 +5382,15 @@ namespace MinecraftClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Avaliable profiles:.
|
||||||
|
/// </summary>
|
||||||
|
internal static string mcc_avaliable_profiles {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("mcc.avaliable_profiles", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to The old MinecraftClient.ini has been backed up as {0}.
|
/// Looks up a localized string similar to The old MinecraftClient.ini has been backed up as {0}.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -5755,6 +5764,24 @@ namespace MinecraftClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select a profile from available profiles:.
|
||||||
|
/// </summary>
|
||||||
|
internal static string mcc_select_profile {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("mcc.select_profile", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Selected profile:.
|
||||||
|
/// </summary>
|
||||||
|
internal static string mcc_selected_profile {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("mcc.selected_profile", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Looks up a localized string similar to Server is in offline mode..
|
/// Looks up a localized string similar to Server is in offline mode..
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
||||||
|
|
@ -2121,4 +2121,13 @@ Logging in...</value>
|
||||||
<data name="cmd.inventory.shiftrightclick" xml:space="preserve">
|
<data name="cmd.inventory.shiftrightclick" xml:space="preserve">
|
||||||
<value>Shift right-clicking slot {0} in window #{1}</value>
|
<value>Shift right-clicking slot {0} in window #{1}</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="mcc.avaliable_profiles" xml:space="preserve">
|
||||||
|
<value>Avaliable profiles:</value>
|
||||||
|
</data>
|
||||||
|
<data name="mcc.selected_profile" xml:space="preserve">
|
||||||
|
<value>Selected profile:</value>
|
||||||
|
</data>
|
||||||
|
<data name="mcc.select_profile" xml:space="preserve">
|
||||||
|
<value>Select a profile from available profiles:</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
|
|
@ -494,8 +494,11 @@ namespace MinecraftClient
|
||||||
|
|
||||||
[TomlInlineComment("$Main.General.method$")]
|
[TomlInlineComment("$Main.General.method$")]
|
||||||
public LoginMethod Method = LoginMethod.mcc;
|
public LoginMethod Method = LoginMethod.mcc;
|
||||||
|
[TomlInlineComment("$Main.General.AuthlibServer$")]
|
||||||
|
public AuthlibServer AuthServer = new(string.Empty);
|
||||||
|
|
||||||
public enum LoginType { mojang, microsoft };
|
|
||||||
|
public enum LoginType { mojang, microsoft,yggdrasil };
|
||||||
|
|
||||||
public enum LoginMethod { mcc, browser };
|
public enum LoginMethod { mcc, browser };
|
||||||
}
|
}
|
||||||
|
|
@ -688,6 +691,29 @@ namespace MinecraftClient
|
||||||
this.Port = Port;
|
this.Port = Port;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public struct AuthlibServer
|
||||||
|
{
|
||||||
|
public string Host = string.Empty;
|
||||||
|
public int Port = 443;
|
||||||
|
|
||||||
|
public AuthlibServer(string Host)
|
||||||
|
{
|
||||||
|
string[] sip = Host.Split(new[] { ":", ":" }, StringSplitOptions.None);
|
||||||
|
this.Host = sip[0];
|
||||||
|
|
||||||
|
if (sip.Length > 1)
|
||||||
|
{
|
||||||
|
try { this.Port = Convert.ToUInt16(sip[1]); }
|
||||||
|
catch (FormatException) { }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthlibServer(string Host, ushort Port)
|
||||||
|
{
|
||||||
|
this.Host = Host.Split(new[] { ":", ":" }, StringSplitOptions.None)[0];
|
||||||
|
this.Port = Port;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue