Optional prevention of a couple of exploits.

1. Obsidian generator exploit, which converts redstone wire to obsidian. New setting "handleExploitObsidianGenerators" (enabled by default) to determine whether it's prevented or not. Some servers might want to disable this prevention, to keep it as a viable obsidian creation method. Thanks to ObGenBlocker and WorldGuard plugins for the prevention method.
2. Ender pearl exploit, which could be used to clip through doors, glass, and probably a few other things if just the right spot was targeted. New setting "handleExploitEnderPearlClipping" (enabled by default) to determine whether it's prevented or not.

Also removed our TNT exploit prevention code, since they did get it fully fixed in 1.1-R4 and it doesn't look to be coming back from the dead again like it did when they released 1.1-R2.
This commit is contained in:
Brettflan 2012-03-19 06:55:00 -05:00
parent 2df8ca0df9
commit 8f2e587eb9
5 changed files with 52 additions and 101 deletions

View File

@ -101,7 +101,11 @@ public class Conf
public static boolean logLandUnclaims = true; public static boolean logLandUnclaims = true;
public static boolean logMoneyTransactions = true; public static boolean logMoneyTransactions = true;
public static boolean logPlayerCommands = true; public static boolean logPlayerCommands = true;
// prevent some potential exploits
public static boolean handleExploitObsidianGenerators = true;
public static boolean handleExploitEnderPearlClipping = true;
public static boolean homesEnabled = true; public static boolean homesEnabled = true;
public static boolean homesMustBeInClaimedTerritory = true; public static boolean homesMustBeInClaimedTerritory = true;
public static boolean homesTeleportToOnDeath = true; public static boolean homesTeleportToOnDeath = true;

View File

@ -30,6 +30,7 @@ import com.massivecraft.factions.integration.Worldguard;
import com.massivecraft.factions.listeners.FactionsBlockListener; import com.massivecraft.factions.listeners.FactionsBlockListener;
import com.massivecraft.factions.listeners.FactionsChatListener; import com.massivecraft.factions.listeners.FactionsChatListener;
import com.massivecraft.factions.listeners.FactionsEntityListener; import com.massivecraft.factions.listeners.FactionsEntityListener;
import com.massivecraft.factions.listeners.FactionsExploitListener;
import com.massivecraft.factions.listeners.FactionsPlayerListener; import com.massivecraft.factions.listeners.FactionsPlayerListener;
import com.massivecraft.factions.listeners.FactionsServerListener; import com.massivecraft.factions.listeners.FactionsServerListener;
import com.massivecraft.factions.struct.ChatMode; import com.massivecraft.factions.struct.ChatMode;
@ -54,6 +55,7 @@ public class P extends MPlugin
public final FactionsPlayerListener playerListener; public final FactionsPlayerListener playerListener;
public final FactionsChatListener chatListener; public final FactionsChatListener chatListener;
public final FactionsEntityListener entityListener; public final FactionsEntityListener entityListener;
public final FactionsExploitListener exploitListener;
public final FactionsBlockListener blockListener; public final FactionsBlockListener blockListener;
public final FactionsServerListener serverListener; public final FactionsServerListener serverListener;
@ -73,6 +75,7 @@ public class P extends MPlugin
this.playerListener = new FactionsPlayerListener(this); this.playerListener = new FactionsPlayerListener(this);
this.chatListener = new FactionsChatListener(this); this.chatListener = new FactionsChatListener(this);
this.entityListener = new FactionsEntityListener(this); this.entityListener = new FactionsEntityListener(this);
this.exploitListener = new FactionsExploitListener();
this.blockListener = new FactionsBlockListener(this); this.blockListener = new FactionsBlockListener(this);
this.serverListener = new FactionsServerListener(this); this.serverListener = new FactionsServerListener(this);
} }
@ -113,6 +116,7 @@ public class P extends MPlugin
getServer().getPluginManager().registerEvents(playerListener, this); getServer().getPluginManager().registerEvents(playerListener, this);
getServer().getPluginManager().registerEvents(chatListener, this); getServer().getPluginManager().registerEvents(chatListener, this);
getServer().getPluginManager().registerEvents(entityListener, this); getServer().getPluginManager().registerEvents(entityListener, this);
getServer().getPluginManager().registerEvents(exploitListener, this);
getServer().getPluginManager().registerEvents(blockListener, this); getServer().getPluginManager().registerEvents(blockListener, this);
getServer().getPluginManager().registerEvents(serverListener, this); getServer().getPluginManager().registerEvents(serverListener, this);

View File

@ -87,25 +87,9 @@ public class FactionsBlockListener implements Listener
{ {
if (event.isCancelled()) return; if (event.isCancelled()) return;
if ( ! event.canBuild()) return; if ( ! event.canBuild()) return;
// TODO: Test if this old stuff is still an issue.
// special case for flint&steel, which should only be prevented by DenyUsage list
/*if (event.getBlockPlaced().getType() == Material.FIRE)
{
return;
}*/
if ( ! playerCanBuildDestroyBlock(event.getPlayer(), event.getBlock(), "build", false)) if ( ! playerCanBuildDestroyBlock(event.getPlayer(), event.getBlock(), "build", false))
{
event.setCancelled(true); event.setCancelled(true);
Material handItem = event.getPlayer().getItemInHand().getType();
if (handItem == Material.TNT || handItem == Material.REDSTONE_TORCH_ON)
{
Faction targetFaction = Board.getFactionAt(new FLocation(event.getBlock()));
FactionsEntityListener.trackPotentialExplosionExploit(event.getPlayer().getName(), targetFaction, handItem, event.getBlock().getLocation());
}
}
} }
@EventHandler(priority = EventPriority.NORMAL) @EventHandler(priority = EventPriority.NORMAL)

