diff --git a/common/src/main/java/net/draycia/carbon/common/listeners/MessagePacketHandler.java b/common/src/main/java/net/draycia/carbon/common/listeners/MessagePacketHandler.java index 7012a432c..768ac6d90 100644 --- a/common/src/main/java/net/draycia/carbon/common/listeners/MessagePacketHandler.java +++ b/common/src/main/java/net/draycia/carbon/common/listeners/MessagePacketHandler.java @@ -60,7 +60,7 @@ public MessagePacketHandler( final Component networkMessage = e.renderFor(sender); return new ChatMessagePacket(serverId, sender.uuid(), - event.chatChannel().key(), sender.username(), networkMessage); + event.chatChannel().key(), sender.username(), networkMessage, event.signedMessage()); }); }); } diff --git a/common/src/main/java/net/draycia/carbon/common/messaging/CarbonChatPacketHandler.java b/common/src/main/java/net/draycia/carbon/common/messaging/CarbonChatPacketHandler.java index 966999915..01fe44908 100644 --- a/common/src/main/java/net/draycia/carbon/common/messaging/CarbonChatPacketHandler.java +++ b/common/src/main/java/net/draycia/carbon/common/messaging/CarbonChatPacketHandler.java @@ -43,6 +43,7 @@ import net.draycia.carbon.common.users.PartyInvites; import net.draycia.carbon.common.users.UserManagerInternal; import net.kyori.adventure.audience.Audience; +import net.kyori.adventure.chat.ChatType; import net.kyori.adventure.text.Component; import ninja.egg82.messenger.handler.AbstractMessagingHandler; import ninja.egg82.messenger.packets.Packet; @@ -129,7 +130,9 @@ private boolean handleMessagePacket(final ChatMessagePacket messagePacket) { final List renderers = new ArrayList<>(); final List recipients = channel.recipients(sender); - final CarbonChatEventImpl chatEvent = new CarbonChatEventImpl(sender, messagePacket.message(), recipients, renderers, channel, null, false); + + final CarbonChatEventImpl chatEvent = new CarbonChatEventImpl(sender, messagePacket.message(), recipients, renderers, + channel, messagePacket.signedMessage(), false); this.events.emit(chatEvent); for (final Audience recipient : recipients) { @@ -138,7 +141,11 @@ private boolean handleMessagePacket(final ChatMessagePacket messagePacket) { continue; } - recipient.sendMessage(chatEvent.renderFor(recipient)); + if (messagePacket.signedMessage() != null) { + recipient.sendMessage(messagePacket.signedMessage(), ChatType.CHAT.bind(chatEvent.renderFor(recipient))); + } else { + recipient.sendMessage(chatEvent.renderFor(recipient)); + } } this.server.console().sendMessage(Component.text("[Cross-Server] ").append(chatEvent.message())); diff --git a/common/src/main/java/net/draycia/carbon/common/messaging/SignedMessageCarbon.java b/common/src/main/java/net/draycia/carbon/common/messaging/SignedMessageCarbon.java new file mode 100644 index 000000000..5ef0cc619 --- /dev/null +++ b/common/src/main/java/net/draycia/carbon/common/messaging/SignedMessageCarbon.java @@ -0,0 +1,30 @@ +/* + * CarbonChat + * + * Copyright (c) 2024 Josua Parks (Vicarious) + * Contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package net.draycia.carbon.common.messaging; + +import java.time.Instant; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.identity.Identity; +import net.kyori.adventure.text.Component; +import org.jetbrains.annotations.Nullable; + +public record SignedMessageCarbon(Instant timestamp, long salt, Component unsignedContent, String message, Identity identity, @Nullable Signature signature) implements SignedMessage { + +} diff --git a/common/src/main/java/net/draycia/carbon/common/messaging/packets/CarbonPacket.java b/common/src/main/java/net/draycia/carbon/common/messaging/packets/CarbonPacket.java index 501ab0640..fa0ddfe87 100644 --- a/common/src/main/java/net/draycia/carbon/common/messaging/packets/CarbonPacket.java +++ b/common/src/main/java/net/draycia/carbon/common/messaging/packets/CarbonPacket.java @@ -20,11 +20,15 @@ package net.draycia.carbon.common.messaging.packets; import io.netty.buffer.ByteBuf; +import java.time.Instant; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.function.BiConsumer; import java.util.function.Function; +import net.draycia.carbon.common.messaging.SignedMessageCarbon; +import net.kyori.adventure.chat.SignedMessage; +import net.kyori.adventure.identity.Identity; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.serializer.gson.GsonComponentSerializer; @@ -95,4 +99,42 @@ protected final > E readEnum(final ByteBuf buf, final Class return cls.getEnumConstants()[this.readVarInt(buf)]; } + protected final SignedMessage readSignedMessage(final @NotNull ByteBuf buffer) { + final Instant timestamp = Instant.ofEpochMilli(buffer.readLong()); + final long salt = buffer.readLong(); + final Component unsignedContent = this.readComponent(buffer); + final String msg = this.readString(buffer); + final Identity identity = Identity.identity(this.readUUID(buffer)); + final SignedMessage.Signature signature; + + if (buffer.readableBytes() > 0) { + signature = this.readSignature(buffer); + } else { + signature = null; + } + + return new SignedMessageCarbon(timestamp, salt, unsignedContent, msg, identity, signature); + } + + protected final void writeSignedMessage(final @NotNull SignedMessage signedMessage, final @NotNull ByteBuf buffer) { + buffer.writeLong(signedMessage.timestamp().getEpochSecond()); + buffer.writeLong(signedMessage.salt()); + this.writeComponent(signedMessage.unsignedContent(), buffer); + this.writeString(signedMessage.message(), buffer); + this.writeUUID(signedMessage.identity().uuid(), buffer); + + if (signedMessage.signature() != null) { + this.writeSignature(signedMessage.signature(), buffer); + } + } + + protected final SignedMessage.Signature readSignature(final @NotNull ByteBuf buffer) { + return SignedMessage.signature(buffer.readBytes(buffer.readByte()).array()); + } + + protected final void writeSignature(final @NotNull SignedMessage.Signature signature, final @NotNull ByteBuf buffer) { + buffer.writeByte(signature.bytes().length); + buffer.writeBytes(signature.bytes()); + } + } diff --git a/common/src/main/java/net/draycia/carbon/common/messaging/packets/ChatMessagePacket.java b/common/src/main/java/net/draycia/carbon/common/messaging/packets/ChatMessagePacket.java index 03b2ee2b3..b3cf7e1df 100644 --- a/common/src/main/java/net/draycia/carbon/common/messaging/packets/ChatMessagePacket.java +++ b/common/src/main/java/net/draycia/carbon/common/messaging/packets/ChatMessagePacket.java @@ -21,10 +21,12 @@ import io.netty.buffer.ByteBuf; import java.util.UUID; +import net.kyori.adventure.chat.SignedMessage; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.Component; import ninja.egg82.messenger.utils.UUIDUtil; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public final class ChatMessagePacket extends CarbonPacket { @@ -34,6 +36,7 @@ public final class ChatMessagePacket extends CarbonPacket { private Key channelKey; private String username; private Component message; + private @Nullable SignedMessage signedMessage; public UUID userId() { return this.userId; @@ -55,6 +58,10 @@ public Component message() { return this.message; } + public @Nullable SignedMessage signedMessage() { + return this.signedMessage; + } + public ChatMessagePacket(final @NotNull UUID sender, final @NotNull ByteBuf data) { super(sender); this.read(data); @@ -69,29 +76,40 @@ public ChatMessagePacket( final UUID userId, final Key channelKey, final String username, - final Component message + final Component message, + final @Nullable SignedMessage signedMessage ) { super(serverId); this.userId = userId; this.channelKey = channelKey; this.username = username; this.message = message; + this.signedMessage = signedMessage; } @Override - public void read(final io.netty.buffer.@NotNull ByteBuf buffer) { + public void read(final @NotNull ByteBuf buffer) { this.userId = this.readUUID(buffer); this.channelKey = this.readKey(buffer); this.username = this.readString(buffer); this.message = this.readComponent(buffer); + + if (buffer.readableBytes() > 0) { + this.signedMessage = this.readSignedMessage(buffer); + } else { + this.signedMessage = null; + } } @Override - public void write(final io.netty.buffer.@NotNull ByteBuf buffer) { + public void write(final @NotNull ByteBuf buffer) { this.writeUUID(this.userId, buffer); this.writeKey(this.channelKey, buffer); this.writeString(this.username, buffer); this.writeComponent(this.message, buffer); + if (this.signedMessage != null) { + this.writeSignedMessage(this.signedMessage, buffer); + } } }