+ Patched the disconnect nofall exploit

+ Commands are now hidden (from players)
= Fixed the SpamJoin check (2 issues)
= Fixed the issue with plugins lists
= Fixed the Tracker check's issue with AuthMe
= Fixed an issue with boats and moving water
This commit is contained in:
NeatMonster 2012-04-15 01:55:23 +02:00
parent 9aa5536fe4
commit 27c79ac30c
8 changed files with 124 additions and 51 deletions

View File

@ -3,6 +3,7 @@ version: ${project.version}
description: ${project.description}
author: NeatMonster
authors: [Eventprime, Juliui]
website: ${project.url}
main: me.neatmonster.nocheatplus.NoCheatPlus
@ -10,7 +11,7 @@ main: me.neatmonster.nocheatplus.NoCheatPlus
commands:
nocheatplus:
description: NoCheatPlus command(s)
permission: nocheatplus.admin.commands
# permission: nocheatplus.admin.commands
usage: |
/<command> permlist player [permission]: list NoCheatPlus' permissions of player, optionally only if beginning with [permission]
/<command> playerinfo player: show the collected data NoCheatPlus collected about a player

View File

@ -4,7 +4,7 @@
<!-- Informations -->
<name>NoCheatPlus</name>
<version>3.5.5_3</version>
<version>3.5.5_4</version>
<description>Detect and fight the exploitation of various flaws/bugs in Minecraft.</description>
<url>http://dev.bukkit.org/server-mods/nocheatplus</url>

View File

