1.19.3 Message signing support.

This commit is contained in:
BruceChen 2023-01-13 16:12:10 +08:00
parent e447fea16b
commit fe0b268878
13 changed files with 532 additions and 313 deletions

View file

@ -57,9 +57,9 @@ namespace MinecraftClient.Protocol.Message
this.senderUUID = senderUUID;
}
public LastSeenMessageList.Entry? ToLastSeenMessageEntry()
public LastSeenMessageList.AcknowledgedMessage? ToLastSeenMessageEntry()
{
return signature != null ? new LastSeenMessageList.Entry(senderUUID, signature) : null;
return signature != null ? new LastSeenMessageList.AcknowledgedMessage(senderUUID, signature, true) : null;
}
public bool LacksSender()

View file

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Security.Permissions;
using static MinecraftClient.Protocol.Message.LastSeenMessageList;
namespace MinecraftClient.Protocol.Message
{
@ -8,38 +10,45 @@ namespace MinecraftClient.Protocol.Message
/// </summary>
public class LastSeenMessageList
{
public static readonly LastSeenMessageList EMPTY = new(Array.Empty<Entry>());
public static readonly LastSeenMessageList EMPTY = new(Array.Empty<AcknowledgedMessage>());
public static readonly int MAX_ENTRIES = 5;
public Entry[] entries;
public AcknowledgedMessage[] entries;
public LastSeenMessageList(Entry[] list)
public LastSeenMessageList(AcknowledgedMessage[] list)
{
entries = list;
}
public void WriteForSign(List<byte> data)
{
foreach (Entry entry in entries)
foreach (AcknowledgedMessage entry in entries)
{
data.Add(70);
data.AddRange(entry.profileId.ToBigEndianBytes());
data.AddRange(entry.lastSignature);
data.AddRange(entry.signature);
}
}
/// <summary>
/// A pair of a player's UUID and the signature of the last message they saw, used as an entry of LastSeenMessageList.
/// </summary>
public class Entry
public record AcknowledgedMessage
{
public bool pending;
public Guid profileId;
public byte[] lastSignature;
public byte[] signature;
public Entry(Guid profileId, byte[] lastSignature)
public AcknowledgedMessage(Guid profileId, byte[] lastSignature, bool pending)
{
this.profileId = profileId;
this.lastSignature = lastSignature;
this.signature = lastSignature;
this.pending = pending;
}
public AcknowledgedMessage UnmarkAsPending()
{
return this.pending ? new AcknowledgedMessage(profileId, signature, false) : this;
}
}
@ -50,9 +59,9 @@ namespace MinecraftClient.Protocol.Message
public class Acknowledgment
{
public LastSeenMessageList lastSeen;
public Entry? lastReceived;
public AcknowledgedMessage? lastReceived;
public Acknowledgment(LastSeenMessageList lastSeenMessageList, Entry? lastReceivedMessage)
public Acknowledgment(LastSeenMessageList lastSeenMessageList, AcknowledgedMessage? lastReceivedMessage)
{
lastSeen = lastSeenMessageList;
lastReceived = lastReceivedMessage;
@ -70,24 +79,26 @@ namespace MinecraftClient.Protocol.Message
/// </summary>
public class LastSeenMessagesCollector
{
private readonly LastSeenMessageList.Entry[] entries;
private int size = 0;
private readonly LastSeenMessageList.AcknowledgedMessage?[] acknowledgedMessages;
private int nextIndex = 0;
internal int messageCount { private set; get; } = 0;
private LastSeenMessageList.AcknowledgedMessage? lastEntry = null;
private LastSeenMessageList lastSeenMessages;
public LastSeenMessagesCollector(int size)
{
lastSeenMessages = LastSeenMessageList.EMPTY;
entries = new LastSeenMessageList.Entry[size];
acknowledgedMessages = new LastSeenMessageList.AcknowledgedMessage[size];
}
public void Add(LastSeenMessageList.Entry entry)
public void Add_1_19_2(LastSeenMessageList.AcknowledgedMessage entry)
{
LastSeenMessageList.Entry? lastEntry = entry;
LastSeenMessageList.AcknowledgedMessage? lastEntry = entry;
for (int i = 0; i < size; ++i)
for (int i = 0; i < messageCount; ++i)
{
LastSeenMessageList.Entry curEntry = entries[i];
entries[i] = lastEntry;
LastSeenMessageList.AcknowledgedMessage curEntry = acknowledgedMessages[i]!;
acknowledgedMessages[i] = lastEntry;
lastEntry = curEntry;
if (curEntry.profileId == entry.profileId)
{
@ -96,19 +107,62 @@ namespace MinecraftClient.Protocol.Message
}
}
if (lastEntry != null && size < entries.Length)
entries[size++] = lastEntry;
if (lastEntry != null && messageCount < acknowledgedMessages.Length)
acknowledgedMessages[messageCount++] = lastEntry;
LastSeenMessageList.Entry[] msgList = new LastSeenMessageList.Entry[size];
for (int i = 0; i < size; ++i)
msgList[i] = entries[i];
LastSeenMessageList.AcknowledgedMessage[] msgList = new LastSeenMessageList.AcknowledgedMessage[messageCount];
for (int i = 0; i < messageCount; ++i)
msgList[i] = acknowledgedMessages[i]!;
lastSeenMessages = new LastSeenMessageList(msgList);
}
public bool Add_1_19_3(LastSeenMessageList.AcknowledgedMessage entry, bool displayed)
{
// net.minecraft.network.message.LastSeenMessagesCollector#add(net.minecraft.network.message.MessageSignatureData, boolean)
// net.minecraft.network.message.LastSeenMessagesCollector#add(net.minecraft.network.message.AcknowledgedMessage)
if (entry == lastEntry)
return false;
lastEntry = entry;
int index = nextIndex;
nextIndex = (index + 1) % acknowledgedMessages.Length;
++messageCount;
acknowledgedMessages[index] = displayed ? entry : null;
return true;
}
public Tuple<AcknowledgedMessage[], byte[], int> Collect_1_19_3()
{
// net.minecraft.network.message.LastSeenMessagesCollector#collect
int count = ResetMessageCount();
byte[] bitset = new byte[3]; // new Bitset(20); Todo: Use a complete bitset implementation.
List<AcknowledgedMessage> objectList = new(acknowledgedMessages.Length);
for (int j = 0; j < acknowledgedMessages.Length; ++j)
{
int k = (nextIndex + j) % acknowledgedMessages.Length;
AcknowledgedMessage? acknowledgedMessage = acknowledgedMessages[k];
if (acknowledgedMessage == null)
continue;
bitset[j / 8] |= (byte)(1 << (j % 8)); // bitSet.set(j, true);
objectList.Add(acknowledgedMessage);
acknowledgedMessages[k] = acknowledgedMessage.UnmarkAsPending();
}
return new(objectList.ToArray(), bitset, count);
}
public LastSeenMessageList GetLastSeenMessages()
{
return lastSeenMessages;
}
public int ResetMessageCount()
{
// net.minecraft.network.message.LastSeenMessagesCollector#resetMessageCount
int cnt = messageCount;
messageCount = 0;
return cnt;
}
}
}