diff --git a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java index 3c75254b..c0207398 100644 --- a/src/main/java/com/comphenix/protocol/events/AbstractStructure.java +++ b/src/main/java/com/comphenix/protocol/events/AbstractStructure.java @@ -1017,7 +1017,7 @@ public abstract class AbstractStructure { } /** - * @return read/writer structure direct access to signature data like chat messages + * @return read/writer structure direct access to salted signature data like chat messages */ public StructureModifier getSignatures() { return structureModifier.withType( @@ -1026,6 +1026,16 @@ public abstract class AbstractStructure { ); } + /** + * @return read/writer structure direct access to unsalted signature data for example in chat message (since 1.19.3) + */ + public StructureModifier getMessageSignatures() { + return structureModifier.withType( + MinecraftReflection.getMessageSignatureClass(), + BukkitConverters.getWrappedMessageSignatureConverter() + ); + } + /** * @param leftConverter converter for left values * @param rightConverter converter for right values diff --git a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java index 3263782e..3b01e3a5 100644 --- a/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java +++ b/src/main/java/com/comphenix/protocol/utility/MinecraftReflection.java @@ -1573,6 +1573,10 @@ public final class MinecraftReflection { return getMinecraftClass("world.entity.player.ProfilePublicKey"); } + public static Class getMessageSignatureClass() { + return getMinecraftClass("network.chat.MessageSignature"); + } + public static Class getSaltedSignatureClass() { try { return getMinecraftClass("SaltedSignature"); diff --git a/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java b/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java index 8a554950..d7d53495 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java +++ b/src/main/java/com/comphenix/protocol/wrappers/BukkitConverters.java @@ -615,6 +615,13 @@ public class BukkitConverters { return ignoreNull(handle(WrappedSaltedSignature::getHandle, WrappedSaltedSignature::new, WrappedSaltedSignature.class)); } + /** + * @return converter for an encoded cryptographic message signature + */ + public static EquivalentConverter getWrappedMessageSignatureConverter() { + return ignoreNull(handle(WrappedMessageSignature::getHandle, WrappedMessageSignature::new, WrappedMessageSignature.class)); + } + public static EquivalentConverter getWrappedChunkDataConverter() { return ignoreNull(handle(WrappedLevelChunkData.ChunkData::getHandle, WrappedLevelChunkData.ChunkData::new, WrappedLevelChunkData.ChunkData.class)); } diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedMessageSignature.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedMessageSignature.java new file mode 100644 index 00000000..85ae86d6 --- /dev/null +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedMessageSignature.java @@ -0,0 +1,48 @@ +package com.comphenix.protocol.wrappers; + +import com.comphenix.protocol.reflect.StructureModifier; +import com.comphenix.protocol.reflect.accessors.Accessors; +import com.comphenix.protocol.reflect.accessors.ConstructorAccessor; +import com.comphenix.protocol.utility.MinecraftReflection; + +/** + * @author Lukas Alt + * @since 24.04.2023 + */ +public class WrappedMessageSignature extends AbstractWrapper { + private final static Class HANDLE_TYPE = MinecraftReflection.getMessageSignatureClass(); + private static ConstructorAccessor CONSTRUCTOR; + private StructureModifier modifier; + + /** + * Construct a new NMS wrapper. + * + * @param handle - the NMS handle + */ + public WrappedMessageSignature(Object handle) { + super(HANDLE_TYPE); + this.setHandle(handle); + } + + public WrappedMessageSignature(byte[] bytes) { + super(HANDLE_TYPE); + if(CONSTRUCTOR == null) { + CONSTRUCTOR = Accessors.getConstructorAccessor(HANDLE_TYPE, byte[].class); + } + this.setHandle(CONSTRUCTOR.invoke(bytes)); + } + + @Override + protected void setHandle(Object handle) { + super.setHandle(handle); + this.modifier = new StructureModifier<>(HANDLE_TYPE).withTarget(handle); + } + + public byte[] getBytes() { + return modifier.withType(byte[].class).read(0); + } + + public void setBytes(byte[] bytes) { + modifier.withType(byte[].class).write(0, bytes); + } +} diff --git a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java index f2c01948..5aef1541 100644 --- a/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java +++ b/src/test/java/com/comphenix/protocol/events/PacketContainerTest.java @@ -774,21 +774,17 @@ public class PacketContainerTest { Assertions.assertEquals(NativeGameMode.CREATIVE, firstData.getGameMode()); } - // TODO: fix this this at some point - /* @Test public void testSignedChatMessage() { PacketContainer chatPacket = new PacketContainer(PacketType.Play.Client.CHAT); - byte[] signature = new byte[512]; - long salt = 124L; - WrappedSaltedSignature wrappedSignature = new WrappedSaltedSignature(salt, signature); - chatPacket.getSignatures().write(0, wrappedSignature); + byte[] signature = new byte[256]; + WrappedMessageSignature wrappedSignature = new WrappedMessageSignature(signature); + chatPacket.getMessageSignatures().write(0, wrappedSignature); - WrappedSaltedSignature read = chatPacket.getSignatures().read(0); - assertEquals(salt, read.getSalt()); - assertArrayEquals(signature, read.getSignature()); - }*/ + WrappedMessageSignature read = chatPacket.getMessageSignatures().read(0); + assertArrayEquals(signature, read.getBytes()); + } private void assertPacketsEqualAndSerializable(PacketContainer constructed, PacketContainer cloned) { StructureModifier firstMod = constructed.getModifier(), secondMod = cloned.getModifier(); diff --git a/src/test/java/com/comphenix/protocol/wrappers/BukkitConvertersTest.java b/src/test/java/com/comphenix/protocol/wrappers/BukkitConvertersTest.java index 21ba518e..5b1cd923 100644 --- a/src/test/java/com/comphenix/protocol/wrappers/BukkitConvertersTest.java +++ b/src/test/java/com/comphenix/protocol/wrappers/BukkitConvertersTest.java @@ -16,18 +16,9 @@ import org.bukkit.inventory.meta.ItemMeta; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.security.KeyFactory; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.PublicKey; -import java.security.spec.EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; -import java.time.Instant; import java.util.Random; -import java.util.UUID; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.*; public class BukkitConvertersTest { @@ -69,18 +60,27 @@ public class BukkitConvertersTest { assertEquals(wrapped.right(), nmsEither.right()); } - @Test - public void testPacketContainerConverter() { - for (PacketType type : PacketType.values()) { - if (!type.isSupported()) { - continue; - } - PacketContainer container = new PacketContainer(type); - Object generic = BukkitConverters.getPacketContainerConverter().getGeneric(container); - Object specific = BukkitConverters.getPacketContainerConverter().getSpecific(generic); - assertTrue(EqualsBuilder.reflectionEquals(container, specific)); // PacketContainer does not properly implement equals(.) - } - } + @Test + public void testPacketContainerConverter() { + for (PacketType type : PacketType.values()) { + if(!type.isSupported()) { + continue; + } + PacketContainer container = new PacketContainer(type); + Object generic = BukkitConverters.getPacketContainerConverter().getGeneric(container); + Object specific = BukkitConverters.getPacketContainerConverter().getSpecific(generic); + assertTrue(EqualsBuilder.reflectionEquals(container, specific)); // PacketContainer does not properly implement equals(.) + } + } + + @Test + void getWrappedMessageSignatureConverter() { + byte[] data = new byte[256]; + new Random().nextBytes(data); + WrappedMessageSignature messageSignature = new WrappedMessageSignature(data); + + assertArrayEquals(data, BukkitConverters.getWrappedMessageSignatureConverter().getSpecific(BukkitConverters.getWrappedMessageSignatureConverter().getGeneric(messageSignature)).getBytes()); + } @Test public void testRemoteChatSessionDataConverter() throws Exception {