Signature forwarding works

This commit is contained in:
Noel Németh 2022-06-10 17:01:30 +02:00
parent c4b5a2020d
commit 6b489b5843
8 changed files with 95 additions and 43 deletions

View File

@ -58,7 +58,8 @@ public interface PacketGroupingAudience extends ForwardingAudience {
@Override
default void sendMessage(@NotNull Identity source, @NotNull Component message, @NotNull MessageType type) {
Messenger.sendMessage(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid());
// FIXME: 2022. 06. 10.
// Messenger.send(this.getPlayers(), message, ChatPosition.fromMessageType(type), source.uuid());
}
@Override

View File

@ -0,0 +1,25 @@
package net.minestom.server.crypto;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import net.minestom.server.utils.binary.Writeable;
import org.jetbrains.annotations.NotNull;
import java.time.Instant;
import java.util.UUID;
public record MessageSignature(Instant timestamp, long salt, byte[] signature) implements Writeable {
public static final UUID UNSIGNED_SENDER = new UUID(0,0);
public static final MessageSignature UNSIGNED = new MessageSignature(Instant.ofEpochMilli(0), 0, new byte[0]);
public MessageSignature(BinaryReader reader) {
this(Instant.ofEpochMilli(reader.readLong()), reader.readLong(), reader.readByteArray());
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeLong(timestamp.toEpochMilli());
writer.writeLong(salt);
writer.writeByteArray(signature);
}
}

View File

@ -24,6 +24,7 @@ import net.minestom.server.command.CommandSender;
import net.minestom.server.coordinate.Point;
import net.minestom.server.coordinate.Pos;
import net.minestom.server.coordinate.Vec;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.effects.Effects;
import net.minestom.server.entity.damage.DamageType;
import net.minestom.server.entity.fakeplayer.FakePlayer;
@ -672,7 +673,7 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
* @param message the message that the player will send
*/
public void chat(@NotNull String message) {
addPacketToQueue(new ClientChatMessagePacket(message, 0, 0, new byte[0], false));
addPacketToQueue(new ClientChatMessagePacket(message, MessageSignature.UNSIGNED, false));
}
@Override

View File

@ -1,13 +1,13 @@
package net.minestom.server.listener;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.event.ClickEvent;
import net.minestom.server.MinecraftServer;
import net.minestom.server.command.CommandManager;
import net.minestom.server.entity.Player;
import net.minestom.server.event.EventDispatcher;
import net.minestom.server.event.player.PlayerChatEvent;
import net.minestom.server.message.ChatPosition;
import net.minestom.server.message.MessageSender;
import net.minestom.server.message.Messenger;
import net.minestom.server.network.ConnectionManager;
import net.minestom.server.network.packet.client.play.ClientChatMessagePacket;
@ -58,20 +58,16 @@ public class ChatMessageListener {
final Collection<Player> recipients = playerChatEvent.getRecipients();
if (!recipients.isEmpty()) {
// delegate to the messenger to avoid sending messages we shouldn't be
Messenger.sendMessage(recipients, textObject, ChatPosition.CHAT, player.getUuid());
Messenger.sendSignedPlayerMessage(recipients, textObject, ChatPosition.CHAT,
new MessageSender(player.getUuid(), player.getDisplayName() != null ? player.getDisplayName() :
Component.text(player.getUsername()), player.getTeam() == null ?
null : player.getTeam().getTeamDisplayName()), packet.signature());
}
});
}
private static @NotNull Component buildDefaultChatMessage(@NotNull Player player, @NotNull String message) {
final String username = player.getUsername();
return Component.translatable("chat.type.text")
.args(Component.text(username)
.insertion(username)
.clickEvent(ClickEvent.suggestCommand("/msg " + username + " "))
.hoverEvent(player),
Component.text(message)
);
return Component.text(message);
}
}

View File

@ -0,0 +1,23 @@
package net.minestom.server.message;
import net.kyori.adventure.text.Component;
import net.minestom.server.crypto.MessageSignature;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.UUID;
public record MessageSender(UUID uuid, @NotNull Component displayName, @Nullable Component teamName) {
public static MessageSender forUnsigned(@NotNull Component displayName, @Nullable Component teamName) {
return new MessageSender(MessageSignature.UNSIGNED_SENDER, displayName, teamName);
}
public static MessageSender forUnsigned(@NotNull Component displayName) {
return new MessageSender(MessageSignature.UNSIGNED_SENDER, displayName, null);
}
public static MessageSender forSigned(@NotNull UUID uuid, @NotNull Component displayName) {
return new MessageSender(uuid, displayName, null);
}
}

View File

