diff --git a/spigot/build.gradle.kts b/spigot/build.gradle.kts index df4bbd895..376d1c9f8 100644 --- a/spigot/build.gradle.kts +++ b/spigot/build.gradle.kts @@ -25,6 +25,7 @@ dependencies { testImplementation("org.junit.jupiter:junit-jupiter:5.10.5") testImplementation("com.mojang", "authlib", authlibVersion) + testImplementation("io.netty", "netty-transport", Versions.nettyVersion) testImplementation("dev.folia", "folia-api", Versions.spigotVersion) { attributes { attribute(TargetJvmVersion.TARGET_JVM_VERSION_ATTRIBUTE, 17) diff --git a/spigot/src/main/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilter.java b/spigot/src/main/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilter.java index f5b8994a2..b12c12962 100644 --- a/spigot/src/main/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilter.java +++ b/spigot/src/main/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilter.java @@ -99,9 +99,14 @@ private static Object rewriteChatLastSeen(Object packet) throws Exception { } private static Object emptyLastSeenUpdate() throws Exception { - Constructor constructor = classForName(LAST_SEEN_UPDATE) - .getConstructor(int.class, BitSet.class, byte.class); - return constructor.newInstance(0, new BitSet(), (byte) 0); + Class lastSeenUpdate = classForName(LAST_SEEN_UPDATE); + try { + Constructor constructor = lastSeenUpdate.getConstructor(int.class, BitSet.class, byte.class); + return constructor.newInstance(0, new BitSet(), (byte) 0); + } catch (NoSuchMethodException ignored) { + Constructor constructor = lastSeenUpdate.getConstructor(int.class, BitSet.class); + return constructor.newInstance(0, new BitSet()); + } } private static Object invoke(Object target, String methodName) throws Exception { diff --git a/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterTest.java b/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterTest.java new file mode 100644 index 000000000..dc15a25fa --- /dev/null +++ b/spigot/src/test/java/com/minekube/connect/addon/data/SpigotChatSessionPacketFilterTest.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2021-2022 Minekube. https://minekube.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author Minekube + * @link https://github.com/minekube/connect-java + */ + +package com.minekube.connect.addon.data; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotSame; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.time.Instant; +import java.util.BitSet; +import net.minecraft.network.chat.LastSeenMessages; +import net.minecraft.network.chat.MessageSignature; +import net.minecraft.network.protocol.game.ServerboundChatPacket; +import org.junit.jupiter.api.Test; + +class SpigotChatSessionPacketFilterTest { + @Test + void rewritesChatPacketWhenLastSeenUpdateHasNoChecksumConstructor() throws Exception { + MessageSignature signature = new MessageSignature(); + ServerboundChatPacket packet = new ServerboundChatPacket( + "hello", + Instant.EPOCH, + 1L, + signature, + new LastSeenMessages.Update(4, new BitSet()) + ); + + ServerboundChatPacket rewritten = (ServerboundChatPacket) rewrite(packet); + + assertNotSame(packet, rewritten); + assertEquals("hello", rewritten.message()); + assertEquals(Instant.EPOCH, rewritten.timeStamp()); + assertEquals(1L, rewritten.salt()); + assertEquals(signature, rewritten.signature()); + assertEquals(0, rewritten.lastSeenMessages().offset()); + assertTrue(rewritten.lastSeenMessages().acknowledged().isEmpty()); + } + + private static Object rewrite(Object packet) throws Exception { + Method method = SpigotChatSessionPacketFilter.class.getDeclaredMethod("rewrite", Object.class); + method.setAccessible(true); + try { + return method.invoke(null, packet); + } catch (InvocationTargetException exception) { + Throwable cause = exception.getCause(); + if (cause instanceof Exception) { + throw (Exception) cause; + } + throw exception; + } + } +} diff --git a/spigot/src/test/java/net/minecraft/network/chat/LastSeenMessages.java b/spigot/src/test/java/net/minecraft/network/chat/LastSeenMessages.java new file mode 100644 index 000000000..9be4545ce --- /dev/null +++ b/spigot/src/test/java/net/minecraft/network/chat/LastSeenMessages.java @@ -0,0 +1,26 @@ +package net.minecraft.network.chat; + +import java.util.BitSet; + +public final class LastSeenMessages { + private LastSeenMessages() { + } + + public static final class Update { + private final int offset; + private final BitSet acknowledged; + + public Update(int offset, BitSet acknowledged) { + this.offset = offset; + this.acknowledged = acknowledged; + } + + public int offset() { + return offset; + } + + public BitSet acknowledged() { + return acknowledged; + } + } +} diff --git a/spigot/src/test/java/net/minecraft/network/chat/MessageSignature.java b/spigot/src/test/java/net/minecraft/network/chat/MessageSignature.java new file mode 100644 index 000000000..b80f58a84 --- /dev/null +++ b/spigot/src/test/java/net/minecraft/network/chat/MessageSignature.java @@ -0,0 +1,4 @@ +package net.minecraft.network.chat; + +public final class MessageSignature { +} diff --git a/spigot/src/test/java/net/minecraft/network/protocol/game/ServerboundChatPacket.java b/spigot/src/test/java/net/minecraft/network/protocol/game/ServerboundChatPacket.java new file mode 100644 index 000000000..f6f1be6ad --- /dev/null +++ b/spigot/src/test/java/net/minecraft/network/protocol/game/ServerboundChatPacket.java @@ -0,0 +1,47 @@ +package net.minecraft.network.protocol.game; + +import java.time.Instant; +import net.minecraft.network.chat.LastSeenMessages; +import net.minecraft.network.chat.MessageSignature; + +public final class ServerboundChatPacket { + private final String message; + private final Instant timeStamp; + private final long salt; + private final MessageSignature signature; + private final LastSeenMessages.Update lastSeenMessages; + + public ServerboundChatPacket( + String message, + Instant timeStamp, + long salt, + MessageSignature signature, + LastSeenMessages.Update lastSeenMessages + ) { + this.message = message; + this.timeStamp = timeStamp; + this.salt = salt; + this.signature = signature; + this.lastSeenMessages = lastSeenMessages; + } + + public String message() { + return message; + } + + public Instant timeStamp() { + return timeStamp; + } + + public long salt() { + return salt; + } + + public MessageSignature signature() { + return signature; + } + + public LastSeenMessages.Update lastSeenMessages() { + return lastSeenMessages; + } +}