@ -98,7 +98,7 @@ public class ChatCheckListener implements Listener, EventManager {
if ((event.getMessage().equalsIgnoreCase("/plugins")
|| event.getMessage().toLowerCase().startsWith("/plugins ")
|| event.getMessage().equalsIgnoreCase("/pl") || event.getMessage().toLowerCase().startsWith("/pl "))
&& cc.hideNoCheatPlus) {
&& Bukkit.getPluginManager().getPlugin("PluginList") == null && cc.hideNoCheatPlus) {
// If the player isn't allowed to use this command
if (!event.getPlayer().hasPermission("bukkit.command.plugins"))
// Fake the permissions error message
@ -153,8 +153,8 @@ public class ChatCheckListener implements Listener, EventManager {
ignoreCancelled = true, priority = EventPriority.LOWEST)
public void login(final PlayerLoginEvent event) {
// Only check players who haven't played before
if (event.getPlayer().hasPlayedBefore())
// Only check new players (who has joined less than 10 minutes ago)
if (System.currentTimeMillis() - event.getPlayer().getFirstPlayed() > 600000D)
return;
final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer());

View File

@ -1,16 +1,19 @@
package me.neatmonster.nocheatplus.checks.chat;
import java.util.Arrays;
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;
private boolean cooldown = false;
private long cooldownStartTime = 0L;
// Used to remember the latest joins;
private long[] joins = null;
private long[] joinsTimes = null;
private String[] joinsPlayers = null;
public SpamJoinsCheck(final NoCheatPlus plugin) {
super(plugin, "chat.spamjoins");
@ -19,8 +22,10 @@ public class SpamJoinsCheck extends ChatCheck {
public boolean check(final NoCheatPlusPlayer player, final ChatData data, final ChatConfig cc) {
// Initialize the joins array
if (joins == null)
joins = new long[cc.spamJoinsPlayersLimit];
if (joinsTimes == null)
joinsTimes = new long[cc.spamJoinsPlayersLimit];
if (joinsPlayers == null)
joinsPlayers = new String[cc.spamJoinsPlayersLimit];
boolean kick = false;
@ -37,7 +42,7 @@ public class SpamJoinsCheck extends ChatCheck {
kick = true;
// If more than limit new players have joined in less than limit time
else if (System.currentTimeMillis() - joins[0] < cc.spamJoinsTimeLimit) {
else if (System.currentTimeMillis() - joinsTimes[0] < cc.spamJoinsTimeLimit) {
// Enable the new players cooldown
cooldown = true;
cooldownStartTime = System.currentTimeMillis();
@ -46,9 +51,14 @@ public class SpamJoinsCheck extends ChatCheck {
}
// 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();
if (!Arrays.asList(joinsPlayers).contains(player.getName())) {
for (int i = 0; i < cc.spamJoinsPlayersLimit - 1; i++) {
joinsTimes[i] = joinsTimes[i + 1];
joinsPlayers[i] = joinsPlayers[i + 1];
}
joinsTimes[cc.spamJoinsPlayersLimit - 1] = System.currentTimeMillis();
joinsPlayers[cc.spamJoinsPlayersLimit - 1] = player.getName();
}
return kick;
}

View File

@ -23,6 +23,7 @@ import org.bukkit.event.block.Action;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerChangedWorldEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerPortalEvent;
import org.bukkit.event.player.PlayerQuitEvent;
@ -135,6 +136,26 @@ public class MovingCheckListener implements Listener, EventManager {
}
}
/**
* If a player tries to place a boat on the ground, the event
* will be cancelled.
*
* @param event
* The PlayerInteractEvent
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.LOWEST)
public void boat(final PlayerInteractEvent event) {
if (!event.getPlayer().hasPermission(Permissions.MOVING_BOATONGROUND)
&& event.getAction() == Action.RIGHT_CLICK_BLOCK
&& event.getPlayer().getItemInHand().getType() == Material.BOAT
&& event.getClickedBlock().getType() != Material.WATER
&& event.getClickedBlock().getType() != Material.STATIONARY_WATER
&& event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.WATER
&& event.getClickedBlock().getRelative(event.getBlockFace()).getType() != Material.STATIONARY_WATER)
event.setCancelled(true);
}
@Override
public List<String> getActiveChecks(final ConfigurationCacheStore cc) {
final LinkedList<String> s = new LinkedList<String>();
@ -160,6 +181,27 @@ public class MovingCheckListener implements Listener, EventManager {
return s;
}
/**
* This event handler is used to prevent the player from quickly
* disconnecting/reconnecting in order to cancel his fall damages.
*
* @param event
* The PlayerJoinEvent
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.MONITOR)
public void join(final PlayerJoinEvent event) {
final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer());
final MovingData data = MovingCheck.getData(player);
// If the player has joined in the air and a safe location is defined...
if (player.getPlayer().getLocation().add(0, -1, 0).getBlock().getType() == Material.AIR
&& data.lastSafeLocations[0] != null)
// ...then teleport him to this location
event.getPlayer().teleport(data.lastSafeLocations[0]);
}
/**
* When a player moves, he will be checked for various
* suspicious behaviour.
@ -197,6 +239,12 @@ public class MovingCheckListener implements Listener, EventManager {
final Location to = event.getTo();
data.to.set(to);
// Remember safe locations
if (Math.abs(event.getPlayer().getVelocity().getY()) < 0.0785D) {
data.lastSafeLocations[0] = data.lastSafeLocations[1];
data.lastSafeLocations[1] = event.getFrom();
}
PreciseLocation newTo = null;
/** RUNFLY CHECK SECTION **/
@ -238,24 +286,6 @@ public class MovingCheckListener implements Listener, EventManager {
}
}
/**
* If a player tries to place a boat on the ground, the event
* will be cancelled.
*
* @param event
* The PlayerInteractEvent
*/
@EventHandler(
ignoreCancelled = true, priority = EventPriority.LOWEST)
public void onPlayerInteract(final PlayerInteractEvent event) {
if (!event.getPlayer().hasPermission(Permissions.MOVING_BOATONGROUND)
&& event.getAction() == Action.RIGHT_CLICK_BLOCK
&& event.getPlayer().getItemInHand().getType() == Material.BOAT
&& event.getClickedBlock().getType() != Material.WATER
&& event.getClickedBlock().getType() != Material.STATIONARY_WATER)
event.setCancelled(true);
}
/**
* When a player uses a portal, all information related to the
* moving checks becomes invalid.
@ -278,6 +308,13 @@ public class MovingCheckListener implements Listener, EventManager {
*/
@EventHandler
public void quit(final PlayerQuitEvent event) {
final NoCheatPlusPlayer player = plugin.getPlayer(event.getPlayer());
final MovingData data = MovingCheck.getData(player);
// Reset the variable
data.fallingSince = 0L;
if (!event.getPlayer().hasPermission(Permissions.MOVING_RESPAWNTRICK)
&& (event.getPlayer().getLocation().getBlock().getType() == Material.GRAVEL || event.getPlayer()
.getLocation().getBlock().getType() == Material.SAND)) {
@ -420,6 +457,9 @@ public class MovingCheckListener implements Listener, EventManager {
final MovingData data = MovingCheck.getData(plugin.getPlayer(event.getPlayer()));
// Reset the tracker's data
data.fallingSince = 0L;
final Vector v = event.getVelocity();
double newVal = v.getY();

View File

@ -4,6 +4,8 @@ import me.neatmonster.nocheatplus.DataItem;
import me.neatmonster.nocheatplus.data.PreciseLocation;
import me.neatmonster.nocheatplus.data.Statistics.Id;
import org.bukkit.Location;
/**
* Player specific data for the moving check group
*/
@ -28,7 +30,7 @@ public class MovingData implements DataItem {
public int onIce;
// Where should a player be teleported back to when failing the check
public final PreciseLocation runflySetBackPoint = new PreciseLocation();
public final PreciseLocation runflySetBackPoint = new PreciseLocation();
// Some values for estimating movement freedom
public double vertFreedom;
@ -44,39 +46,45 @@ public class MovingData implements DataItem {
public float lastAddedFallDistance;
// Keep in mind since when the player in falling/jumping
public long fallingSince = 0L;
public long fallingSince = 0L;
// Remember if the player has already been on the ground
public boolean hasAlreadyBeenOnTheGround = false;
// Keep in mind the player's last safe position
public Location[] lastSafeLocations = new Location[] {null, null};
// Keep track of when "morePackets" last time checked and how much packets
// a player sent and may send before failing the check
public long morePacketsLastTime;
public int packets;
public int morePacketsBuffer = 50;
public int morePacketsBuffer = 50;
// Where to teleport the player that fails the "morepackets" check
public final PreciseLocation morePacketsSetbackPoint = new PreciseLocation();
public final PreciseLocation morePacketsSetbackPoint = new PreciseLocation();
// Keep track of when "morePacketsVehicle" last time checked an how much
// packets a vehicle sent and may send before failing the check
public long morePacketsVehicleLastTime;
public int packetsVehicle;
public int morePacketsVehicleBuffer = 50;
public int morePacketsVehicleBuffer = 50;
// When NoCheatPlus does teleport the player, remember the target location to
// be able to distinguish "our" teleports from teleports of others
public final PreciseLocation teleportTo = new PreciseLocation();
public final PreciseLocation teleportTo = new PreciseLocation();
// For logging and convenience, make copies of the events locations
public final PreciseLocation from = new PreciseLocation();
public final PreciseLocation fromVehicle = new PreciseLocation();
public final PreciseLocation to = new PreciseLocation();
public final PreciseLocation toVehicle = new PreciseLocation();
public final PreciseLocation from = new PreciseLocation();
public final PreciseLocation fromVehicle = new PreciseLocation();
public final PreciseLocation to = new PreciseLocation();
public final PreciseLocation toVehicle = new PreciseLocation();
// For convenience, remember if the locations are considered "on ground"
// by NoCheatPlus
public boolean fromOnOrInGround;
public boolean toOnOrInGround;
public Id statisticCategory = Id.MOV_RUNNING;
public Id statisticCategory = Id.MOV_RUNNING;
public void clearMorePacketsData() {
morePacketsSetbackPoint.reset();

View File

@ -28,24 +28,32 @@ public class TrackerCheck extends MovingCheck {
final int type = CheckUtil.evaluateLocation(player.getPlayer().getWorld(), location);
final boolean isLiquid = CheckUtil.isLiquid(type);
// Check if the player is on the ground
if (player.getPlayer().getLocation().add(0, -1, 0).getBlock().getType() != Material.AIR)
data.hasAlreadyBeenOnTheGround = true;
// 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, if he has the required permission,
// if he is in water or in vines.
// if he is in water, on a ladder or in vines.
if (!cc.tracker || cc.allowFlying || player.getPlayer().getGameMode() == GameMode.CREATIVE
|| player.getPlayer().getAllowFlight() || player.getPlayer().hasPermission(Permissions.MOVING_RUNFLY)
|| player.getPlayer().hasPermission(Permissions.MOVING_FLYING) || isLiquid
|| player.getPlayer().getLocation().getBlock().getType() == Material.LADDER
|| player.getPlayer().getLocation().getBlock().getType() == Material.VINE
|| player.getPlayer().getLocation().getX() < 0D) {
data.fallingSince = 0;
|| player.getPlayer().getLocation().getY() < 0D) {
data.fallingSince = 0L;
return;
}
// If the player isn't falling or jumping
// If the player isn't static or jumping
if (Math.abs(player.getPlayer().getVelocity().getY()) > 0.1D) {
// The player is falling/jumping, check if he was previously on the ground
if (data.fallingSince == 0)
// Only do something if the player has already been on the ground
if (!data.hasAlreadyBeenOnTheGround)
return;
// The player is static/jumping, check if he was previously on the ground
if (data.fallingSince == 0L)
data.fallingSince = System.currentTimeMillis();
// Check if he has stayed too much time in the air (more than 6 seconds)
@ -56,11 +64,11 @@ public class TrackerCheck extends MovingCheck {
// Execute whatever actions are associated with this check and the
// violation level and find out if we should cancel the event
executeActions(player, cc.nofallActions, data.nofallVL);
executeActions(player, cc.trackerActions, data.trackerVL);
}
} else {
// Reset the timer
data.fallingSince = 0;
data.fallingSince = 0L;
// Reduce the violation level
data.trackerVL *= 0.95;

View File

@ -63,6 +63,12 @@ public class CommandHandler {
public boolean handleCommand(final NoCheatPlus plugin, final CommandSender sender, final Command command,
final String label, final String[] args) {
// Hide NoCheatPlus's commands if the player doesn't have the required permission
if (sender instanceof Player && !sender.hasPermission("nocheatplus.admin.commands")) {
sender.sendMessage("Unknown command. Type \"help\" for help.");
return true;
}
boolean result = false;
// Not our command, how did it get here?
if (!command.getName().equalsIgnoreCase("nocheatplus") || args.length == 0)