mirror of
https://github.com/GTNewHorizons/EnderIO.git
synced 2026-10-26 14:24:40 +00:00
valiate tp packets (#128)
* validate tp packets Signed-off-by: Glease <4586901+Glease@users.noreply.github.com> * spotless Signed-off-by: Glease <4586901+Glease@users.noreply.github.com> --------- Signed-off-by: Glease <4586901+Glease@users.noreply.github.com>
This commit is contained in:
1 parent
ebcbef851a
commit
54d61f5251
9 files changed
+187
-41
No files matched your search
@@ -4,10 +4,20 @@ import net.minecraft.entity.player.EntityPlayer;
|
||||
import net.minecraft.item.ItemStack;
|
||||
|
||||
import cofh.api.energy.IEnergyContainerItem;
|
||||
import crazypants.enderio.config.Config;
|
||||
|
||||
public interface IItemOfTravel extends IEnergyContainerItem {
|
||||
|
||||
boolean isActive(EntityPlayer ep, ItemStack equipped);
|
||||
|
||||
void extractInternal(ItemStack equipped, int power);
|
||||
|
||||
/**
|
||||
* @param equipped player who is currently holding this item. caller will ensure the item held has your Item as item
|
||||
* type
|
||||
* @return -1 if method not supported, or max(can extract, power), e.g. 0 if item is empty.
|
||||
*/
|
||||
default int canExtractInternal(ItemStack equipped, int power) {
|
||||
return Config.strictTPItemChecking ? 0 : -1;
|
||||
}
|
||||
}
|
||||
@@ -563,6 +563,8 @@ public final class Config {
|
||||
public static float inventoryPanelExtractCostPerItem = 12.0f;
|
||||
public static float inventoryPanelExtractCostPerOperation = 32.0f;
|
||||
|
||||
public static boolean strictTPItemChecking = true;
|
||||
|
||||
public static void load(FMLPreInitializationEvent event) {
|
||||
PacketHandler.INSTANCE
|
||||
.registerMessage(PacketConfigSync.class, PacketConfigSync.class, PacketHandler.nextID(), Side.CLIENT);
|
||||
@@ -2884,6 +2886,12 @@ public final class Config {
|
||||
0.0f,
|
||||
10000.0f,
|
||||
"Internal power used per extract operation (independent of stack size)");
|
||||
strictTPItemChecking = config.get(
|
||||
sectionMisc.name,
|
||||
"strictTPItemChecking",
|
||||
strictTPItemChecking,
|
||||
"If true, turn on strict checking of item energy checking. This might cause traveling tools from third party mods to fire fake security warnings on server side and not function correctly.")
|
||||
.getBoolean(strictTPItemChecking);
|
||||
}
|
||||
|
||||
public static void checkYetaAccess() {
|
||||
|
||||
@@ -331,6 +331,11 @@ public class ItemDarkSteelPickaxe extends ItemPickaxe
|
||||
extractEnergy(equipped, power, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canExtractInternal(ItemStack equipped, int power) {
|
||||
return extractEnergy(equipped, power, true);
|
||||
}
|
||||
|
||||
private boolean isTravelUpgradeActive(EntityPlayer ep, ItemStack equipped) {
|
||||
return isEquipped(ep) && ep.isSneaking() && TravelUpgrade.loadFromItem(equipped) != null;
|
||||
}
|
||||
|
||||
@@ -394,6 +394,11 @@ public class ItemDarkSteelSword extends ItemSword
|
||||
extractEnergy(equipped, power, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canExtractInternal(ItemStack equipped, int power) {
|
||||
return extractEnergy(equipped, power, true);
|
||||
}
|
||||
|
||||
private boolean isTravelUpgradeActive(EntityPlayer ep, ItemStack equipped) {
|
||||
return isEquipped(ep) && ep.isSneaking() && TravelUpgrade.loadFromItem(equipped) != null;
|
||||
}
|
||||
|
||||
@@ -84,6 +84,11 @@ public class ItemTeleportStaff extends ItemTravelStaff {
|
||||
// Do nothing, as we have infinite energy.
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canExtractInternal(ItemStack equipped, int power) {
|
||||
return power;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SideOnly(Side.CLIENT)
|
||||
public void getSubItems(Item item, CreativeTabs par2CreativeTabs, List par3List) {
|
||||
|
||||
@@ -132,6 +132,11 @@ public class ItemTravelStaff extends ItemEnergyContainer implements IItemOfTrave
|
||||
setEnergy(item, res);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int canExtractInternal(ItemStack equipped, int power) {
|
||||
return Math.min(getEnergyStored(equipped), power);
|
||||
}
|
||||
|
||||
void setEnergy(ItemStack container, int energy) {
|
||||
if (container.stackTagCompound == null) {
|
||||
container.stackTagCompound = new NBTTagCompound();
|
||||
|
||||
@@ -111,6 +111,47 @@ public class TravelController {
|
||||
}
|
||||
}
|
||||
|
||||
public boolean validatePacketTravelEvent(EntityPlayerMP toTp, int x, int y, int z, int powerUse,
|
||||
boolean conserveMotion, TravelSource source) {
|
||||
BlockCoord target = new BlockCoord(x, y, z);
|
||||
double dist = getDistanceSquared(toTp, target);
|
||||
// allow 15% overshoot to account for rounding
|
||||
if (dist * 100 > source.getMaxDistanceTravelledSq() * 115) return false;
|
||||
if (powerUse < getRequiredPower(toTp, source, target)) return false;
|
||||
ItemStack equippedItem = toTp.getCurrentEquippedItem();
|
||||
switch (source) {
|
||||
case TELEPAD:
|
||||
// this source is invalid for this type of packet
|
||||
return false;
|
||||
case BLOCK:
|
||||
// this source is only triggered when player is on any active travel anchor
|
||||
BlockCoord on = getActiveTravelBlock(toTp);
|
||||
if (on == null) return false;
|
||||
// target must be a valid selectedCoord
|
||||
// selectedCoord can either be a block right above/below when the player is on anchor...
|
||||
if (on.x == x && on.z == z) return true;
|
||||
// or another anchor
|
||||
TileEntity maybeAnchor = target.getTileEntity(toTp.worldObj);
|
||||
if (!(maybeAnchor instanceof ITravelAccessable)) return false;
|
||||
ITravelAccessable anchor = (ITravelAccessable) maybeAnchor;
|
||||
return anchor.canBlockBeAccessed(toTp) || !isValidTarget(toTp, target, TravelSource.BLOCK);
|
||||
case STAFF:
|
||||
case STAFF_BLINK:
|
||||
if (equippedItem == null || !(equippedItem.getItem() instanceof IItemOfTravel)) return false;
|
||||
if (!((IItemOfTravel) equippedItem.getItem()).isActive(toTp, equippedItem)) return false;
|
||||
int energy = ((IItemOfTravel) equippedItem.getItem()).canExtractInternal(equippedItem, powerUse);
|
||||
return energy == -1 || energy == powerUse;
|
||||
case TELEPORT_STAFF_BLINK:
|
||||
case TELEPORT_STAFF:
|
||||
// tp staff is creative version of traveling staff
|
||||
// no energy check or anything else needed
|
||||
// but the player must actually be equipped with one of these
|
||||
return equippedItem != null && equippedItem.getItem() instanceof ItemTeleportStaff;
|
||||
default:
|
||||
throw new AssertionError("unidentified travel source");
|
||||
}
|
||||
}
|
||||
|
||||
public void addBlockToBlinkBlackList(String blockName) {
|
||||
blackList.add(new UniqueIdentifier(blockName));
|
||||
}
|
||||
@@ -733,35 +774,41 @@ public class TravelController {
|
||||
&& y <= 255; i++, y += direction) {
|
||||
|
||||
// Circumvents the raytracing used to find candidates on the y axis
|
||||
TileEntity selectedBlock = world.getTileEntity(currentBlock.x, y, currentBlock.z);
|
||||
|
||||
if (selectedBlock instanceof ITravelAccessable) {
|
||||
ITravelAccessable travelBlock = (ITravelAccessable) selectedBlock;
|
||||
BlockCoord targetBlock = new BlockCoord(currentBlock.x, y, currentBlock.z);
|
||||
|
||||
if (Config.travelAnchorSkipWarning) {
|
||||
if (travelBlock.getRequiresPassword(player)) {
|
||||
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipLocked"));
|
||||
}
|
||||
|
||||
if (travelBlock.getAccessMode() == ITravelAccessable.AccessMode.PRIVATE
|
||||
&& !travelBlock.canUiBeAccessed(player)) {
|
||||
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipPrivate"));
|
||||
}
|
||||
if (!isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
|
||||
showMessage(
|
||||
player,
|
||||
new ChatComponentTranslation("enderio.gui.travelAccessable.skipObstructed"));
|
||||
}
|
||||
}
|
||||
if (travelBlock.canBlockBeAccessed(player) && isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
|
||||
selectedCoord = targetBlock;
|
||||
return;
|
||||
}
|
||||
BlockCoord targetBlock = getValidVerticalTarget(player, currentBlock, world, y);
|
||||
if (targetBlock != null) {
|
||||
selectedCoord = targetBlock;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private BlockCoord getValidVerticalTarget(EntityPlayer player, BlockCoord currentBlock, World world, int y) {
|
||||
TileEntity selectedBlock = world.getTileEntity(currentBlock.x, y, currentBlock.z);
|
||||
|
||||
if (selectedBlock instanceof ITravelAccessable) {
|
||||
ITravelAccessable travelBlock = (ITravelAccessable) selectedBlock;
|
||||
BlockCoord targetBlock = new BlockCoord(currentBlock.x, y, currentBlock.z);
|
||||
|
||||
if (Config.travelAnchorSkipWarning) {
|
||||
if (travelBlock.getRequiresPassword(player)) {
|
||||
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipLocked"));
|
||||
}
|
||||
|
||||
if (travelBlock.getAccessMode() == ITravelAccessable.AccessMode.PRIVATE
|
||||
&& !travelBlock.canUiBeAccessed(player)) {
|
||||
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipPrivate"));
|
||||
}
|
||||
if (!isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
|
||||
showMessage(player, new ChatComponentTranslation("enderio.gui.travelAccessable.skipObstructed"));
|
||||
}
|
||||
}
|
||||
if (travelBlock.canBlockBeAccessed(player) && isValidTarget(player, targetBlock, TravelSource.BLOCK)) {
|
||||
return targetBlock;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private void updateSelectedTarget(EntityPlayer player) {
|
||||
selectedCoord = null;
|
||||
@@ -923,19 +970,16 @@ public class TravelController {
|
||||
return true;
|
||||
}
|
||||
|
||||
@SideOnly(Side.CLIENT)
|
||||
private BlockCoord getActiveTravelBlock(EntityPlayer player) {
|
||||
World world = Minecraft.getMinecraft().theWorld;
|
||||
if (world != null && player != null) {
|
||||
int x = MathHelper.floor_double(player.posX);
|
||||
int y = MathHelper.floor_double(player.boundingBox.minY) - 1;
|
||||
int z = MathHelper.floor_double(player.posZ);
|
||||
TileEntity tileEntity = world.getTileEntity(x, y, z);
|
||||
if (tileEntity instanceof ITravelAccessable) {
|
||||
if (((ITravelAccessable) tileEntity).isTravelSource()) {
|
||||
return new BlockCoord(x, y, z);
|
||||
}
|
||||
}
|
||||
if (player == null) return null;
|
||||
World world = player.worldObj;
|
||||
if (world == null) return null;
|
||||
int x = MathHelper.floor_double(player.posX);
|
||||
int y = MathHelper.floor_double(player.boundingBox.minY) - 1;
|
||||
int z = MathHelper.floor_double(player.posZ);
|
||||
TileEntity tileEntity = world.getTileEntity(x, y, z);
|
||||
if (tileEntity instanceof ITravelAccessable && ((ITravelAccessable) tileEntity).isTravelSource()) {
|
||||
return new BlockCoord(x, y, z);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
+46
-2
@@ -16,9 +16,11 @@ import com.enderio.core.common.vecmath.Vector3d;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import crazypants.enderio.Log;
|
||||
import crazypants.enderio.api.teleport.IItemOfTravel;
|
||||
import crazypants.enderio.api.teleport.TeleportEntityEvent;
|
||||
import crazypants.enderio.api.teleport.TravelSource;
|
||||
import crazypants.enderio.teleport.ItemTeleportStaff;
|
||||
import crazypants.enderio.teleport.TravelController;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
@@ -53,16 +55,50 @@ public class PacketLongDistanceTravelEvent
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(PacketLongDistanceTravelEvent message, MessageContext ctx) {
|
||||
Entity toTp = message.entityId == -1 ? ctx.getServerHandler().playerEntity
|
||||
: ctx.getServerHandler().playerEntity.worldObj.getEntityByID(message.entityId);
|
||||
if (message.entityId != -1) {
|
||||
// after checking the code base, this type of packet won't be sent at all,
|
||||
// so we can assume this to be an attempt to hack
|
||||
Log.LOGGER.warn(
|
||||
Log.securityMarker,
|
||||
"Player {} tried to illegally tp other entity {}.",
|
||||
ctx.getServerHandler().playerEntity.getGameProfile(),
|
||||
message.entityId);
|
||||
return null;
|
||||
}
|
||||
EntityPlayerMP toTp = ctx.getServerHandler().playerEntity;
|
||||
|
||||
TravelSource source = TravelSource.values()[message.source];
|
||||
|
||||
if (!validate(toTp, source)) {
|
||||
Log.LOGGER.warn(
|
||||
Log.securityMarker,
|
||||
"Player {} tried to tp without valid prereq.",
|
||||
ctx.getServerHandler().playerEntity.getGameProfile());
|
||||
return null;
|
||||
}
|
||||
|
||||
doServerTeleport(toTp, message.conserveMotion, source);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean validate(EntityPlayerMP toTp, TravelSource source) {
|
||||
ItemStack equippedItem = toTp.getCurrentEquippedItem();
|
||||
switch (source) {
|
||||
case STAFF:
|
||||
return equippedItem != null && equippedItem.getItem() instanceof IItemOfTravel
|
||||
&& ((IItemOfTravel) equippedItem.getItem()).isActive(toTp, equippedItem);
|
||||
case TELEPORT_STAFF:
|
||||
// tp staff is creative version of traveling staff
|
||||
// no energy check or anything else needed
|
||||
// but the player must actually be equipped with one of these
|
||||
return equippedItem != null && equippedItem.getItem() instanceof ItemTeleportStaff;
|
||||
default:
|
||||
// all other types are not allowed
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean doServerTeleport(Entity toTp, boolean conserveMotion, TravelSource source) {
|
||||
EntityPlayer player = toTp instanceof EntityPlayer ? (EntityPlayer) toTp : null;
|
||||
Optional<BlockCoord> travelDestination = TravelController.instance.findTravelDestination(player, source);
|
||||
@@ -77,6 +113,14 @@ public class PacketLongDistanceTravelEvent
|
||||
if (powerUse < 0) {
|
||||
return false;
|
||||
}
|
||||
if (player != null && player.getCurrentEquippedItem() != null
|
||||
&& player.getCurrentEquippedItem().getItem() instanceof IItemOfTravel) {
|
||||
int used = ((IItemOfTravel) player.getCurrentEquippedItem().getItem())
|
||||
.canExtractInternal(player.getCurrentEquippedItem(), powerUse);
|
||||
if (used != -1 && used != powerUse) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
TeleportEntityEvent evt = new TeleportEntityEvent(toTp, source, x, y, z);
|
||||
if (MinecraftForge.EVENT_BUS.post(evt)) {
|
||||
|
||||
@@ -13,9 +13,11 @@ import com.enderio.core.common.vecmath.Vector3d;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessage;
|
||||
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler;
|
||||
import cpw.mods.fml.common.network.simpleimpl.MessageContext;
|
||||
import crazypants.enderio.Log;
|
||||
import crazypants.enderio.api.teleport.IItemOfTravel;
|
||||
import crazypants.enderio.api.teleport.TeleportEntityEvent;
|
||||
import crazypants.enderio.api.teleport.TravelSource;
|
||||
import crazypants.enderio.teleport.TravelController;
|
||||
import io.netty.buffer.ByteBuf;
|
||||
|
||||
public class PacketTravelEvent implements IMessage, IMessageHandler<PacketTravelEvent, IMessage> {
|
||||
@@ -65,13 +67,31 @@ public class PacketTravelEvent implements IMessage, IMessageHandler<PacketTravel
|
||||
|
||||
@Override
|
||||
public IMessage onMessage(PacketTravelEvent message, MessageContext ctx) {
|
||||
Entity toTp = message.entityId == -1 ? ctx.getServerHandler().playerEntity
|
||||
: ctx.getServerHandler().playerEntity.worldObj.getEntityByID(message.entityId);
|
||||
if (message.entityId != -1) {
|
||||
// after checking the code base, this type of packet won't be sent at all,
|
||||
// so we can assume this to be an attempt to hack
|
||||
Log.LOGGER.warn(
|
||||
Log.securityMarker,
|
||||
"Player {} tried to illegally tp other entity {}.",
|
||||
ctx.getServerHandler().playerEntity.getGameProfile(),
|
||||
message.entityId);
|
||||
return null;
|
||||
}
|
||||
EntityPlayerMP toTp = ctx.getServerHandler().playerEntity;
|
||||
|
||||
int x = message.x, y = message.y, z = message.z;
|
||||
|
||||
TravelSource source = TravelSource.values()[message.source];
|
||||
|
||||
if (!TravelController.instance
|
||||
.validatePacketTravelEvent(toTp, x, y, z, message.powerUse, message.conserveMotion, source)) {
|
||||
Log.LOGGER.warn(
|
||||
Log.securityMarker,
|
||||
"Player {} tried to tp without valid prereq.",
|
||||
ctx.getServerHandler().playerEntity.getGameProfile());
|
||||
return null;
|
||||
}
|
||||
|
||||
doServerTeleport(toTp, x, y, z, message.powerUse, message.conserveMotion, source);
|
||||
|
||||
return null;
|
||||
|
||||
Reference in new issue
Block a user