mirror of
https://github.com/MCCTeam/Minecraft-Console-Client
synced 2025-11-07 17:36:07 +00:00
Implement Forge FML3 protocol (MC 1.18+) and Fix yggdrasil-auth chat issue
Implement Forge FML3 protocol (MC 1.18+) and Fix yggdrasil-auth chat issue
This commit is contained in:
commit
6faddae16e
6 changed files with 261 additions and 28 deletions
|
|
@ -557,7 +557,7 @@ namespace MinecraftClient
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Config.Main.General.AccountType == LoginType.microsoft
|
if ((Config.Main.General.AccountType == LoginType.microsoft || Config.Main.General.AccountType == LoginType.yggdrasil)
|
||||||
&& (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser)
|
&& (InternalConfig.Account.Password != "-" || Config.Main.General.Method == LoginMethod.browser)
|
||||||
&& Config.Signature.LoginWithSecureProfile
|
&& Config.Signature.LoginWithSecureProfile
|
||||||
&& protocolversion >= 759 /* 1.19 and above */)
|
&& protocolversion >= 759 /* 1.19 and above */)
|
||||||
|
|
@ -582,7 +582,7 @@ namespace MinecraftClient
|
||||||
if (playerKeyPair == null || playerKeyPair.NeedRefresh())
|
if (playerKeyPair == null || playerKeyPair.NeedRefresh())
|
||||||
{
|
{
|
||||||
ConsoleIO.WriteLineFormatted(Translations.mcc_fetching_key, acceptnewlines: true);
|
ConsoleIO.WriteLineFormatted(Translations.mcc_fetching_key, acceptnewlines: true);
|
||||||
playerKeyPair = KeyUtils.GetNewProfileKeys(session.ID);
|
playerKeyPair = KeyUtils.GetNewProfileKeys(session.ID, Config.Main.General.AccountType == LoginType.yggdrasil);
|
||||||
if (Config.Main.Advanced.ProfileKeyCache != CacheType.none && playerKeyPair != null)
|
if (Config.Main.Advanced.ProfileKeyCache != CacheType.none && playerKeyPair != null)
|
||||||
{
|
{
|
||||||
KeysCache.Store(loginLower, playerKeyPair);
|
KeysCache.Store(loginLower, playerKeyPair);
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
enum FMLVersion
|
enum FMLVersion
|
||||||
{
|
{
|
||||||
FML,
|
FML,
|
||||||
FML2
|
FML2,
|
||||||
|
FML3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,13 @@ namespace MinecraftClient.Protocol.Handlers.Forge
|
||||||
};
|
};
|
||||||
Version = fmlVersion;
|
Version = fmlVersion;
|
||||||
break;
|
break;
|
||||||
|
case FMLVersion.FML3:
|
||||||
|
Mods = new List<ForgeMod>
|
||||||
|
{
|
||||||
|
new ForgeMod("forge", "ANY")
|
||||||
|
};
|
||||||
|
Version = fmlVersion;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new InvalidOperationException(Translations.error_forgeforce);
|
throw new InvalidOperationException(Translations.error_forgeforce);
|
||||||
}
|
}
|
||||||
|
|
@ -133,10 +140,125 @@ namespace MinecraftClient.Protocol.Handlers.Forge
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
case FMLVersion.FML3:
|
||||||
|
// Example ModInfo for Minecraft 1.18 and greater (FML3)
|
||||||
|
|
||||||
|
// {
|
||||||
|
// "enforcesSecureChat": true,
|
||||||
|
// "forgeData": {
|
||||||
|
// "channels": [],
|
||||||
|
// "mods": [],
|
||||||
|
// "truncated": false, // legacy versions see truncated lists, modern versions ignore this truncated flag (binary data has its own)
|
||||||
|
// "fmlNetworkVersion": 3,
|
||||||
|
// "d": "ȳ\u0000\u0000ࠨ㐤獋㙖⹌ᦘ̺⸱恤䒸⡑⛧沮婙㨹牥ఈㄵচ₀沮婙㨹牥ఈㄵচ倠岙㜲獥䋊㷍᭳ႇׇ㘴娘▅筳ص䰭宛㘲、\u0000ᠸጋ囗湌夜㘲杩棐䐱ᅱ挃☥ోᤗ㌮ఀ䬣 坖ɍ䮌ᤘ\r\n旉䠳ዣ◆䲌㜃瑥廮ⷉࠋ–䁠奚Ҵ㔱摜䂸ᅱ獳ౠᡚ㜷汥戊䂸űဓĠ嵛㖱数嫤Ǎ塰䛶ⶎᮚ㞳晲擞ᖝ″ዣ䘆ఋʂ潦令ඕ爈䖔⺁ᥚ⾹潳棤㦥ᬻ挐䅀㠹楬ۨ㣄উ瀀渀嬛㘼扩搢䃀熁挂♥\r\n墋㒺摬牜ࣜ䁠嘗湌孛㜴浩惂䠙熙排٥孁㒰ͮ屢Ӏ䠐⚐䷮ᣛ㊴瑳戚䢸熁匒إܴ䫜巑፻ᚷؠ䀀ㆃ牵䋨㦥ࠫ㋣䗆䂌㨈慲䫬ᖱᮓᘧ汬尚ㆰ٫屲㣄ᆉ恳ಭ川㤷፫擨妅挫♖乮塘 㖱慰\r\n囆䓩\t"
|
||||||
|
// },
|
||||||
|
// "description": {
|
||||||
|
// "text": "A Minecraft Server"
|
||||||
|
// },
|
||||||
|
// "players": {
|
||||||
|
// "max": 100,
|
||||||
|
// "online": 0
|
||||||
|
// },
|
||||||
|
// "version": {
|
||||||
|
// "name": "1.20.1",
|
||||||
|
// "protocol": 763
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// All buffer data are encoded and write to forgeData["d"]
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/cb12df41e13da576b781be695f80728b9594c25f/src/main/java/net/minecraftforge/network/ServerStatusPing.java#L264
|
||||||
|
|
||||||
|
// 1.18 and greater, the buffer is encoded for efficiency
|
||||||
|
// see https://github.com/MinecraftForge/MinecraftForge/pull/8169
|
||||||
|
|
||||||
|
string encodedData = data.Properties["d"].StringValue;
|
||||||
|
Queue<byte> dataPackage = decodeOptimized(encodedData);
|
||||||
|
DataTypes dataTypes = new DataTypes(Protocol18Handler.MC_1_18_1_Version);
|
||||||
|
|
||||||
|
//
|
||||||
|
// [truncated][boolean] placeholder for whether we are truncating
|
||||||
|
// [Mod Size][unsigned short] short so that we can replace it later in case of truncation
|
||||||
|
//
|
||||||
|
bool truncated = dataTypes.ReadNextBool(dataPackage);
|
||||||
|
var modsSize = dataTypes.ReadNextUShort(dataPackage);
|
||||||
|
|
||||||
|
Dictionary<string, string> channels = new();
|
||||||
|
Dictionary<string, string> mods = new();
|
||||||
|
|
||||||
|
for (var i = 0; i < modsSize; i++) {
|
||||||
|
var channelSizeAndVersionFlag = dataTypes.ReadNextVarInt(dataPackage);
|
||||||
|
var channelSize = channelSizeAndVersionFlag >> 1;
|
||||||
|
|
||||||
|
int VERSION_FLAG_IGNORESERVERONLY = 0b1;
|
||||||
|
var isIgnoreServerOnly = (channelSizeAndVersionFlag & VERSION_FLAG_IGNORESERVERONLY) != 0;
|
||||||
|
|
||||||
|
var modId = dataTypes.ReadNextString(dataPackage);
|
||||||
|
|
||||||
|
string IGNORESERVERONLY = "";// it was "OHNOES\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31\uD83D\uDE31";
|
||||||
|
var modVersion = isIgnoreServerOnly ? IGNORESERVERONLY : dataTypes.ReadNextString(dataPackage);
|
||||||
|
|
||||||
|
for (var i1 = 0; i1 < channelSize; i1++) {
|
||||||
|
var channelName = dataTypes.ReadNextString(dataPackage);
|
||||||
|
var channelVersion = dataTypes.ReadNextString(dataPackage);
|
||||||
|
var requiredOnClient = dataTypes.ReadNextBool(dataPackage);
|
||||||
|
channels.Add(modId + ":" + channelName, channelVersion + ":" + requiredOnClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
mods.Add(modId, modVersion);
|
||||||
|
Mods.Add(new ForgeMod(modId, modVersion));
|
||||||
|
}
|
||||||
|
|
||||||
|
var nonModChannelCount = dataTypes.ReadNextVarInt(dataPackage);
|
||||||
|
for (var i = 0; i < nonModChannelCount; i++) {
|
||||||
|
var channelName = dataTypes.ReadNextString(dataPackage);
|
||||||
|
var channelVersion = dataTypes.ReadNextString(dataPackage);
|
||||||
|
var requiredOnClient = dataTypes.ReadNextBool(dataPackage);
|
||||||
|
channels.Add(channelName, channelVersion + ":" + requiredOnClient);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException("FMLVersion '" + fmlVersion + "' not implemented!");
|
throw new NotImplementedException("FMLVersion '" + fmlVersion + "' not implemented!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/cb12df41e13da576b781be695f80728b9594c25f/src/main/java/net/minecraftforge/network/ServerStatusPing.java#L361
|
||||||
|
// Decode binary data ForgeData["d"] to Queue<byte>
|
||||||
|
private static Queue<byte> decodeOptimized(string encodedData) {
|
||||||
|
// Console.WriteLine("Got encoded data:" + encodedData + ", decoding...");
|
||||||
|
int size0 = encodedData[0];
|
||||||
|
int size1 = encodedData[1];
|
||||||
|
int size = size0 | (size1 << 15);
|
||||||
|
|
||||||
|
List<byte> packageData = new();
|
||||||
|
|
||||||
|
int stringIndex = 2;
|
||||||
|
int buffer = 0;
|
||||||
|
int bitsInBuf = 0;
|
||||||
|
|
||||||
|
while (stringIndex < encodedData.Length)
|
||||||
|
{
|
||||||
|
while (bitsInBuf >= 8)
|
||||||
|
{
|
||||||
|
packageData.Add((byte)buffer);
|
||||||
|
buffer >>= 8;
|
||||||
|
bitsInBuf -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
char c = encodedData[stringIndex];
|
||||||
|
buffer |= (c & 0x7FFF) << bitsInBuf;
|
||||||
|
bitsInBuf += 15;
|
||||||
|
stringIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (packageData.Count < size)
|
||||||
|
{
|
||||||
|
packageData.Add((byte)buffer);
|
||||||
|
buffer >>= 8;
|
||||||
|
bitsInBuf -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Queue<byte>(packageData.ToArray());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -233,7 +233,7 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Handle Forge plugin messages during login phase (Forge Protocol version 2: FML2)
|
/// Handle Forge plugin messages during login phase (Forge Protocol version 2: FML2 or Forge Protocol version 3: FML3)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="channel">Plugin message channel</param>
|
/// <param name="channel">Plugin message channel</param>
|
||||||
/// <param name="packetData">Plugin message data</param>
|
/// <param name="packetData">Plugin message data</param>
|
||||||
|
|
@ -241,14 +241,18 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
/// <returns>TRUE/FALSE depending on whether the packet was understood or not</returns>
|
/// <returns>TRUE/FALSE depending on whether the packet was understood or not</returns>
|
||||||
public bool HandleLoginPluginRequest(string channel, Queue<byte> packetData, ref List<byte> responseData)
|
public bool HandleLoginPluginRequest(string channel, Queue<byte> packetData, ref List<byte> responseData)
|
||||||
{
|
{
|
||||||
if (ForgeEnabled() && forgeInfo!.Version == FMLVersion.FML2 && channel == "fml:loginwrapper")
|
if (ForgeEnabled() && (forgeInfo!.Version == FMLVersion.FML2 || forgeInfo!.Version == FMLVersion.FML3) && channel == "fml:loginwrapper")
|
||||||
{
|
{
|
||||||
// Forge Handshake handler source code used to implement the FML2 packets:
|
// Forge Handshake handler source code used to implement the FML2 packets:
|
||||||
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/FMLNetworkConstants.java
|
||||||
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/FMLHandshakeHandler.java
|
||||||
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/NetworkInitialization.java
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/NetworkInitialization.java
|
||||||
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/FMLLoginWrapper.java
|
||||||
// https://github.com/MinecraftForge/MinecraftForge/blob/master/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.13.x/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java
|
||||||
|
//
|
||||||
|
// FML3 packets:
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.18.x/src/main/java/net/minecraftforge/network/NetworkInitialization.java
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/1.18.x/src/main/java/net/minecraftforge/fml/network/FMLHandshakeMessages.java
|
||||||
//
|
//
|
||||||
// During Login, Forge will send a set of LoginPluginRequest packets and we need to respond accordingly.
|
// During Login, Forge will send a set of LoginPluginRequest packets and we need to respond accordingly.
|
||||||
// Each login plugin message contains in its payload field an inner packet created by FMLLoginWrapper.java:
|
// Each login plugin message contains in its payload field an inner packet created by FMLLoginWrapper.java:
|
||||||
|
|
@ -274,6 +278,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
// 2 = Client to Server - Mod List
|
// 2 = Client to Server - Mod List
|
||||||
// 3 = Server to Client - Registry
|
// 3 = Server to Client - Registry
|
||||||
// 4 = Server to Client - Config
|
// 4 = Server to Client - Config
|
||||||
|
// 5 = Server to Client - Mod Data List (FML3)
|
||||||
|
// 6 = Server to Client - MismatchedMod List (FML3)
|
||||||
//
|
//
|
||||||
// The content of each message is mapped into a class inside FMLHandshakeMessages.java
|
// The content of each message is mapped into a class inside FMLHandshakeMessages.java
|
||||||
// FMLHandshakeHandler will then process the packet, e.g. handleServerModListOnClient() for Server Mod List.
|
// FMLHandshakeHandler will then process the packet, e.g. handleServerModListOnClient() for Server Mod List.
|
||||||
|
|
@ -320,6 +326,15 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
for (int i = 0; i < registryCount; i++)
|
for (int i = 0; i < registryCount; i++)
|
||||||
registries.Add(dataTypes.ReadNextString(packetData));
|
registries.Add(dataTypes.ReadNextString(packetData));
|
||||||
|
|
||||||
|
// FML3 specific,
|
||||||
|
List<string> dataPackRegistries = new();
|
||||||
|
if (forgeInfo!.Version == FMLVersion.FML3 && packetData.Count != 0)
|
||||||
|
{
|
||||||
|
int dataPackRegistryCount = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
for (int i = 0; i < dataPackRegistryCount; i++)
|
||||||
|
dataPackRegistries.Add(dataTypes.ReadNextString(packetData));
|
||||||
|
}
|
||||||
|
|
||||||
// Server Mod List Reply: FMLHandshakeMessages.java > C2SModListReply > encode()
|
// Server Mod List Reply: FMLHandshakeMessages.java > C2SModListReply > encode()
|
||||||
//
|
//
|
||||||
// [ Mod Count ][ VarInt ]
|
// [ Mod Count ][ VarInt ]
|
||||||
|
|
@ -399,6 +414,53 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
fmlResponseReady = true;
|
fmlResponseReady = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
// FML 3
|
||||||
|
// Server Config: FMLHandshakeMessages.java > S2CModData > decode()
|
||||||
|
//
|
||||||
|
// We're ignoring this packet in MCC
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Uncomment this code block if needed
|
||||||
|
var size = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
Dictionary<string, string> modsData = new();
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
var modId = dataTypes.ReadNextString(packetData);
|
||||||
|
var displayName = dataTypes.ReadNextString(packetData);
|
||||||
|
var version = dataTypes.ReadNextString(packetData);
|
||||||
|
modsData.Add(modId, displayName + ":" + version);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + "Received FML3 Server Mod Data List");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
// FML 3
|
||||||
|
// Server Config: FMLHandshakeMessages.java > S2CChannelMismatchData > decode()
|
||||||
|
//
|
||||||
|
// We're ignoring this packet in MCC
|
||||||
|
|
||||||
|
/*
|
||||||
|
// Uncomment this code block if needed
|
||||||
|
Dictionary<string, string> mismatchedMods = new();
|
||||||
|
var size0 = dataTypes.ReadNextVarInt(packetData);
|
||||||
|
for (int i = 0; i < size0; i++)
|
||||||
|
{
|
||||||
|
var modId = dataTypes.ReadNextString(packetData);
|
||||||
|
var version = dataTypes.ReadNextString(packetData);
|
||||||
|
mismatchedMods.Add(modId, version);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
|
{
|
||||||
|
ConsoleIO.WriteLineFormatted("§8" + "Received FML3 Server Mismatched Mods List");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (Settings.Config.Logging.DebugMessages)
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.forge_fml2_unknown, packetID));
|
ConsoleIO.WriteLineFormatted("§8" + string.Format(Translations.forge_fml2_unknown, packetID));
|
||||||
|
|
@ -442,7 +504,8 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
public static bool ServerInfoCheckForge(Json.JSONData jsonData, ref ForgeInfo? forgeInfo)
|
public static bool ServerInfoCheckForge(Json.JSONData jsonData, ref ForgeInfo? forgeInfo)
|
||||||
{
|
{
|
||||||
return ServerInfoCheckForgeSub(jsonData, ref forgeInfo, FMLVersion.FML) // MC 1.12 and lower
|
return ServerInfoCheckForgeSub(jsonData, ref forgeInfo, FMLVersion.FML) // MC 1.12 and lower
|
||||||
|| ServerInfoCheckForgeSub(jsonData, ref forgeInfo, FMLVersion.FML2); // MC 1.13 and greater
|
|| ServerInfoCheckForgeSub(jsonData, ref forgeInfo, FMLVersion.FML2) // MC 1.13 to 1.17
|
||||||
|
|| ServerInfoCheckForgeSub(jsonData, ref forgeInfo, FMLVersion.FML3); // MC 1.18 and greater
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
@ -464,13 +527,21 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
{
|
{
|
||||||
if (ServerMayForceForge(protocolVersion))
|
if (ServerMayForceForge(protocolVersion))
|
||||||
{
|
{
|
||||||
|
// 1.17 is still FML2
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/50b5414033de82f46be23201db50484f36c37d4f/src/main/java/net/minecraftforge/fmllegacy/network/FMLNetworkConstants.java#L37C29-L37C42
|
||||||
|
// 1.18 change the constant FMLNETVERSION to 3
|
||||||
|
// https://github.com/MinecraftForge/MinecraftForge/blob/cb12df41e13da576b781be695f80728b9594c25f/src/main/java/net/minecraftforge/network/NetworkConstants.java#L28
|
||||||
|
if (protocolVersion > ProtocolHandler.MCVer2ProtocolVersion("1.18"))
|
||||||
|
{
|
||||||
|
return new ForgeInfo(FMLVersion.FML3);
|
||||||
|
}
|
||||||
return new ForgeInfo(FMLVersion.FML2);
|
return new ForgeInfo(FMLVersion.FML2);
|
||||||
}
|
}
|
||||||
else throw new InvalidOperationException(Translations.error_forgeforce);
|
else throw new InvalidOperationException(Translations.error_forgeforce);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Server Info: Check for For Forge on a Minecraft server Ping result (Handles FML and FML2
|
/// Server Info: Check for For Forge on a Minecraft server Ping result (Handles FML and FML2 and FML3
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="jsonData">JSON data returned by the server</param>
|
/// <param name="jsonData">JSON data returned by the server</param>
|
||||||
/// <param name="forgeInfo">ForgeInfo to populate</param>
|
/// <param name="forgeInfo">ForgeInfo to populate</param>
|
||||||
|
|
@ -494,6 +565,11 @@ namespace MinecraftClient.Protocol.Handlers
|
||||||
versionField = "fmlNetworkVersion";
|
versionField = "fmlNetworkVersion";
|
||||||
versionString = "2";
|
versionString = "2";
|
||||||
break;
|
break;
|
||||||
|
case FMLVersion.FML3:
|
||||||
|
forgeDataTag = "forgeData";
|
||||||
|
versionField = "fmlNetworkVersion";
|
||||||
|
versionString = "3";
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
throw new NotImplementedException("FMLVersion '" + fmlVersion + "' not implemented!");
|
throw new NotImplementedException("FMLVersion '" + fmlVersion + "' not implemented!");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ using System.Text;
|
||||||
using MinecraftClient.Protocol.Handlers;
|
using MinecraftClient.Protocol.Handlers;
|
||||||
using MinecraftClient.Protocol.Message;
|
using MinecraftClient.Protocol.Message;
|
||||||
using static MinecraftClient.Protocol.Message.LastSeenMessageList;
|
using static MinecraftClient.Protocol.Message.LastSeenMessageList;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace MinecraftClient.Protocol.ProfileKey
|
namespace MinecraftClient.Protocol.ProfileKey
|
||||||
{
|
{
|
||||||
|
|
@ -14,27 +15,34 @@ namespace MinecraftClient.Protocol.ProfileKey
|
||||||
|
|
||||||
private static readonly string certificates = "https://api.minecraftservices.com/player/certificates";
|
private static readonly string certificates = "https://api.minecraftservices.com/player/certificates";
|
||||||
|
|
||||||
public static PlayerKeyPair? GetNewProfileKeys(string accessToken)
|
public static PlayerKeyPair? GetNewProfileKeys(string accessToken, bool isYggdrasil)
|
||||||
{
|
{
|
||||||
ProxiedWebRequest.Response? response = null;
|
ProxiedWebRequest.Response? response = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var request = new ProxiedWebRequest(certificates)
|
if (!isYggdrasil) {
|
||||||
{
|
var request = new ProxiedWebRequest(certificates)
|
||||||
Accept = "application/json"
|
{
|
||||||
};
|
Accept = "application/json"
|
||||||
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
|
};
|
||||||
|
request.Headers.Add("Authorization", string.Format("Bearer {0}", accessToken));
|
||||||
|
|
||||||
response = request.Post("application/json", "");
|
response = request.Post("application/json", "");
|
||||||
|
|
||||||
if (Settings.Config.Logging.DebugMessages)
|
if (Settings.Config.Logging.DebugMessages)
|
||||||
{
|
{
|
||||||
ConsoleIO.WriteLine(response.Body.ToString());
|
ConsoleIO.WriteLine(response.Body.ToString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string jsonString = 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
|
||||||
|
string jsonString = isYggdrasil ? MakeDummyResponse() : response!.Body;
|
||||||
Json.JSONData json = Json.ParseJson(jsonString);
|
Json.JSONData json = Json.ParseJson(jsonString);
|
||||||
|
Console.WriteLine("Got public key:" + json.Properties["keyPair"].Properties["publicKey"].StringValue);
|
||||||
|
Console.WriteLine("Got private key:" + json.Properties["keyPair"].Properties["privateKey"].StringValue);
|
||||||
|
|
||||||
|
// Error here
|
||||||
PublicKey publicKey = new(pemKey: json.Properties["keyPair"].Properties["publicKey"].StringValue,
|
PublicKey publicKey = new(pemKey: json.Properties["keyPair"].Properties["publicKey"].StringValue,
|
||||||
sig: json.Properties["publicKeySignature"].StringValue,
|
sig: json.Properties["publicKeySignature"].StringValue,
|
||||||
sigV2: json.Properties["publicKeySignatureV2"].StringValue);
|
sigV2: json.Properties["publicKeySignatureV2"].StringValue);
|
||||||
|
|
@ -230,5 +238,30 @@ namespace MinecraftClient.Protocol.ProfileKey
|
||||||
sb.Append(src, start, src.Length - start);
|
sb.Append(src, start, src.Length - start);
|
||||||
return sb.ToString();
|
return sb.ToString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string MakeDummyResponse()
|
||||||
|
{
|
||||||
|
RSACryptoServiceProvider rsa = new RSACryptoServiceProvider(2048);
|
||||||
|
var mimePublicKey = Convert.ToBase64String(rsa.ExportSubjectPublicKeyInfo());
|
||||||
|
var mimePrivateKey = Convert.ToBase64String(rsa.ExportPkcs8PrivateKey());
|
||||||
|
string publicKeyPEM = $"-----BEGIN RSA PUBLIC KEY-----\n{mimePublicKey}\n-----END RSA PUBLIC KEY-----\n";
|
||||||
|
string privateKeyPEM = $"-----BEGIN RSA PRIVATE KEY-----\n{mimePrivateKey}\n-----END RSA PRIVATE KEY-----\n";
|
||||||
|
DateTime now = DateTime.UtcNow;
|
||||||
|
DateTime expiresAt = now.AddHours(48);
|
||||||
|
DateTime refreshedAfter = now.AddHours(36);
|
||||||
|
JObject response = new JObject();
|
||||||
|
JObject keyPairObj = new JObject
|
||||||
|
{
|
||||||
|
{ "privateKey", privateKeyPEM },
|
||||||
|
{ "publicKey", publicKeyPEM }
|
||||||
|
};
|
||||||
|
response.Add("keyPair", keyPairObj);
|
||||||
|
response.Add("publicKeySignature", "AA==");
|
||||||
|
response.Add("publicKeySignatureV2", "AA==");
|
||||||
|
string format = "yyyy-MM-ddTHH:mm:ss.ffffffZ";
|
||||||
|
response.Add("expiresAt", expiresAt.ToString(format));
|
||||||
|
response.Add("refreshedAfter", refreshedAfter.ToString(format));
|
||||||
|
return response.ToString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1100,7 +1100,8 @@ namespace MinecraftClient.Protocol
|
||||||
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)
|
if (statusCode != 204)
|
||||||
{
|
{
|
||||||
postResult = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..].Split("\r\n")[1];
|
var splited = raw_result[(raw_result.IndexOf("\r\n\r\n") + 4)..].Split("\r\n");
|
||||||
|
postResult = splited[1] + splited[3];
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue