diff --git a/Instructions.txt b/Instructions.txt index 3a55d225..858a0504 100644 --- a/Instructions.txt +++ b/Instructions.txt @@ -961,6 +961,26 @@ number of messages/commands that were sent beyond the specified limits. It gets increased for every message/command by 1 and reset to zero when the "timeframe" has passed. + + 3) SPAMJOINS: + + This check limits the number of new players joining every X seconds to + prevent the usage of softwares like PWN4G3. + + active: + Should players get checked for that kind of spam. + + playerslimit: + The number of new players allowed to join during the interval defined + in the configuration. + + timelimit: + The interval in milliseconds during which the number of new players + defined in the configuration are allowed to join. + + cooldown: + The number of milliseconds during which new players won't be allowed + to join if too many new players have been detected. ------------------------------ FIGHT Subsection -------------------------------- diff --git a/pom.xml b/pom.xml index 33a685f9..a762a071 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ NoCheatPlus - 3.5.4_1 + 3.5.5 Detect and fight the exploitation of various flaws/bugs in Minecraft. http://dev.bukkit.org/server-mods/nocheatplus diff --git a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java index eeb77792..25919bb8 100644 --- a/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java +++ b/src/me/neatmonster/nocheatplus/checks/blockplace/BlockPlaceCheckListener.java @@ -56,6 +56,8 @@ public class BlockPlaceCheckListener implements Listener, EventManager { s.add("blockplace.reach"); if (bp.directionCheck) s.add("blockplace.direction"); + if (bp.projectileCheck) + s.add("blockplace.projectileCheck"); return s; } @@ -127,8 +129,10 @@ public class BlockPlaceCheckListener implements Listener, EventManager { public void otherProjectiles(final ProjectileLaunchEvent event) { // We are only interested by enderpears, endersignals, eggs, snowballs and expbottles - if (event.getEntityType() != EntityType.ENDER_PEARL && event.getEntityType() != EntityType.ENDER_SIGNAL - && event.getEntityType() != EntityType.EGG && event.getEntityType() != EntityType.SNOWBALL + // of course thrown by a player + if (!(event.getEntity().getShooter() instanceof Player) || event.getEntityType() != EntityType.ENDER_PEARL + && event.getEntityType() != EntityType.ENDER_SIGNAL && event.getEntityType() != EntityType.EGG + && event.getEntityType() != EntityType.SNOWBALL && event.getEntityType() != EntityType.THROWN_EXP_BOTTLE) return; diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java index f20d8d78..cab5ec62 100644 --- a/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java +++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatCheckListener.java @@ -14,6 +14,7 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; +import org.bukkit.event.player.PlayerJoinEvent; /** * Central location to listen to events that are @@ -22,16 +23,18 @@ import org.bukkit.event.player.PlayerCommandPreprocessEvent; */ public class ChatCheckListener implements Listener, EventManager { - private final SpamCheck spamCheck; - private final ColorCheck colorCheck; + private final SpamCheck spamCheck; + private final SpamJoinsCheck spamJoinsCheck; + private final ColorCheck colorCheck; - private final NoCheatPlus plugin; + private final NoCheatPlus plugin; public ChatCheckListener(final NoCheatPlus plugin) { this.plugin = plugin; spamCheck = new SpamCheck(plugin); + spamJoinsCheck = new SpamJoinsCheck(plugin); colorCheck = new ColorCheck(plugin); } @@ -95,8 +98,27 @@ public class ChatCheckListener implements Listener, EventManager { final ChatConfig c = ChatCheck.getConfig(cc); if (c.spamCheck) s.add("chat.spam"); + if (c.spamJoinsCheck) + s.add("chat.spamjoins"); if (c.colorCheck) s.add("chat.color"); return s; } + + @EventHandler( + ignoreCancelled = true, priority = EventPriority.LOWEST) + public void join(final PlayerJoinEvent event) { + + // Only check new players (who has joined less than 10 minutes ago) + if (System.currentTimeMillis() - event.getPlayer().getFirstPlayed() > 600000L) + return; + + final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer()); + final ChatConfig cc = ChatCheck.getConfig(player); + final ChatData data = ChatCheck.getData(player); + + if (cc.spamJoinsCheck && spamJoinsCheck.check(player, data, cc)) + // If the player failed the check, kick it + event.getPlayer().kickPlayer(cc.spamJoinsKickMessage); + } } diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java index 6b3dae96..b8db4e1f 100644 --- a/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java +++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatConfig.java @@ -24,6 +24,12 @@ public class ChatConfig implements ConfigItem { public final int spamCommandLimit; public final ActionList spamActions; + public final boolean spamJoinsCheck; + public final int spamJoinsPlayersLimit; + public final int spamJoinsTimeLimit; + public final int spamJoinsCooldown; + public final String spamJoinsKickMessage; + public final boolean colorCheck; public final ActionList colorActions; @@ -35,6 +41,11 @@ public class ChatConfig implements ConfigItem { spamMessageLimit = data.getInt(ConfPaths.CHAT_SPAM_MESSAGELIMIT); spamCommandLimit = data.getInt(ConfPaths.CHAT_SPAM_COMMANDLIMIT); spamActions = data.getActionList(ConfPaths.CHAT_SPAM_ACTIONS, Permissions.CHAT_SPAM); + spamJoinsCheck = data.getBoolean(ConfPaths.CHAT_SPAMJOINS_CHECK); + spamJoinsPlayersLimit = data.getInt(ConfPaths.CHAT_SPAMJOINS_PLAYERSLIMIT); + spamJoinsTimeLimit = data.getInt(ConfPaths.CHAT_SPAMJOINS_TIMELIMIT); + spamJoinsCooldown = data.getInt(ConfPaths.CHAT_SPAMJOINS_COOLDOWN); + spamJoinsKickMessage = data.getString(ConfPaths.CHAT_SPAMJOINS_KICKMESSAGE); colorCheck = data.getBoolean(ConfPaths.CHAT_COLOR_CHECK); colorActions = data.getActionList(ConfPaths.CHAT_COLOR_ACTIONS, Permissions.CHAT_COLOR); } diff --git a/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java b/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java index eb5e22da..94be82cd 100644 --- a/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java +++ b/src/me/neatmonster/nocheatplus/checks/chat/ChatData.java @@ -10,6 +10,7 @@ public class ChatData implements DataItem { // Keep track of the violation levels for the two checks public int spamVL; + public int spamJoinsVL; public int colorVL; // Count messages and commands diff --git a/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java b/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java new file mode 100644 index 00000000..dc21ccd4 --- /dev/null +++ b/src/me/neatmonster/nocheatplus/checks/chat/SpamJoinsCheck.java @@ -0,0 +1,55 @@ +package me.neatmonster.nocheatplus.checks.chat; + +import me.neatmonster.nocheatplus.NoCheatPlus; +import me.neatmonster.nocheatplus.NoCheatPlusPlayer; + +public class SpamJoinsCheck extends ChatCheck { + + // Used to know if the cooldown is enabled and since when + private boolean cooldown = false; + private long cooldownStartTime = 0L; + + // Used to remember the latest joins; + private long[] joins = null; + + public SpamJoinsCheck(final NoCheatPlus plugin) { + super(plugin, "chat.spamjoins"); + } + + public boolean check(final NoCheatPlusPlayer player, final ChatData data, final ChatConfig cc) { + + // Initialize the joins array + if (joins == null) + joins = new long[cc.spamJoinsPlayersLimit]; + + boolean kick = false; + + // If the new players cooldown is over + if (cooldown && System.currentTimeMillis() - cooldownStartTime > cc.spamJoinsCooldown) { + // Stop the new players cooldown + cooldown = false; + cooldownStartTime = 0L; + } + + // If the new players cooldown is active + else if (cooldown) + // Kick the player who joined + kick = true; + + // If more than limit new players have joined in less than limit time + else if (System.currentTimeMillis() - joins[0] < cc.spamJoinsTimeLimit) { + // Enable the new players cooldown + cooldown = true; + cooldownStartTime = System.currentTimeMillis(); + // Kick the player who joined + kick = true; + } + + // Fill the joining times array + for (int i = 0; i < cc.spamJoinsPlayersLimit - 1; i++) + joins[i] = joins[i + 1]; + joins[cc.spamJoinsPlayersLimit - 1] = System.currentTimeMillis(); + + return kick; + } +} diff --git a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java index 96b81eb3..9b63d624 100644 --- a/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java +++ b/src/me/neatmonster/nocheatplus/checks/moving/MovingCheckListener.java @@ -71,19 +71,17 @@ public class MovingCheckListener implements Listener, EventManager { final MovingData data = MovingCheck.getData(player); // Do not do the check if it's disabled, if flying is allowed, if the player is - // allowed to fly because of its game mode or if he has the required permission. + // allowed to fly because of its game mode, if he has the required permission, + // if he is in water or in vines. if (!cc.tracker || cc.allowFlying || bukkitPlayer.getGameMode() == GameMode.CREATIVE - || bukkitPlayer.getAllowFlight() || bukkitPlayer.hasPermission(Permissions.MOVING_RUNFLY)) { - data.fallingSince = 0; - return; - } - - // If the player is in water or in vines, then do not run the check - if (bukkitPlayer.getLocation().getBlock().getType() == Material.WATER + || bukkitPlayer.getAllowFlight() || bukkitPlayer.hasPermission(Permissions.MOVING_RUNFLY) + || bukkitPlayer.hasPermission(Permissions.MOVING_FLYING) + || bukkitPlayer.getLocation().getBlock().getType() == Material.WATER || bukkitPlayer.getLocation().getBlock().getType() == Material.STATIONARY_WATER + || bukkitPlayer.getLocation().getBlock().getType() == Material.LADDER || bukkitPlayer.getLocation().getBlock().getType() == Material.VINE) { data.fallingSince = 0; - return; + continue; } // If the player isn't falling or jumping @@ -176,10 +174,14 @@ public class MovingCheckListener implements Listener, EventManager { s.add("moving.sneaking"); if (m.nofallCheck) s.add("moving.nofall"); + if (m.waterWalkCheck) + s.add("moving.waterwalk"); } else s.add("moving.flying"); if (m.morePacketsCheck) s.add("moving.morepackets"); + if (m.morePacketsVehicleCheck) + s.add("moving.morepacketsvehicle"); return s; } diff --git a/src/me/neatmonster/nocheatplus/config/ConfPaths.java b/src/me/neatmonster/nocheatplus/config/ConfPaths.java index 17757801..5e10257e 100644 --- a/src/me/neatmonster/nocheatplus/config/ConfPaths.java +++ b/src/me/neatmonster/nocheatplus/config/ConfPaths.java @@ -142,6 +142,13 @@ public abstract class ConfPaths { public final static String CHAT_SPAM_COMMANDLIMIT = CHAT_SPAM + "commandlimit"; public final static String CHAT_SPAM_ACTIONS = CHAT_SPAM + "actions"; + private final static String CHAT_SPAMJOINS = CHAT + "spamjoins."; + public final static String CHAT_SPAMJOINS_CHECK = CHAT_SPAMJOINS + "active"; + public final static String CHAT_SPAMJOINS_PLAYERSLIMIT = CHAT_SPAMJOINS + "playerslimit"; + public final static String CHAT_SPAMJOINS_TIMELIMIT = CHAT_SPAMJOINS + "timelimit"; + public final static String CHAT_SPAMJOINS_COOLDOWN = CHAT_SPAMJOINS + "cooldown"; + public final static String CHAT_SPAMJOINS_KICKMESSAGE = CHAT_SPAMJOINS + "kickmessage"; + private final static String FIGHT = CHECKS + "fight."; private final static String FIGHT_DIRECTION = FIGHT + "direction."; diff --git a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java index 69e73a45..93a5d80e 100644 --- a/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java +++ b/src/me/neatmonster/nocheatplus/config/DefaultConfiguration.java @@ -125,6 +125,12 @@ public class DefaultConfiguration extends NoCheatPlusConfiguration { set(ConfPaths.CHAT_SPAM_COMMANDLIMIT, 12); set(ConfPaths.CHAT_SPAM_ACTIONS, "log:spam:0:3:if cancel vl>30 log:spam:0:3:cif cancel cmd:kick"); + set(ConfPaths.CHAT_SPAMJOINS_CHECK, true); + set(ConfPaths.CHAT_SPAMJOINS_PLAYERSLIMIT, 3); + set(ConfPaths.CHAT_SPAMJOINS_TIMELIMIT, 5000); + set(ConfPaths.CHAT_SPAMJOINS_COOLDOWN, 5000); + set(ConfPaths.CHAT_SPAMJOINS_KICKMESSAGE, "SpamBot?!"); + /*** FIGHT ***/ set(ConfPaths.FIGHT_DIRECTION_CHECK, true);