View File

@ -1,22 +1,18 @@
package com.massivecraft.factions.listeners; package com.massivecraft.factions.listeners;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.logging.Level;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.Set; import java.util.Set;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.entity.Enderman; import org.bukkit.entity.Enderman;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Projectile; import org.bukkit.entity.Projectile;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
@ -28,7 +24,6 @@ import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityDeathEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityTargetEvent; import org.bukkit.event.entity.EntityTargetEvent;
import org.bukkit.event.entity.ExplosionPrimeEvent;
import org.bukkit.event.entity.PotionSplashEvent; import org.bukkit.event.entity.PotionSplashEvent;
import org.bukkit.event.painting.PaintingBreakByEntityEvent; import org.bukkit.event.painting.PaintingBreakByEntityEvent;
import org.bukkit.event.painting.PaintingBreakEvent; import org.bukkit.event.painting.PaintingBreakEvent;
@ -154,9 +149,7 @@ public class FactionsEntityListener implements Listener
} }
if ( ! badjuju) return; if ( ! badjuju) return;
Entity thrower = event.getEntity(); Entity thrower = event.getPotion().getShooter();
if (thrower instanceof Projectile)
thrower = ((Projectile)thrower).getShooter();
// scan through affected entities to make sure they're all valid targets // scan through affected entities to make sure they're all valid targets
Iterator<LivingEntity> iter = event.getAffectedEntities().iterator(); Iterator<LivingEntity> iter = event.getAffectedEntities().iterator();
@ -386,80 +379,4 @@ public class FactionsEntityListener implements Listener
event.setCancelled(true); event.setCancelled(true);
} }
/**
* Canceled redstone torch placement next to existing TNT is still triggering an explosion, thus, our workaround here.
* related to this:
* https://bukkit.atlassian.net/browse/BUKKIT-89
* though they do finally appear to have fixed the converse situation (existing redstone torch, TNT placement attempted but canceled)
*/
private static ArrayList<PotentialExplosionExploit> exploitExplosions = new ArrayList<PotentialExplosionExploit>();
@EventHandler(priority = EventPriority.NORMAL)
public void onExplosionPrime(ExplosionPrimeEvent event)
{
if (event.isCancelled()) return;
if (! (event.getEntity() instanceof TNTPrimed)) return;
if (exploitExplosions.isEmpty()) return;
// make sure this isn't a TNT explosion exploit attempt
int locX = event.getEntity().getLocation().getBlockX();
int locZ = event.getEntity().getLocation().getBlockZ();
for (int i = exploitExplosions.size() - 1; i >= 0; i--)
{
PotentialExplosionExploit ex = exploitExplosions.get(i);
// remove anything from the list older than 8 seconds
if (ex.timeMillis + 8000 < System.currentTimeMillis())
{
exploitExplosions.remove(i);
continue;
}
int absX = Math.abs(ex.X - locX);
int absZ = Math.abs(ex.Z - locZ);
if (absX < 5 && absZ < 5)
{ // it sure looks like an exploit attempt
// let's tattle on him to everyone
String msg = "NOTICE: Player \""+ex.playerName+"\" attempted to exploit a TNT bug in the territory of \""+ex.faction.getTag()+"\"";
P.p.log(Level.WARNING, msg + " at "+ex.X+","+ex.Z+" (X,Z) using a "+ex.item.name());
for (FPlayer fplayer : FPlayers.i.getOnline())
{
fplayer.sendMessage(msg+". Coordinates logged.");
}
event.setCancelled(true);
exploitExplosions.remove(i);
return;
}
}
}
public static void trackPotentialExplosionExploit(String playerName, Faction faction, Material item, Location location)
{
exploitExplosions.add(new PotentialExplosionExploit(playerName, faction, item, location));
}
public static class PotentialExplosionExploit
{
public String playerName;
public Faction faction;
public Material item;
public long timeMillis;
public int X;
public int Z;
public PotentialExplosionExploit(String playerName, Faction faction, Material item, Location location)
{
this.playerName = playerName;
this.faction = faction;
this.item = item;
this.timeMillis = System.currentTimeMillis();
this.X = location.getBlockX();
this.Z = location.getBlockZ();
}
}
} }

View File

@ -0,0 +1,42 @@
package com.massivecraft.factions.listeners;
import org.bukkit.block.Block;
import org.bukkit.event.block.BlockFromToEvent;
import org.bukkit.event.player.PlayerTeleportEvent;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import org.bukkit.Location;
import com.massivecraft.factions.Conf;
public class FactionsExploitListener implements Listener
{
@EventHandler(priority = EventPriority.NORMAL)
public void obsidianGenerator(BlockFromToEvent event)
{
if (event.isCancelled() == true || ! Conf.handleExploitObsidianGenerators) return;
// thanks to ObGenBlocker and WorldGuard for this method
int source = event.getBlock().getTypeId();
Block block = event.getToBlock();
if ((source == 0 || source == 10 || source == 11) && block.getTypeId() == 55)
block.setTypeId(0);
}
@EventHandler(priority = EventPriority.NORMAL)
public void enderPearlTeleport(PlayerTeleportEvent event)
{
if (event.isCancelled() == true || ! Conf.handleExploitEnderPearlClipping) return;
if (event.getCause() != PlayerTeleportEvent.TeleportCause.ENDER_PEARL) return;
// this exploit works when the target location is within 0.31 blocks or so of a door or glass block or similar...
// simple fix: ender pearl target locations are standardized to be in the center (X/Z) of the target block, not at the edges
Location target = event.getTo();
target.setX(target.getBlockX() + 0.5);
target.setZ(target.getBlockZ() + 0.5);
event.setTo(target);
}
}