From 2254df21fda2f7404efdff0c938c10b1a3a4ec45 Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Mon, 1 Jun 2020 14:38:29 +0200 Subject: [PATCH 1/7] Add Emoji event This is received from the client when they are trying to display an emoji, this comes in to the server, gets processed, and the server sends back the Emote Bubble packet to the clients. --- CHANGELOG.md | 2 +- TShockAPI/GetDataHandlers.cs | 46 ++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 121cb25a..9860f9d5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large. ## Upcoming Changes -* Your change goes here! +* Add Emoji event to GetDataHandler. This packet is received when a player tries to display an emote. ## TShock 4.4.0 (Pre-release 10) * Fix all rope coils. (@Olink) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index b5c9bbb0..c9e9608e 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -151,6 +151,7 @@ namespace TShockAPI { PacketTypes.CrystalInvasionStart, HandleOldOnesArmy }, { PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 }, { PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 }, + { PacketTypes.Emoji, HandleEmoji }, { PacketTypes.FishOutNPC, HandleFishOutNPC }, { PacketTypes.FoodPlatterTryPlacing, HandleFoodPlatterTryPlacing }, { PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker } @@ -1866,6 +1867,40 @@ namespace TShockAPI return args.Handled; } + /// + /// For use in an Emoji event. + /// + public class EmojiEventArgs : GetDataHandledEventArgs + { + /// + /// The player index in the packet, who sends the emoji. + /// + public byte PlayerIndex { get; set; } + /// + /// The ID of the emoji, that is being received. + /// + public byte EmojiID { get; set; } + } + /// + /// Called when a player sends an emoji. + /// + public static HandlerList Emoji = new HandlerList(); + private static bool OnEmoji(TSPlayer player, MemoryStream data, byte playerIndex, byte emojiID) + { + if (Emoji == null) + return false; + + var args = new EmojiEventArgs + { + Player = player, + Data = data, + PlayerIndex = playerIndex, + EmojiID = emojiID + }; + Emoji.Invoke(null, args); + return args.Handled; + } + /// /// For use in a FishOutNPC event. /// @@ -3671,6 +3706,17 @@ namespace TShockAPI return false; } + private static bool HandleEmoji(GetDataHandlerArgs args) + { + byte playerIndex = args.Data.ReadInt8(); + byte emojiID = args.Data.ReadInt8(); + + if (OnEmoji(args.Player, args.Data, playerIndex, emojiID)) + return true; + + return false; + } + private static bool HandleFishOutNPC(GetDataHandlerArgs args) { ushort tileX = args.Data.ReadUInt16(); From f538ceb79371776afa386e9bc7648366f16b897c Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Mon, 1 Jun 2020 15:24:02 +0200 Subject: [PATCH 2/7] Adding EmojiHandler to handle an exploit. Adding sendemoji permission and checks. I know, this is not something important, but I'm going through the new packets one by one and adding events developers can work with, patching exploits, and thought this could be a core permission. --- CHANGELOG.md | 3 ++- TShockAPI/DB/GroupManager.cs | 3 ++- TShockAPI/Handlers/EmojiHandler.cs | 31 ++++++++++++++++++++++++++++++ TShockAPI/Permissions.cs | 3 +++ 4 files changed, 38 insertions(+), 2 deletions(-) create mode 100644 TShockAPI/Handlers/EmojiHandler.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9860f9d5..67a650ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,8 @@ This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large. ## Upcoming Changes -* Add Emoji event to GetDataHandler. This packet is received when a player tries to display an emote. +* Add Emoji event to GetDataHandler. This packet is received when a player tries to display an emote. + * Adding EmojiHandler to handle an exploit. Adding `tshock.sendemoji` permission and checks. Added this permission to guest group by default. ## TShock 4.4.0 (Pre-release 10) * Fix all rope coils. (@Olink) diff --git a/TShockAPI/DB/GroupManager.cs b/TShockAPI/DB/GroupManager.cs index 584ad374..3cff37a1 100644 --- a/TShockAPI/DB/GroupManager.cs +++ b/TShockAPI/DB/GroupManager.cs @@ -65,7 +65,8 @@ namespace TShockAPI.DB Permissions.canpartychat, Permissions.cantalkinthird, Permissions.canchat, - Permissions.synclocalarea)); + Permissions.synclocalarea, + Permissions.sendemoji)); AddDefaultGroup("default", "guest", string.Join(",", diff --git a/TShockAPI/Handlers/EmojiHandler.cs b/TShockAPI/Handlers/EmojiHandler.cs new file mode 100644 index 00000000..39570d80 --- /dev/null +++ b/TShockAPI/Handlers/EmojiHandler.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TShockAPI.Handlers +{ + /// + /// Handles an exploit and checks for permissions. + /// + public class EmojiHandler + { + public void OnEmoji(object sender, GetDataHandlers.EmojiEventArgs args) + { + if (args.PlayerIndex != args.Player.Index) + { + TShock.Log.ConsoleError($"EmojiHandler: Packet is spoofing to be player ID {args.PlayerIndex}! - From [{args.Player.Index}]{args.Player.Name}"); + args.Handled = true; + return; + } + + if (!args.Player.HasPermission(Permissions.sendemoji)) + { + args.Player.SendErrorMessage("You have no permission to send emotes!"); + args.Handled = true; + return; + } + } + } +} diff --git a/TShockAPI/Permissions.cs b/TShockAPI/Permissions.cs index baf21a73..4b196380 100644 --- a/TShockAPI/Permissions.cs +++ b/TShockAPI/Permissions.cs @@ -468,6 +468,9 @@ namespace TShockAPI [Description("Player can resync themselves with server state.")] public static readonly string synclocalarea = "tshock.synclocalarea"; + + [Description("Player can send emotes.")] + public static readonly string sendemoji = "tshock.sendemoji"; #endregion /// /// Lists all commands associated with a given permission From c94d15e63451bac4da16ba8d34a55bf6a603a45b Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Mon, 1 Jun 2020 15:31:45 +0200 Subject: [PATCH 3/7] Commit EmojiHandler.cs and register OnEmoji hook. --- TShockAPI/Bouncer.cs | 4 ++++ TShockAPI/Handlers/EmojiHandler.cs | 2 +- TShockAPI/TShockAPI.csproj | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 395bfddd..5bd42ffd 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -37,6 +37,7 @@ namespace TShockAPI internal sealed class Bouncer { internal Handlers.SendTileSquareHandler STSHandler { get; set; } + internal Handlers.EmojiHandler EmojiHandler { get; set; } /// Constructor call initializes Bouncer and related functionality. /// A new Bouncer. @@ -45,6 +46,9 @@ namespace TShockAPI STSHandler = new Handlers.SendTileSquareHandler(); GetDataHandlers.SendTileSquare += STSHandler.OnReceiveSendTileSquare; + EmojiHandler = new Handlers.EmojiHandler(); + GetDataHandlers.Emoji += EmojiHandler.OnEmoji; + // Setup hooks GetDataHandlers.GetSection += OnGetSection; GetDataHandlers.PlayerUpdate += OnPlayerUpdate; diff --git a/TShockAPI/Handlers/EmojiHandler.cs b/TShockAPI/Handlers/EmojiHandler.cs index 39570d80..8606884d 100644 --- a/TShockAPI/Handlers/EmojiHandler.cs +++ b/TShockAPI/Handlers/EmojiHandler.cs @@ -15,7 +15,7 @@ namespace TShockAPI.Handlers { if (args.PlayerIndex != args.Player.Index) { - TShock.Log.ConsoleError($"EmojiHandler: Packet is spoofing to be player ID {args.PlayerIndex}! - From [{args.Player.Index}]{args.Player.Name}"); + TShock.Log.ConsoleError($"EmojiHandler: Packet is spoofing to be player ID {args.PlayerIndex}! - From [{args.Player.Index}] {args.Player.Name}"); args.Handled = true; return; } diff --git a/TShockAPI/TShockAPI.csproj b/TShockAPI/TShockAPI.csproj index ea6f4f48..3647b476 100644 --- a/TShockAPI/TShockAPI.csproj +++ b/TShockAPI/TShockAPI.csproj @@ -88,6 +88,7 @@ + From ce5ee0d6230fa96954d317bf9ef3f74e5d746525 Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Mon, 1 Jun 2020 17:02:27 +0200 Subject: [PATCH 4/7] Add HandleSyncCavernMonsterType This packet is never sent from the client to the server in a normal scenario. Although with modded clients, a packet can be sent to modify the cavernMonsterType of the server world and have the world spawn defined NPC types. Can be used to have the server randomly spawn bosses on players in caverns. Is it okay to have this simple handling in GetDataHandlers? A seperate class felt like an overkill. Moved the HandleSyncRevengeMarker packet handler to it's "correct" position, so I won't have merge issues between my last PR. As I've mentioned there, we have the Packets in their numerical order. --- CHANGELOG.md | 2 +- TShockAPI/GetDataHandlers.cs | 33 ++++++++++++++++++++------------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 121cb25a..49ffe302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ This is the rolling changelog for TShock for Terraria. Use past tense when adding new entries; sign your name off when you add or change something. This should primarily be things like user changes, not necessarily codebase changes unless it's really relevant or large. ## Upcoming Changes -* Your change goes here! +* Handling SyncCavernMonsterType packet to prevent an exploit where players could modify the server's cavern monster types and make the server spawn any NPCs - including bosses - onto other players. ## TShock 4.4.0 (Pre-release 10) * Fix all rope coils. (@Olink) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index b5c9bbb0..f2083f90 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -151,9 +151,10 @@ namespace TShockAPI { PacketTypes.CrystalInvasionStart, HandleOldOnesArmy }, { PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 }, { PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 }, + { PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker }, { PacketTypes.FishOutNPC, HandleFishOutNPC }, { PacketTypes.FoodPlatterTryPlacing, HandleFoodPlatterTryPlacing }, - { PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker } + { PacketTypes.SyncCavernMonsterType, HandleSyncCavernMonsterType } }; } @@ -3671,6 +3672,21 @@ namespace TShockAPI return false; } + private static bool HandleSyncRevengeMarker(GetDataHandlerArgs args) + { + int uniqueID = args.Data.ReadInt32(); + Vector2 location = args.Data.ReadVector2(); + int netId = args.Data.ReadInt32(); + float npcHpPercent = args.Data.ReadSingle(); + int npcTypeAgainstDiscouragement = args.Data.ReadInt32(); //tfw the argument is Type Against Discouragement + int npcAiStyleAgainstDiscouragement = args.Data.ReadInt32(); //see ^ + int coinsValue = args.Data.ReadInt32(); + float baseValue = args.Data.ReadSingle(); + bool spawnedFromStatus = args.Data.ReadBoolean(); + + return false; + } + private static bool HandleFishOutNPC(GetDataHandlerArgs args) { ushort tileX = args.Data.ReadUInt16(); @@ -3697,19 +3713,10 @@ namespace TShockAPI return false; } - private static bool HandleSyncRevengeMarker(GetDataHandlerArgs args) + private static bool HandleSyncCavernMonsterType(GetDataHandlerArgs args) { - int uniqueID = args.Data.ReadInt32(); - Vector2 location = args.Data.ReadVector2(); - int netId = args.Data.ReadInt32(); - float npcHpPercent = args.Data.ReadSingle(); - int npcTypeAgainstDiscouragement = args.Data.ReadInt32(); //tfw the argument is Type Against Discouragement - int npcAiStyleAgainstDiscouragement = args.Data.ReadInt32(); //see ^ - int coinsValue = args.Data.ReadInt32(); - float baseValue = args.Data.ReadSingle(); - bool spawnedFromStatus = args.Data.ReadBoolean(); - - return false; + TShock.Log.ConsoleDebug($"HandleSyncCavernMonsterType: Player is trying to modify NPC cavernMonsterType; this is a crafted packet! - From {args.Player.Name}"); + return true; } public enum EditAction From acdbfecaf130a41d2b1ff2a5f53e1ea4e0d55b05 Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Tue, 2 Jun 2020 11:20:04 +0200 Subject: [PATCH 5/7] EmojiHandler - Adding requested PR changes. Changing debug message. Fix wordings. --- TShockAPI/Bouncer.cs | 2 +- TShockAPI/Handlers/EmojiHandler.cs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/TShockAPI/Bouncer.cs b/TShockAPI/Bouncer.cs index 5bd42ffd..534d670b 100644 --- a/TShockAPI/Bouncer.cs +++ b/TShockAPI/Bouncer.cs @@ -47,7 +47,7 @@ namespace TShockAPI GetDataHandlers.SendTileSquare += STSHandler.OnReceiveSendTileSquare; EmojiHandler = new Handlers.EmojiHandler(); - GetDataHandlers.Emoji += EmojiHandler.OnEmoji; + GetDataHandlers.Emoji += EmojiHandler.OnReceiveEmoji; // Setup hooks GetDataHandlers.GetSection += OnGetSection; diff --git a/TShockAPI/Handlers/EmojiHandler.cs b/TShockAPI/Handlers/EmojiHandler.cs index 8606884d..b21cd53e 100644 --- a/TShockAPI/Handlers/EmojiHandler.cs +++ b/TShockAPI/Handlers/EmojiHandler.cs @@ -7,22 +7,22 @@ using System.Threading.Tasks; namespace TShockAPI.Handlers { /// - /// Handles an exploit and checks for permissions. + /// Handles emoji packets and checks for validity and permissions /// public class EmojiHandler { - public void OnEmoji(object sender, GetDataHandlers.EmojiEventArgs args) + public void OnReceiveEmoji(object sender, GetDataHandlers.EmojiEventArgs args) { if (args.PlayerIndex != args.Player.Index) { - TShock.Log.ConsoleError($"EmojiHandler: Packet is spoofing to be player ID {args.PlayerIndex}! - From [{args.Player.Index}] {args.Player.Name}"); + TShock.Log.ConsoleError($"EmojiHandler: Emoji packet rejected for ID spoofing. Expected {args.Player.Index}, received {args.PlayerIndex} from {args.Player.Name}."); args.Handled = true; return; } if (!args.Player.HasPermission(Permissions.sendemoji)) { - args.Player.SendErrorMessage("You have no permission to send emotes!"); + args.Player.SendErrorMessage("You do not have permission to send emotes!"); args.Handled = true; return; } From cd58d79322aa018e90da735bebe465b8ead23141 Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Tue, 2 Jun 2020 11:34:10 +0200 Subject: [PATCH 6/7] Kick player on attempting cavern npc type modification. --- TShockAPI/GetDataHandlers.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index f2083f90..f86104d9 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -3715,6 +3715,7 @@ namespace TShockAPI private static bool HandleSyncCavernMonsterType(GetDataHandlerArgs args) { + args.Player.Kick("Exploit attempt detected!"); TShock.Log.ConsoleDebug($"HandleSyncCavernMonsterType: Player is trying to modify NPC cavernMonsterType; this is a crafted packet! - From {args.Player.Name}"); return true; } From 0619092ba5e9a140e136c451e7c7ed5c654db40f Mon Sep 17 00:00:00 2001 From: Patrikkk Date: Tue, 2 Jun 2020 11:41:41 +0200 Subject: [PATCH 7/7] Fix identing after conflict resolve merge. --- TShockAPI/GetDataHandlers.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TShockAPI/GetDataHandlers.cs b/TShockAPI/GetDataHandlers.cs index 00172763..a73c7aef 100644 --- a/TShockAPI/GetDataHandlers.cs +++ b/TShockAPI/GetDataHandlers.cs @@ -152,7 +152,7 @@ namespace TShockAPI { PacketTypes.PlayerHurtV2, HandlePlayerDamageV2 }, { PacketTypes.PlayerDeathV2, HandlePlayerKillMeV2 }, { PacketTypes.Emoji, HandleEmoji }, - { PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker }, + { PacketTypes.SyncRevengeMarker, HandleSyncRevengeMarker }, { PacketTypes.FishOutNPC, HandleFishOutNPC }, { PacketTypes.FoodPlatterTryPlacing, HandleFoodPlatterTryPlacing }, { PacketTypes.SyncCavernMonsterType, HandleSyncCavernMonsterType } @@ -3603,7 +3603,7 @@ namespace TShockAPI return false; } - private static bool HandleSyncRevengeMarker(GetDataHandlerArgs args) + private static bool HandleSyncRevengeMarker(GetDataHandlerArgs args) { int uniqueID = args.Data.ReadInt32(); Vector2 location = args.Data.ReadVector2(); @@ -3615,7 +3615,7 @@ namespace TShockAPI float baseValue = args.Data.ReadSingle(); bool spawnedFromStatus = args.Data.ReadBoolean(); - return false; + return false; } private static bool HandleFishOutNPC(GetDataHandlerArgs args)