Skip to content

Commit

Permalink
feat: Add packet listeners to convert Player Chat to System Chat and …
Browse files Browse the repository at this point in the history
…block Chat Header/Chat Session packets
  • Loading branch information
MemencioPerez committed May 20, 2024
1 parent 90cff1a commit 928a186
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@
import com.velocitypowered.proxy.VelocityServer;
import io.github._4drian3d.unsignedvelocity.configuration.Configuration;
import io.github._4drian3d.unsignedvelocity.listener.LoadablePacketListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.chat.ChatListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.chat.ChatHeaderListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.chat.ChatSessionListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.chat.ClientChatListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.chat.ServerChatListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.command.CommandListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.login.LoginListener;
import io.github._4drian3d.unsignedvelocity.listener.packet.data.ServerDataListener;
Expand Down Expand Up @@ -82,7 +85,10 @@ public void onProxyInitialize(ProxyInitializeEvent event) {
Stream.of(
LoginListener.class,
CommandListener.class,
ChatListener.class,
ClientChatListener.class,
ServerChatListener.class,
ChatHeaderListener.class,
ChatSessionListener.class,
ServerDataListener.class,
ServerResponseListener.class
).map(injector::getInstance)
Expand All @@ -99,6 +105,14 @@ public void onProxyInitialize(ProxyInitializeEvent event) {
"<#6892bd>UnSigned <dark_gray>|</dark_gray> Commands: <aqua>{}</aqua> <dark_gray>|</dark_gray> Chat: <aqua>{}"),
configuration.removeSignedCommandInformation(),
configuration.applyChatMessages());
logger.info(miniMessage().deserialize(
"<#6892bd>Convert Player Chat Messages to System Chat Messages: <aqua>{}</aqua>"), configuration.convertPlayerChatToSystemChat(),
configuration.blockChatHeaderPackets(),
configuration.blockChatSessionPackets());
logger.info(miniMessage().deserialize(
"<#6892bd>Block <dark_gray>|</dark_gray> <#6892bd>Chat Header Packets: <aqua>{}</aqua> <dark_gray>|</dark_gray> <#6892bd>Chat Session Packets: <aqua>{}</aqua>"),
configuration.blockChatHeaderPackets(),
configuration.blockChatSessionPackets());
logger.info(miniMessage().deserialize(
"<#6892bd>Secure Chat Data: <aqua>{} <dark_gray>|</dark_gray> <#6892bd>Safe Server Status: <aqua>{}"), configuration.sendSecureChatData(), configuration.sendSafeServerStatus());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ public interface Configuration {

boolean applyChatMessages();

boolean convertPlayerChatToSystemChat();

boolean blockChatHeaderPackets();

boolean blockChatSessionPackets();

boolean sendSecureChatData();

boolean sendSafeServerStatus();


static Configuration loadConfig(final Path path) throws IOException {
final Path configPath = loadFiles(path);
final HoconConfigurationLoader loader = HoconConfigurationLoader.builder()
Expand All @@ -33,6 +40,12 @@ static Configuration loadConfig(final Path path) throws IOException {
.getBoolean(false);
final boolean applyChatMessages = loaded.node("apply-chat-messages")
.getBoolean(true);
final boolean convertPlayerChatToSystemChat = loaded.node("convert-player-chat-to-system-chat")
.getBoolean(false);
final boolean blockChatHeaderPackets = loaded.node("block-chat-header-packets")
.getBoolean(false);
final boolean blockChatSessionPackets = loaded.node("block-chat-session-packets")
.getBoolean(false);
final boolean sendSecureChatData = loaded.node("send-secure-chat-data")
.getBoolean(false);
final boolean sendSafeServerStatus = loaded.node("send-safe-server-status")
Expand All @@ -54,6 +67,21 @@ public boolean applyChatMessages() {
return applyChatMessages;
}

@Override
public boolean convertPlayerChatToSystemChat() {
return convertPlayerChatToSystemChat;
}

@Override
public boolean blockChatHeaderPackets() {
return blockChatHeaderPackets;
}

@Override
public boolean blockChatSessionPackets() {
return blockChatSessionPackets;
}

@Override
public boolean sendSecureChatData() {
return sendSecureChatData;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github._4drian3d.unsignedvelocity.listener.packet.chat;

import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.google.inject.Inject;
import io.github._4drian3d.unsignedvelocity.UnSignedVelocity;
import io.github._4drian3d.unsignedvelocity.listener.LoadablePacketListener;

public final class ChatHeaderListener extends PacketListenerAbstract implements LoadablePacketListener {
private final UnSignedVelocity plugin;

@Inject
public ChatHeaderListener(UnSignedVelocity plugin) {
super(PacketListenerPriority.LOWEST);
this.plugin = plugin;
}

@Override
public boolean canBeLoaded() {
return plugin.getConfiguration().blockChatHeaderPackets();
}

@Override
public void onPacketReceive(final PacketReceiveEvent event) {
final PacketTypeCommon packetType = event.getPacketType();
if (packetType == PacketType.Play.Client.CHAT_SESSION_UPDATE) {
event.setCancelled(true);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package io.github._4drian3d.unsignedvelocity.listener.packet.chat;

import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.google.inject.Inject;
import io.github._4drian3d.unsignedvelocity.UnSignedVelocity;
import io.github._4drian3d.unsignedvelocity.listener.LoadablePacketListener;

public final class ChatSessionListener extends PacketListenerAbstract implements LoadablePacketListener {
private final UnSignedVelocity plugin;

@Inject
public ChatSessionListener(UnSignedVelocity plugin) {
super(PacketListenerPriority.LOWEST);
this.plugin = plugin;
}

@Override
public boolean canBeLoaded() {
return plugin.getConfiguration().blockChatSessionPackets();
}

@Override
public void onPacketReceive(final PacketReceiveEvent event) {
final PacketTypeCommon packetType = event.getPacketType();
if (packetType == PacketType.Play.Client.CHAT_SESSION_UPDATE) {
event.setCancelled(true);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@

import java.time.Instant;

public final class ChatListener extends PacketListenerAbstract implements LoadablePacketListener {
public final class ClientChatListener extends PacketListenerAbstract implements LoadablePacketListener {
private final UnSignedVelocity plugin;

@Inject
public ChatListener(UnSignedVelocity plugin) {
public ClientChatListener(UnSignedVelocity plugin) {
super(PacketListenerPriority.LOWEST);
this.plugin = plugin;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package io.github._4drian3d.unsignedvelocity.listener.packet.chat;

import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketListenerPriority;
import com.github.retrooper.packetevents.event.PacketSendEvent;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_1;
import com.github.retrooper.packetevents.protocol.chat.message.ChatMessage_v1_19_3;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerChatMessage;
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerSystemChatMessage;
import com.google.inject.Inject;
import io.github._4drian3d.unsignedvelocity.UnSignedVelocity;
import io.github._4drian3d.unsignedvelocity.listener.LoadablePacketListener;
import net.kyori.adventure.text.Component;
import org.jetbrains.annotations.Nullable;

import java.util.Optional;

public final class ServerChatListener extends PacketListenerAbstract implements LoadablePacketListener {
private final UnSignedVelocity plugin;

@Inject
public ServerChatListener(UnSignedVelocity plugin) {
super(PacketListenerPriority.LOWEST);
this.plugin = plugin;
}

@Override
public boolean canBeLoaded() {
return plugin.getConfiguration().convertPlayerChatToSystemChat();
}

@Override
public void onPacketSend(final PacketSendEvent event) {
final PacketTypeCommon packetType = event.getPacketType();
if (packetType == PacketType.Play.Server.CHAT_MESSAGE) {
if (event.getUser().getClientVersion().isOlderThan(ClientVersion.V_1_19)) {
return;
}
Component messageContent = getComponentFromChatPacket(event);
final WrapperPlayServerSystemChatMessage newPacket = new WrapperPlayServerSystemChatMessage(false, messageContent);
event.getUser().sendPacketSilently(newPacket);
event.setCancelled(true);
}
}

private static @Nullable Component getComponentFromChatPacket(PacketSendEvent event) {
final WrapperPlayServerChatMessage packet = new WrapperPlayServerChatMessage(event);
ChatMessage chatMessage = packet.getMessage();
Component messageContent = chatMessage.getChatContent();
if (chatMessage instanceof ChatMessage_v1_19) {
messageContent = ((ChatMessage_v1_19) chatMessage).getUnsignedChatContent();
} else if (chatMessage instanceof ChatMessage_v1_19_1) {
messageContent = ((ChatMessage_v1_19_1) chatMessage).getUnsignedChatContent();
} else if (chatMessage instanceof ChatMessage_v1_19_3) {
Optional<Component> unsignedChatContent = ((ChatMessage_v1_19_3) chatMessage).getUnsignedChatContent();
if (unsignedChatContent.isPresent()) {
messageContent = unsignedChatContent.get();
}
}
return messageContent;
}
}
21 changes: 17 additions & 4 deletions src/main/resources/config.conf
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,30 @@

# Removes the player's signed key information,
# so Velocity and plugins will consider this player as UnSigned.
# This only affects players with versions between 1.19 and 1.19.2.
remove-signed-key-on-join = true

# Allows cancellation and modification of commands for players with version 1.19.1 or higher.
# This option may have incompatibilities with plugins that handle command packets on Velocity,
# if you have any problems, first contact UnSignedVelocity support.
remove-signed-command-information = true

# Allows cancellation and modification of chat messages for players with version 1.19.1 or higher.
# This option may have incompatibilities with plugins that handle chat packets on Velocity,
# if you have any problems, first contact UnSignedVelocity support.
apply-chat-messages = true
# Cancel any Server Player Chat Message and convert it to a Server System Chat Message,
# to avoid signature check and hide the red warning sign that comes with unsigned chat messages for Vanilla clients.
# This option is required if you want to use the "Send Secure Chat Data" option.
convert-player-chat-to-system-chat = false

# Blocks any Player Chat Header packet coming from a backend server.
# This option is required if you want to use the "Send Secure Chat Data" option.
block-chat-header-packets = false

# Blocks any Player Chat Session packet coming from the client,
# to avoid transmitting Signed Key information for players with version 1.19.3 or higher
block-chat-session-packets = false

# This will send information to the client about whether the proxy or server has secure chat enabled.
# Not tested for functionality with pirate clients.
send-secure-chat-data = false

# This will send information to the client about whether the proxy or server has secure chat enabled.
# Not tested for functionality with pirate clients.
Expand Down

0 comments on commit 928a186

Please sign in to comment.