@ -2,7 +2,9 @@ package net.minestom.server.message;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.NamedTextColor;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.entity.Player;
import net.minestom.server.network.packet.server.play.PlayerChatMessagePacket;
import net.minestom.server.network.packet.server.play.SystemChatPacket;
import net.minestom.server.utils.PacketUtils;
import org.jetbrains.annotations.NotNull;
@ -15,6 +17,7 @@ import java.io.StringReader;
import java.util.Collection;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
/**
* Utility class to handle client chat settings.
@ -24,7 +27,6 @@ public final class Messenger {
* The message sent to the client if they send a chat message but it is rejected by the server.
*/
public static final Component CANNOT_SEND_MESSAGE = Component.translatable("chat.cannotSend", NamedTextColor.RED);
private static final UUID NO_SENDER = new UUID(0, 0);
private static final SystemChatPacket CANNOT_SEND_PACKET = new SystemChatPacket(CANNOT_SEND_MESSAGE, ChatPosition.SYSTEM_MESSAGE.getID());
private static final NBTCompound CHAT_REGISTRY;
@ -246,6 +248,7 @@ public final class Messenger {
* @param uuid the UUID of the sender, if any
* @return if the message was sent
*/
//fixme
public static boolean sendMessage(@NotNull Player player, @NotNull Component message, @NotNull ChatPosition position, @Nullable UUID uuid) {
if (getChatMessageType(player).accepts(position)) {
player.sendPacket(new SystemChatPacket(message, 1));
@ -257,15 +260,16 @@ public final class Messenger {
/**
* Sends a message to some players, respecting their chat settings.
*
* @param players the players
* @param recipients the players
* @param message the message
* @param position the position
* @param uuid the UUID of the sender, if any
*/
public static void sendMessage(@NotNull Collection<Player> players, @NotNull Component message,
@NotNull ChatPosition position, @Nullable UUID uuid) {
PacketUtils.sendGroupedPacket(players, new SystemChatPacket(message, 1),
player -> getChatMessageType(player).accepts(position));
public static void sendSignedPlayerMessage(@NotNull Collection<Player> recipients, @NotNull Component message,
@NotNull ChatPosition position, @NotNull MessageSender sender,
@NotNull MessageSignature signature) {
PacketUtils.sendGroupedPacket(recipients.stream().filter(x -> x.getSettings().getChatMessageType() == null ||
x.getSettings().getChatMessageType().accepts(position)).collect(Collectors.toList()),
PlayerChatMessagePacket.signed(message, position, sender, signature));
}
/**

View File

@ -1,13 +1,12 @@
package net.minestom.server.network.packet.client.play;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.network.packet.client.ClientPacket;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter;
import org.jetbrains.annotations.NotNull;
public record ClientChatMessagePacket(@NotNull String message,
long timestamp, long salt,
byte[] signature, boolean signed) implements ClientPacket {
public record ClientChatMessagePacket(@NotNull String message, MessageSignature signature, boolean signedPreview) implements ClientPacket {
public ClientChatMessagePacket {
if (message.length() > 256) {
throw new IllegalArgumentException("Message cannot be more than 256 characters long.");
@ -15,17 +14,13 @@ public record ClientChatMessagePacket(@NotNull String message,
}
public ClientChatMessagePacket(BinaryReader reader) {
this(reader.readSizedString(256),
reader.readLong(), reader.readLong(),
reader.readByteArray(), reader.readBoolean());
this(reader.readSizedString(256), new MessageSignature(reader), reader.readBoolean());
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeSizedString(message);
writer.writeLong(timestamp);
writer.writeLong(salt);
writer.writeByteArray(signature);
writer.writeBoolean(signed);
writer.write(signature);
writer.writeBoolean(signedPreview);
}
}

View File

@ -1,6 +1,9 @@
package net.minestom.server.network.packet.server.play;
import net.kyori.adventure.text.Component;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.message.ChatPosition;
import net.minestom.server.message.MessageSender;
import net.minestom.server.network.packet.server.ComponentHoldingServerPacket;
import net.minestom.server.network.packet.server.ServerPacket;
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
@ -20,28 +23,32 @@ import java.util.function.UnaryOperator;
public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullable Component unsignedContent,
int type, @NotNull UUID uuid,
@NotNull Component displayName, @Nullable Component teamDisplayName,
long timestamp, long salt,
byte[] signature) implements ComponentHoldingServerPacket {
@NotNull MessageSignature signature) implements ComponentHoldingServerPacket {
public PlayerChatMessagePacket(BinaryReader reader) {
this(reader.readComponent(), reader.readBoolean() ? reader.readComponent() : null,
reader.readVarInt(), reader.readUuid(),
reader.readComponent(), reader.readBoolean() ? reader.readComponent() : null,
reader.readLong(), reader.readLong(), reader.readByteArray());
this(reader.readComponent(), reader.readNullableComponent(), reader.readVarInt(), reader.readUuid(),
reader.readComponent(), reader.readNullableComponent(), new MessageSignature(reader));
}
public static PlayerChatMessagePacket unsigned(@NotNull Component message, ChatPosition type, @NotNull MessageSender sender) {
return new PlayerChatMessagePacket(message, null, type.getID(), MessageSignature.UNSIGNED_SENDER,
sender.displayName(), sender.teamName(), MessageSignature.UNSIGNED);
}
public static PlayerChatMessagePacket signed(@NotNull Component message, ChatPosition type, @NotNull MessageSender sender,
@NotNull MessageSignature signature) {
return new PlayerChatMessagePacket(message, null, type.getID(), sender.uuid(),
sender.displayName(), sender.teamName(), signature);
}
@Override
public void write(@NotNull BinaryWriter writer) {
writer.writeComponent(signedContent);
writer.writeBoolean(unsignedContent != null);
if (unsignedContent != null) writer.writeComponent(unsignedContent);
writer.writeNullableComponent(unsignedContent);
writer.writeVarInt(type);
writer.writeUuid(uuid);
writer.writeComponent(displayName);
writer.writeBoolean(teamDisplayName != null);
if (teamDisplayName != null) writer.writeComponent(teamDisplayName);
writer.writeLong(timestamp);
writer.writeLong(salt);
writer.writeByteArray(signature);
writer.writeNullableComponent(teamDisplayName);
writer.write(signature);
}
@Override
@ -57,6 +64,6 @@ public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullabl
@Override
public @NotNull ServerPacket copyWithOperator(@NotNull UnaryOperator<Component> operator) {
return new PlayerChatMessagePacket(signedContent, unsignedContent, type,
uuid, displayName, teamDisplayName, timestamp, salt, signature);
uuid, displayName, teamDisplayName, signature);
}
}