mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2026-08-15 13:04:36 +00:00
Fix offline Microsoft auth profile-key checks and complete status ping/pong during auto-version detection.
This commit is contained in:
parent
af405e5632
commit
d44fc22c8a
3 changed files with 126 additions and 73 deletions
|
|
@ -596,7 +596,8 @@ namespace MinecraftClient
|
|||
if ((Config.Main.General.AccountType == LoginType.microsoft || Config.Main.General.AccountType == LoginType.yggdrasil)
|
||||
&& (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser)
|
||||
&& Config.Signature.LoginWithSecureProfile
|
||||
&& protocolversion >= 759 /* 1.19 and above */)
|
||||
&& protocolversion >= 759 /* 1.19 and above */
|
||||
&& !string.IsNullOrWhiteSpace(session.ID))
|
||||
{
|
||||
// Load cached profile key from disk if necessary
|
||||
if (Config.Main.Advanced.ProfileKeyCache == CacheType.disk)
|
||||
|
|
|
|||
|
|
@ -3520,81 +3520,113 @@ namespace MinecraftClient.Protocol.Handlers
|
|||
/// <returns>True if ping was successful</returns>
|
||||
public static bool DoPing(string host, int port, ref int protocolVersion, ref ForgeInfo? forgeInfo)
|
||||
{
|
||||
var version = "";
|
||||
var tcp = ProxyHandler.NewTcpClient(host, port);
|
||||
tcp.ReceiveTimeout = 30000; // 30 seconds
|
||||
tcp.ReceiveBufferSize = 1024 * 1024;
|
||||
SocketWrapper socketWrapper = new(tcp);
|
||||
DataTypes dataTypes = new(MC_1_8_Version);
|
||||
SocketWrapper? socketWrapper = null;
|
||||
|
||||
var serverPort = BitConverter.GetBytes((ushort)port);
|
||||
Array.Reverse(serverPort);
|
||||
|
||||
// Ping Packet
|
||||
var pingPacket = dataTypes.ConcatBytes(
|
||||
// Packet Id
|
||||
DataTypes.GetVarInt(0),
|
||||
|
||||
// Protocol Version
|
||||
DataTypes.GetVarInt(-1),
|
||||
|
||||
// Server IP (Host)
|
||||
dataTypes.GetString(host),
|
||||
|
||||
// Server port
|
||||
serverPort,
|
||||
|
||||
// Next State
|
||||
DataTypes.GetVarInt(1));
|
||||
|
||||
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(pingPacket.Length), pingPacket));
|
||||
|
||||
// Status Request Packet
|
||||
var statusRequest = DataTypes.GetVarInt(0);
|
||||
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(statusRequest.Length), statusRequest));
|
||||
|
||||
// Read Response length
|
||||
var packetLength = dataTypes.ReadNextVarIntRAW(socketWrapper);
|
||||
if (packetLength <= 0) return false;
|
||||
|
||||
// Read the Packet Id
|
||||
var packetData = new Queue<byte>(socketWrapper.ReadDataRAW(packetLength));
|
||||
if (dataTypes.ReadNextVarInt(packetData) != 0x00) return false;
|
||||
|
||||
var result = dataTypes.ReadNextString(packetData); // Get the Json data
|
||||
|
||||
if (Config.Logging.DebugMessages)
|
||||
try
|
||||
{
|
||||
// May contain formatting codes, cannot use WriteLineFormatted
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine(result);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
var version = "";
|
||||
var tcp = ProxyHandler.NewTcpClient(host, port);
|
||||
tcp.ReceiveTimeout = 30000; // 30 seconds
|
||||
tcp.ReceiveBufferSize = 1024 * 1024;
|
||||
socketWrapper = new SocketWrapper(tcp);
|
||||
DataTypes dataTypes = new(MC_1_8_Version);
|
||||
|
||||
var serverPort = BitConverter.GetBytes((ushort)port);
|
||||
Array.Reverse(serverPort);
|
||||
|
||||
// Ping Packet
|
||||
var pingPacket = dataTypes.ConcatBytes(
|
||||
// Packet Id
|
||||
DataTypes.GetVarInt(0),
|
||||
|
||||
// Protocol Version
|
||||
DataTypes.GetVarInt(-1),
|
||||
|
||||
// Server IP (Host)
|
||||
dataTypes.GetString(host),
|
||||
|
||||
// Server port
|
||||
serverPort,
|
||||
|
||||
// Next State
|
||||
DataTypes.GetVarInt(1));
|
||||
|
||||
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(pingPacket.Length), pingPacket));
|
||||
|
||||
// Status Request Packet
|
||||
var statusRequest = DataTypes.GetVarInt(0);
|
||||
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(statusRequest.Length), statusRequest));
|
||||
|
||||
// Read Response length
|
||||
var packetLength = dataTypes.ReadNextVarIntRAW(socketWrapper);
|
||||
if (packetLength <= 0)
|
||||
return false;
|
||||
|
||||
// Read the Packet Id
|
||||
var packetData = new Queue<byte>(socketWrapper.ReadDataRAW(packetLength));
|
||||
if (dataTypes.ReadNextVarInt(packetData) != 0x00)
|
||||
return false;
|
||||
|
||||
var result = dataTypes.ReadNextString(packetData); // Get the Json data
|
||||
|
||||
if (Config.Logging.DebugMessages)
|
||||
{
|
||||
// May contain formatting codes, cannot use WriteLineFormatted
|
||||
Console.ForegroundColor = ConsoleColor.DarkGray;
|
||||
ConsoleIO.WriteLine(result);
|
||||
Console.ForegroundColor = ConsoleColor.Gray;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result) || !result.StartsWith("{") || !result.EndsWith("}"))
|
||||
return false;
|
||||
|
||||
var jsonData = Json.ParseJson(result);
|
||||
if (jsonData is not System.Text.Json.Nodes.JsonObject jsonObj || !jsonObj.ContainsKey("version"))
|
||||
return false;
|
||||
|
||||
var versionData = jsonObj["version"]!.AsObject();
|
||||
|
||||
// Retrieve display name of the Minecraft version
|
||||
if (versionData["name"] is { } nameNode)
|
||||
version = nameNode.GetStringValue();
|
||||
|
||||
// Retrieve protocol version number for handling this server
|
||||
if (versionData["protocol"] is { } protocolNode)
|
||||
protocolVersion = int.Parse(protocolNode.GetStringValue(),
|
||||
NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||
|
||||
// Check for forge on the server.
|
||||
Protocol18Forge.ServerInfoCheckForge(jsonObj, ref forgeInfo);
|
||||
|
||||
// Complete the normal status exchange so the probe connection closes cleanly server-side.
|
||||
try
|
||||
{
|
||||
long pingPayload = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
var pingRequest = dataTypes.ConcatBytes(DataTypes.GetVarInt(0x01), DataTypes.GetLong(pingPayload));
|
||||
socketWrapper.SendDataRAW(dataTypes.ConcatBytes(DataTypes.GetVarInt(pingRequest.Length), pingRequest));
|
||||
|
||||
packetLength = dataTypes.ReadNextVarIntRAW(socketWrapper);
|
||||
if (packetLength > 0)
|
||||
{
|
||||
packetData = new Queue<byte>(socketWrapper.ReadDataRAW(packetLength));
|
||||
if (dataTypes.ReadNextVarInt(packetData) == 0x01)
|
||||
dataTypes.ReadNextLong(packetData);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Some servers may close the probe connection immediately after the status response.
|
||||
}
|
||||
|
||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_server_protocol, version,
|
||||
protocolVersion + (forgeInfo != null ? Translations.mcc_with_forge : "")));
|
||||
|
||||
return true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
socketWrapper?.Disconnect();
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(result) || !result.StartsWith("{") || !result.EndsWith("}")) return false;
|
||||
|
||||
var jsonData = Json.ParseJson(result);
|
||||
if (jsonData is not System.Text.Json.Nodes.JsonObject jsonObj || !jsonObj.ContainsKey("version"))
|
||||
return false;
|
||||
|
||||
var versionData = jsonObj["version"]!.AsObject();
|
||||
|
||||
//Retrieve display name of the Minecraft version
|
||||
if (versionData["name"] is { } nameNode)
|
||||
version = nameNode.GetStringValue();
|
||||
|
||||
//Retrieve protocol version number for handling this server
|
||||
if (versionData["protocol"] is { } protocolNode)
|
||||
protocolVersion = int.Parse(protocolNode.GetStringValue(),
|
||||
NumberStyles.Any, CultureInfo.CurrentCulture);
|
||||
|
||||
// Check for forge on the server.
|
||||
Protocol18Forge.ServerInfoCheckForge(jsonObj, ref forgeInfo);
|
||||
|
||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.mcc_server_protocol, version,
|
||||
protocolVersion + (forgeInfo != null ? Translations.mcc_with_forge : "")));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@ namespace MinecraftClient.Protocol.ProfileKey
|
|||
ProxiedWebRequest.Response? response = null;
|
||||
try
|
||||
{
|
||||
if (!isYggdrasil && string.IsNullOrWhiteSpace(accessToken))
|
||||
return null;
|
||||
|
||||
if (!isYggdrasil)
|
||||
{
|
||||
var request = new ProxiedWebRequest(certificates)
|
||||
|
|
@ -34,11 +37,28 @@ namespace MinecraftClient.Protocol.ProfileKey
|
|||
{
|
||||
ConsoleIO.WriteLine(response.Body.ToString());
|
||||
}
|
||||
|
||||
if (response.StatusCode < 200 || response.StatusCode >= 300)
|
||||
{
|
||||
throw new InvalidOperationException(string.IsNullOrWhiteSpace(response.Body)
|
||||
? "Certificate endpoint returned an error response."
|
||||
: response.Body);
|
||||
}
|
||||
}
|
||||
|
||||
// see https://github.com/yushijinhun/authlib-injector/blob/da910956eaa30d2f6c2c457222d188aeb53b0d1f/src/main/java/moe/yushi/authlibinjector/httpd/ProfileKeyFilter.java#L49
|
||||
// POST to "https://api.minecraftservices.com/player/certificates" with authlib-injector will get a dummy response
|
||||
var json = isYggdrasil ? MakeDummyResponse() : Json.ParseJson(response!.Body);
|
||||
if (json?["keyPair"]?["publicKey"] == null
|
||||
|| json["keyPair"]?["privateKey"] == null
|
||||
|| json["publicKeySignature"] == null
|
||||
|| json["publicKeySignatureV2"] == null
|
||||
|| json["expiresAt"] == null
|
||||
|| json["refreshedAfter"] == null)
|
||||
{
|
||||
throw new InvalidOperationException("Certificate endpoint returned an unexpected payload.");
|
||||
}
|
||||
|
||||
// Error here
|
||||
PublicKey publicKey = new(pemKey: json!["keyPair"]!["publicKey"]!.GetStringValue(),
|
||||
sig: json["publicKeySignature"]!.GetStringValue(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue