Move uuid into MessageSignature from MessageSender

This commit is contained in:
Noel Németh 2022-06-12 14:44:28 +02:00
parent 29c5d1d64b
commit fa9ab30410
7 changed files with 42 additions and 56 deletions

View File

@ -3,17 +3,27 @@ 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.Contract;
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 record MessageSignature(UUID signer, 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 static final MessageSignature UNSIGNED = new MessageSignature(UNSIGNED_SENDER, Instant.ofEpochMilli(0), 0, new byte[0]);
public MessageSignature(BinaryReader reader) {
this(Instant.ofEpochMilli(reader.readLong()), reader.readLong(), reader.readByteArray());
public MessageSignature(UUID sender, BinaryReader reader) {
this(sender, Instant.ofEpochMilli(reader.readLong()), reader.readLong(), reader.readByteArray());
}
@Contract("_ -> new")
public MessageSignature withSigner(UUID uuid) {
return new MessageSignature(uuid, timestamp, salt, signature);
}
public boolean unsigned() {
return signer == UNSIGNED_SENDER;
}
@Override

View File

@ -12,7 +12,6 @@ import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.UUID;
/**
* General purpose functional interface to verify signatures.<br>
@ -63,17 +62,16 @@ public interface SignatureValidator {
* <i>net.minecraft.client.player.LocalPlayer#signCommandArguments</i><br>
*
* @param validator validator acquired from {@link SignatureValidator#from(Player)}
* @param signer uuid of the player who signed this component
* @param signature signature data
* @param component the component that was signed
* @return true if the signature is valid
*/
static boolean validate(SignatureValidator validator, UUID signer, MessageSignature signature, Component component) {
static boolean validate(SignatureValidator validator, MessageSignature signature, Component component) {
final byte[] componentBytes = GsonComponentSerializer.gson().serialize(component).getBytes(StandardCharsets.UTF_8);
byte[] signerDetails = new byte[32+ componentBytes.length];
ByteBuffer bytebuffer = ByteBuffer.wrap(signerDetails).order(ByteOrder.BIG_ENDIAN);
bytebuffer.putLong(signature.salt());
bytebuffer.putLong(signer.getMostSignificantBits()).putLong(signer.getLeastSignificantBits());
bytebuffer.putLong(signature.signer().getMostSignificantBits()).putLong(signature.signer().getLeastSignificantBits());
bytebuffer.putLong(signature.timestamp().getEpochSecond());
bytebuffer.put(componentBytes);
return validator.validate(bytebuffer.array(), signature.signature());

View File

@ -669,8 +669,9 @@ public class Player extends LivingEntity implements CommandSender, Localizable,
if (type == MessageType.SYSTEM)
Messenger.sendSystemMessage(this, message, ChatPosition.SYSTEM_MESSAGE);
else
Messenger.sendMessage(Collections.singleton(this), PlayerChatMessagePacket.unsigned(message,
ChatPosition.CHAT, MessageSender.forUnsigned(Component.text("SYSTEM"))));
Messenger.sendMessage(List.of(this), PlayerChatMessagePacket.unsigned(message,
// TODO get name from source if possible
ChatPosition.CHAT, new MessageSender(Component.empty(), null)));
}
/**

View File

@ -44,7 +44,8 @@ public class ChatMessageListener {
final Collection<Player> players = CONNECTION_MANAGER.getOnlinePlayers();
final Component expectedMessage = Objects.requireNonNullElse(player.getLastPreviewedMessage(), Component.text(message));
PlayerChatEvent event = new PlayerChatEvent(player, players, message, packet.signature(), MessageSender.forSigned(player), expectedMessage);
PlayerChatEvent event = new PlayerChatEvent(player, players, message, packet.signature().withSigner(player.getUuid()),
MessageSender.from(player), expectedMessage);
// Call the event
EventDispatcher.callCancellable(event, () -> {
@ -57,8 +58,8 @@ public class ChatMessageListener {
if (formatFunction != null) {
// Let the event modify the message
if (event.getSender().unsigned()) {
// Event handler set unsigned sender, send message as unsigned -> players with
if (event.getSignature().unsigned()) {
// Event handler set message unsigned -> players with
// "Only Show Secure Chat" option enabled won't see this message
Messenger.sendMessage(event.getRecipients(), PlayerChatMessagePacket
.unsigned(formatFunction.apply(event), ChatPosition.CHAT, event.getSender()));
@ -71,7 +72,7 @@ public class ChatMessageListener {
}
} else {
// There is no way the message got modified, send it with the original signature
// TODO Should we handle poor design where the signature or sender uuid got altered?
// TODO Should we handle poor design where the signature got altered?
Messenger.sendMessage(event.getRecipients(), PlayerChatMessagePacket.signed(event.getMessage(),
ChatPosition.CHAT, event.getSender(), event.getSignature()));
}

View File

@ -1,43 +1,17 @@
package net.minestom.server.message;
import net.kyori.adventure.text.Component;
import net.minestom.server.crypto.MessageSignature;
import net.minestom.server.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Objects;
import java.util.UUID;
public record MessageSender(UUID uuid, @NotNull Component displayName, @Nullable Component teamName) {
public record MessageSender(@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);
}
public static MessageSender forSigned(Player player) {
return player.getTeam() == null ? forSigned(player.getUuid(), Objects.requireNonNullElse(player.getDisplayName(),
Component.text(player.getUsername()))) : new MessageSender(player.getUuid(),
Objects.requireNonNullElse(player.getDisplayName(), Component.text(player.getUsername())),
public static MessageSender from(Player player) {
return new MessageSender(Objects.requireNonNullElse(player.getDisplayName(),
Component.text(player.getUsername())), player.getTeam() == null ? null :
player.getTeam().getTeamDisplayName());
}
public static MessageSender forUnsigned(Player player) {
return player.getTeam() == null ? forUnsigned(Objects.requireNonNullElse(player.getDisplayName(),
Component.text(player.getUsername()))) : forUnsigned(
Objects.requireNonNullElse(player.getDisplayName(), Component.text(player.getUsername())),
player.getTeam().getTeamDisplayName());
}
public boolean unsigned() {
return MessageSignature.UNSIGNED_SENDER == uuid;
}
}

View File

@ -14,7 +14,7 @@ public record ClientChatMessagePacket(@NotNull String message, MessageSignature
}
public ClientChatMessagePacket(BinaryReader reader) {
this(reader.readSizedString(256), new MessageSignature(reader), reader.readBoolean());
this(reader.readSizedString(256), new MessageSignature(null, reader), reader.readBoolean());
}
@Override

View File

@ -20,23 +20,26 @@ import java.util.function.UnaryOperator;
/**
* Represents an outgoing chat message packet.
*/
public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullable Component unsignedContent,
int type, @NotNull UUID uuid,
public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullable Component unsignedContent, int type,
@NotNull Component displayName, @Nullable Component teamDisplayName,
@NotNull MessageSignature signature) implements ComponentHoldingServerPacket {
public PlayerChatMessagePacket(BinaryReader reader) {
this(reader.readComponent(), reader.readNullableComponent(), reader.readVarInt(), reader.readUuid(),
reader.readComponent(), reader.readNullableComponent(), new MessageSignature(reader));
public static PlayerChatMessagePacket read(BinaryReader reader) {
final Component signed = reader.readComponent();
final Component unsigned = reader.readNullableComponent();
final int type = reader.readVarInt();
final UUID sender = reader.readUuid();
return new PlayerChatMessagePacket(signed, unsigned, type, reader.readComponent(),
reader.readNullableComponent(), new MessageSignature(sender, reader));
}
public static PlayerChatMessagePacket unsigned(@NotNull Component message, ChatPosition type, @NotNull MessageSender sender) {
return new PlayerChatMessagePacket(message, null, type.getID(), MessageSignature.UNSIGNED_SENDER,
return new PlayerChatMessagePacket(message, null, type.getID(),
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(),
return new PlayerChatMessagePacket(message, null, type.getID(),
sender.displayName(), sender.teamName(), signature);
}
@ -44,7 +47,7 @@ public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullabl
@NotNull Component unsignedContent,
ChatPosition type, @NotNull MessageSender sender,
@NotNull MessageSignature signature) {
return new PlayerChatMessagePacket(message, unsignedContent, type.getID(), sender.uuid(),
return new PlayerChatMessagePacket(message, unsignedContent, type.getID(),
sender.displayName(), sender.teamName(), signature);
}
@ -53,7 +56,7 @@ public record PlayerChatMessagePacket(@NotNull Component signedContent, @Nullabl
writer.writeComponent(signedContent);
writer.writeNullableComponent(unsignedContent);
writer.writeVarInt(type);
writer.writeUuid(uuid);
writer.writeUuid(signature.signer());
writer.writeComponent(displayName);
writer.writeNullableComponent(teamDisplayName);
writer.write(signature);
@ -71,7 +74,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, signature);
return new PlayerChatMessagePacket(signedContent, unsignedContent, type, displayName, teamDisplayName, signature);
}
}