From abe880dae6cfdb48ca82ab55f97e916a623da15c Mon Sep 17 00:00:00 2001 From: EnZaXD <60033407+FlorianMichael@users.noreply.github.com> Date: Tue, 24 Oct 2023 02:04:54 +0200 Subject: [PATCH] Implement provider to allow signed commands in 1.19.x protocols (#3493) --- .../SignableCommandArgumentsProvider.java | 37 +++++++++++++++++++ .../Protocol1_19_1To1_19.java | 33 +++++++++++++++-- .../Protocol1_19_3To1_19_1.java | 32 +++++++++++++++- 3 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/SignableCommandArgumentsProvider.java diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/SignableCommandArgumentsProvider.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/SignableCommandArgumentsProvider.java new file mode 100644 index 000000000..2907a3e56 --- /dev/null +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/signature/SignableCommandArgumentsProvider.java @@ -0,0 +1,37 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2023 ViaVersion and contributors + * + * 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. + */ +package com.viaversion.viaversion.api.minecraft.signature; + +import com.viaversion.viaversion.api.platform.providers.Provider; +import com.viaversion.viaversion.util.Pair; + +import java.util.List; + +public abstract class SignableCommandArgumentsProvider implements Provider { + + /** + * @param command The command to get the signable arguments for. + * @return The signable arguments for the command. + */ + public abstract List> getSignableArguments(final String command); +} diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_1to1_19/Protocol1_19_1To1_19.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_1to1_19/Protocol1_19_1To1_19.java index 533f17984..a6c51168d 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_1to1_19/Protocol1_19_1To1_19.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_1to1_19/Protocol1_19_1To1_19.java @@ -24,6 +24,7 @@ import com.google.gson.JsonElement; import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.minecraft.ProfileKey; +import com.viaversion.viaversion.api.minecraft.signature.SignableCommandArgumentsProvider; import com.viaversion.viaversion.api.minecraft.signature.model.DecoratableMessage; import com.viaversion.viaversion.api.minecraft.signature.model.MessageMetadata; import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19_0; @@ -44,6 +45,7 @@ import com.viaversion.viaversion.protocols.protocol1_19_1to1_19.storage.NonceSto import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ClientboundPackets1_19; import com.viaversion.viaversion.protocols.protocol1_19to1_18_2.ServerboundPackets1_19; import com.viaversion.viaversion.util.CipherUtil; +import com.viaversion.viaversion.util.Pair; import org.checkerframework.checker.nullness.qual.Nullable; import java.util.ArrayList; @@ -165,10 +167,35 @@ public final class Protocol1_19_1To1_19 extends AbstractProtocol { - final int signatures = wrapper.passthrough(Type.VAR_INT); + final ChatSession1_19_0 chatSession = wrapper.user().get(ChatSession1_19_0.class); + final SignableCommandArgumentsProvider argumentsProvider = Via.getManager().getProviders().get(SignableCommandArgumentsProvider.class); + + final int signatures = wrapper.read(Type.VAR_INT); for (int i = 0; i < signatures; i++) { - wrapper.passthrough(Type.STRING); // Argument name - wrapper.passthrough(Type.BYTE_ARRAY_PRIMITIVE); // Signature + wrapper.read(Type.STRING); // Argument name + wrapper.read(Type.BYTE_ARRAY_PRIMITIVE); // Signature + } + + if (chatSession != null && argumentsProvider != null) { + final UUID sender = wrapper.user().getProtocolInfo().getUuid(); + final String message = wrapper.get(Type.STRING, 0); + final long timestamp = wrapper.get(Type.LONG, 0); + final long salt = wrapper.get(Type.LONG, 1); + + final List> arguments = argumentsProvider.getSignableArguments(message); + + wrapper.write(Type.VAR_INT, arguments.size()); // Signature count + for (Pair argument : arguments) { + final MessageMetadata metadata = new MessageMetadata(sender, timestamp, salt); + final DecoratableMessage decoratableMessage = new DecoratableMessage(argument.value()); + + final byte[] signature = chatSession.signChatMessage(metadata, decoratableMessage); + + wrapper.write(Type.STRING, argument.key()); // Argument name + wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, signature); // Signature + } + } else { + wrapper.write(Type.VAR_INT, 0); // Signature count } }); map(Type.BOOLEAN); // Signed preview diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java index a8a4295ac..b27fde3f7 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_19_3to1_19_1/Protocol1_19_3To1_19_1.java @@ -19,12 +19,14 @@ package com.viaversion.viaversion.protocols.protocol1_19_3to1_19_1; import com.google.common.primitives.Longs; import com.google.gson.JsonElement; +import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.connection.UserConnection; import com.viaversion.viaversion.api.data.MappingData; import com.viaversion.viaversion.api.data.MappingDataBase; import com.viaversion.viaversion.api.minecraft.PlayerMessageSignature; import com.viaversion.viaversion.api.minecraft.RegistryType; import com.viaversion.viaversion.api.minecraft.entities.EntityTypes1_19_3; +import com.viaversion.viaversion.api.minecraft.signature.SignableCommandArgumentsProvider; import com.viaversion.viaversion.api.minecraft.signature.model.DecoratableMessage; import com.viaversion.viaversion.api.minecraft.signature.model.MessageMetadata; import com.viaversion.viaversion.api.minecraft.signature.storage.ChatSession1_19_1; @@ -51,7 +53,9 @@ import com.viaversion.viaversion.rewriter.CommandRewriter; import com.viaversion.viaversion.rewriter.SoundRewriter; import com.viaversion.viaversion.rewriter.StatisticsRewriter; import com.viaversion.viaversion.rewriter.TagRewriter; +import com.viaversion.viaversion.util.Pair; +import java.util.List; import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; @@ -217,16 +221,40 @@ public final class Protocol1_19_3To1_19_1 extends AbstractProtocol { + final ChatSession1_19_1 chatSession = wrapper.user().get(ChatSession1_19_1.class); + final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class); + final int signatures = wrapper.read(Type.VAR_INT); - wrapper.write(Type.VAR_INT, 0); for (int i = 0; i < signatures; i++) { wrapper.read(Type.STRING); // Argument name wrapper.read(Type.SIGNATURE_BYTES); // Signature } + final SignableCommandArgumentsProvider argumentsProvider = Via.getManager().getProviders().get(SignableCommandArgumentsProvider.class); + if (chatSession != null && argumentsProvider != null) { + final UUID sender = wrapper.user().getProtocolInfo().getUuid(); + final String message = wrapper.get(Type.STRING, 0); + final long timestamp = wrapper.get(Type.LONG, 0); + final long salt = wrapper.get(Type.LONG, 1); + + final List> arguments = argumentsProvider.getSignableArguments(message); + wrapper.write(Type.VAR_INT, arguments.size()); // Signature count + + for (Pair argument : arguments) { + final MessageMetadata metadata = new MessageMetadata(sender, timestamp, salt); + final DecoratableMessage decoratableMessage = new DecoratableMessage(argument.value()); + + final byte[] signature = chatSession.signChatMessage(metadata, decoratableMessage, messagesStorage.lastSignatures()); + + wrapper.write(Type.STRING, argument.key()); // Argument name + wrapper.write(Type.BYTE_ARRAY_PRIMITIVE, signature); // Signature + } + } else { + wrapper.write(Type.VAR_INT, 0); // Signature count + } + wrapper.write(Type.BOOLEAN, false); // No signed preview - final ReceivedMessagesStorage messagesStorage = wrapper.user().get(ReceivedMessagesStorage.class); messagesStorage.resetUnacknowledgedCount(); wrapper.write(Type.PLAYER_MESSAGE_SIGNATURE_ARRAY, messagesStorage.lastSignatures()); wrapper.write(Type.OPTIONAL_PLAYER_MESSAGE_SIGNATURE, null); // No last unacknowledged