From 27ebd0e9b9191686145f1623eb6bec6964300725 Mon Sep 17 00:00:00 2001 From: LatvianModder Date: Fri, 4 Nov 2016 22:36:30 +0200 Subject: [PATCH] Added PermissionAPI (#3155) --- .../permission/DefaultPermissionHandler.java | 94 ++++++++++ .../permission/DefaultPermissionLevel.java | 35 ++++ .../server/permission/IPermissionHandler.java | 51 +++++ .../server/permission/PermissionAPI.java | 97 ++++++++++ .../permission/context/AreaContext.java | 50 +++++ .../permission/context/BlockPosContext.java | 80 ++++++++ .../server/permission/context/Context.java | 87 +++++++++ .../server/permission/context/ContextKey.java | 67 +++++++ .../permission/context/ContextKeys.java | 46 +++++ .../server/permission/context/IContext.java | 56 ++++++ .../permission/context/PlayerContext.java | 46 +++++ .../permission/context/TargetContext.java | 49 +++++ .../permission/context/WorldContext.java | 49 +++++ .../permission/context/package-info.java | 22 +++ .../server/permission/package-info.java | 22 +++ .../minecraftforge/test/PermissionTest.java | 177 ++++++++++++++++++ 16 files changed, 1028 insertions(+) create mode 100644 src/main/java/net/minecraftforge/server/permission/DefaultPermissionHandler.java create mode 100644 src/main/java/net/minecraftforge/server/permission/DefaultPermissionLevel.java create mode 100644 src/main/java/net/minecraftforge/server/permission/IPermissionHandler.java create mode 100644 src/main/java/net/minecraftforge/server/permission/PermissionAPI.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/AreaContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/BlockPosContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/Context.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/ContextKey.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/ContextKeys.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/IContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/PlayerContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/TargetContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/WorldContext.java create mode 100644 src/main/java/net/minecraftforge/server/permission/context/package-info.java create mode 100644 src/main/java/net/minecraftforge/server/permission/package-info.java create mode 100644 src/test/java/net/minecraftforge/test/PermissionTest.java diff --git a/src/main/java/net/minecraftforge/server/permission/DefaultPermissionHandler.java b/src/main/java/net/minecraftforge/server/permission/DefaultPermissionHandler.java new file mode 100644 index 000000000..6dc667749 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/DefaultPermissionHandler.java @@ -0,0 +1,94 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission; + +import com.mojang.authlib.GameProfile; +import net.minecraft.server.MinecraftServer; +import net.minecraftforge.fml.common.FMLCommonHandler; +import net.minecraftforge.server.permission.context.IContext; + +import javax.annotation.Nullable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; + +/** + * Default implementation of PermissionAPI. + * {@link #hasPermission(GameProfile, String, IContext)} is based on DefaultPermissionLevel + * + * @see IPermissionHandler + */ +public enum DefaultPermissionHandler implements IPermissionHandler +{ + INSTANCE; + private static final HashMap PERMISSION_LEVEL_MAP = new HashMap(); + private static final HashMap DESCRIPTION_MAP = new HashMap(); + + @Override + public void registerNode(String node, DefaultPermissionLevel level, String desc) + { + PERMISSION_LEVEL_MAP.put(node, level); + + if(!desc.isEmpty()) + { + DESCRIPTION_MAP.put(node, desc); + } + } + + @Override + public Collection getRegisteredNodes() + { + return Collections.unmodifiableSet(PERMISSION_LEVEL_MAP.keySet()); + } + + @Override + public boolean hasPermission(GameProfile profile, String node, @Nullable IContext context) + { + DefaultPermissionLevel level = getDefaultPermissionLevel(node); + + if(level == DefaultPermissionLevel.NONE) + { + return false; + } + else if(level == DefaultPermissionLevel.ALL) + { + return true; + } + + MinecraftServer server = FMLCommonHandler.instance().getMinecraftServerInstance(); + return server != null && server.getPlayerList().canSendCommands(profile); + } + + @Override + public String getNodeDescription(String node) + { + String desc = DESCRIPTION_MAP.get(node); + return desc == null ? "" : desc; + } + + /** + * @return The default permission level of a node. If the permission isn't registred, it will return NONE + */ + public DefaultPermissionLevel getDefaultPermissionLevel(String node) + { + DefaultPermissionLevel level = PERMISSION_LEVEL_MAP.get(node); + return level == null ? DefaultPermissionLevel.NONE : level; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/DefaultPermissionLevel.java b/src/main/java/net/minecraftforge/server/permission/DefaultPermissionLevel.java new file mode 100644 index 000000000..30593fa92 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/DefaultPermissionLevel.java @@ -0,0 +1,35 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission; + +/** + * + * + * + * + * + *
LevelPlayerOP
ALLtruetrue
OPfalsetrue
NONEfalsefalse
+ */ +public enum DefaultPermissionLevel +{ + ALL, + OP, + NONE +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/IPermissionHandler.java b/src/main/java/net/minecraftforge/server/permission/IPermissionHandler.java new file mode 100644 index 000000000..fa772efdd --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/IPermissionHandler.java @@ -0,0 +1,51 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission; + +import com.mojang.authlib.GameProfile; +import net.minecraftforge.server.permission.context.IContext; + +import javax.annotation.Nullable; +import java.util.Collection; + +public interface IPermissionHandler +{ + /** + * Use {@link PermissionAPI#registerNode(String, DefaultPermissionLevel, String)} + */ + void registerNode(String node, DefaultPermissionLevel level, String desc); + + /** + * @return Immutable collection of all registered nodes + */ + Collection getRegisteredNodes(); + + /** + * Use {@link PermissionAPI#hasPermission(GameProfile, String, IContext)} + */ + boolean hasPermission(GameProfile profile, String node, @Nullable IContext context); + + /** + * @param node Permission node + * @return Description of the node. "" in case this node doesn't have a decription + * @see #registerNode(String, DefaultPermissionLevel, String) + */ + String getNodeDescription(String node); +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/PermissionAPI.java b/src/main/java/net/minecraftforge/server/permission/PermissionAPI.java new file mode 100644 index 000000000..4349bcb79 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/PermissionAPI.java @@ -0,0 +1,97 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission; + +import com.google.common.base.Preconditions; +import com.mojang.authlib.GameProfile; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraftforge.fml.common.FMLLog; +import net.minecraftforge.fml.common.Loader; +import net.minecraftforge.fml.common.LoaderState; +import net.minecraftforge.server.permission.context.IContext; +import net.minecraftforge.server.permission.context.PlayerContext; +import org.apache.logging.log4j.Level; + +import javax.annotation.Nullable; + +public class PermissionAPI +{ + private static IPermissionHandler permissionHandler = DefaultPermissionHandler.INSTANCE; + + /** + * Only use this in PreInit state! + */ + public static void setPermissionHandler(IPermissionHandler handler) + { + Preconditions.checkNotNull(handler, "Permission handler can't be null!"); + Preconditions.checkState(Loader.instance().getLoaderState().ordinal() <= LoaderState.PREINITIALIZATION.ordinal(), "Can't register after IPermissionHandler PreInit!"); + FMLLog.log(Level.WARN, "Replacing " + permissionHandler.getClass().getName() + " with " + handler.getClass().getName()); + permissionHandler = handler; + } + + public static IPermissionHandler getPermissionHandler() + { + return permissionHandler; + } + + /** + * Only use this after PreInit state! + * + * @param node Permission node, best if it's lowercase and contains '.' (e.g. "modid.subgroup.permission_id") + * @param level Default permission level for this node. If not isn't registered, it's level is going to be 'NONE' + * @param desc Optional description of the node + */ + public static String registerNode(String node, DefaultPermissionLevel level, String desc) + { + Preconditions.checkNotNull(node, "Permission node can't be null!"); + Preconditions.checkNotNull(level, "Permission level can't be null!"); + Preconditions.checkNotNull(desc, "Permission description can't be null!"); + Preconditions.checkArgument(!node.isEmpty(), "Permission node can't be empty!"); + Preconditions.checkState(Loader.instance().getLoaderState().ordinal() > LoaderState.PREINITIALIZATION.ordinal(), "Can't register permission nodes before Init!"); + permissionHandler.registerNode(node, level, desc); + return node; + } + + /** + * @param profile GameProfile of the player who is requesting permission. The player doesn't have to be online + * @param node Permission node. See {@link #registerNode(String, DefaultPermissionLevel, String)} + * @param context Context for this permission. Highly recommended to not be null. See {@link IContext} + * @return true, if player has permission, false if he does not. + * @see DefaultPermissionHandler + */ + public static boolean hasPermission(GameProfile profile, String node, @Nullable IContext context) + { + Preconditions.checkNotNull(profile, "GameProfile can't be null!"); + Preconditions.checkNotNull(node, "Permission node can't be null!"); + Preconditions.checkArgument(!node.isEmpty(), "Permission node can't be empty!"); + return permissionHandler.hasPermission(profile, node, context); + } + + /** + * Shortcut method using EntityPlayer and creating PlayerContext + * + * @see PermissionAPI#hasPermission(GameProfile, String, IContext) + */ + public static boolean hasPermission(EntityPlayer player, String node) + { + Preconditions.checkNotNull(player, "Player can't be null!"); + return hasPermission(player.getGameProfile(), node, new PlayerContext(player)); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/AreaContext.java b/src/main/java/net/minecraftforge/server/permission/context/AreaContext.java new file mode 100644 index 000000000..df82e5ed3 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/AreaContext.java @@ -0,0 +1,50 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import com.google.common.base.Preconditions; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.math.AxisAlignedBB; + +import javax.annotation.Nullable; + +public class AreaContext extends PlayerContext +{ + private final AxisAlignedBB area; + + public AreaContext(EntityPlayer ep, AxisAlignedBB aabb) + { + super(ep); + area = Preconditions.checkNotNull(aabb, "AxisAlignedBB can't be null in AreaContext!"); + } + + @Override + @Nullable + public T get(ContextKey key) + { + return key.equals(ContextKeys.AREA) ? (T) area : super.get(key); + } + + @Override + protected boolean covers(ContextKey key) + { + return key.equals(ContextKeys.AREA); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/BlockPosContext.java b/src/main/java/net/minecraftforge/server/permission/context/BlockPosContext.java new file mode 100644 index 000000000..88a0eee2c --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/BlockPosContext.java @@ -0,0 +1,80 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import com.google.common.base.Preconditions; +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; + +import javax.annotation.Nullable; + +public class BlockPosContext extends PlayerContext +{ + private final BlockPos blockPos; + private IBlockState blockState; + private EnumFacing facing; + + public BlockPosContext(EntityPlayer ep, BlockPos pos, @Nullable IBlockState state, @Nullable EnumFacing f) + { + super(ep); + blockPos = Preconditions.checkNotNull(pos, "BlockPos can't be null in BlockPosContext!"); + blockState = state; + facing = f; + } + + public BlockPosContext(EntityPlayer ep, ChunkPos pos) + { + this(ep, new BlockPos((pos.chunkXPos << 4) + 8, 0, (pos.chunkZPos << 4) + 8), null, null); + } + + @Override + @Nullable + public T get(ContextKey key) + { + if(key.equals(ContextKeys.POS)) + { + return (T) blockPos; + } + else if(key.equals(ContextKeys.BLOCK_STATE)) + { + if(blockState == null) + { + blockState = getWorld().getBlockState(blockPos); + } + + return (T) blockState; + } + else if(key.equals(ContextKeys.FACING)) + { + return (T) facing; + } + + return super.get(key); + } + + @Override + protected boolean covers(ContextKey key) + { + return key.equals(ContextKeys.POS) || key.equals(ContextKeys.BLOCK_STATE) || (facing != null && key.equals(ContextKeys.FACING)); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/Context.java b/src/main/java/net/minecraftforge/server/permission/context/Context.java new file mode 100644 index 000000000..e1e450552 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/Context.java @@ -0,0 +1,87 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +public class Context implements IContext +{ + private Map, Object> map; + + @Override + @Nullable + public World getWorld() + { + return null; + } + + @Override + @Nullable + public EntityPlayer getPlayer() + { + return null; + } + + @Override + @Nullable + public T get(ContextKey key) + { + return map == null || map.isEmpty() ? null : (T) map.get(key); + } + + @Override + public boolean has(ContextKey key) + { + return covers(key) || (map != null && !map.isEmpty() && map.containsKey(key)); + } + + /** + * Sets Context object + * + * @param key Context key + * @param obj Context object. Can be null + * @return itself, for easy context chaining + */ + public Context set(ContextKey key, @Nullable T obj) + { + if(covers(key)) + { + return this; + } + + if(map == null) + { + map = new HashMap, Object>(); + } + + map.put(key, obj); + return this; + } + + protected boolean covers(ContextKey key) + { + return false; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/ContextKey.java b/src/main/java/net/minecraftforge/server/permission/context/ContextKey.java new file mode 100644 index 000000000..0b9129852 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/ContextKey.java @@ -0,0 +1,67 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import com.google.common.base.Preconditions; + +public final class ContextKey +{ + private final String ID; + private final Class typeClass; + + public static ContextKey create(String id, Class c) + { + Preconditions.checkNotNull(id, "ContextKey's ID can't be null!"); + Preconditions.checkNotNull(c, "ContextKey's Type can't be null!"); + + if(id.isEmpty()) + { + throw new IllegalArgumentException("ContextKey's ID can't be blank!"); + } + + return new ContextKey(id, c); + } + + private ContextKey(String id, Class c) + { + ID = id; + typeClass = c; + } + + public String toString() + { + return ID; + } + + public int hashCode() + { + return ID.hashCode(); + } + + public boolean equals(Object o) + { + return o == this || (o != null && o.toString().equals(ID)); + } + + public Class getTypeClass() + { + return typeClass; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/ContextKeys.java b/src/main/java/net/minecraftforge/server/permission/context/ContextKeys.java new file mode 100644 index 000000000..11097104f --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/ContextKeys.java @@ -0,0 +1,46 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import net.minecraft.block.state.IBlockState; +import net.minecraft.entity.Entity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.AxisAlignedBB; +import net.minecraft.util.math.BlockPos; + +/** + * Some default context keys, for easier compatibility + */ +public class ContextKeys +{ + /** + * BlockPos for interacting, breaking and other permissions + */ + public static final ContextKey POS = ContextKey.create("pos", BlockPos.class); + + /** + * The entity can be anything that gets interacted with - a sheep when you try to dye it, skeleton that you attack, etc. + */ + public static final ContextKey TARGET = ContextKey.create("target", Entity.class); + + public static final ContextKey FACING = ContextKey.create("facing", EnumFacing.class); + public static final ContextKey AREA = ContextKey.create("area", AxisAlignedBB.class); + public static final ContextKey BLOCK_STATE = ContextKey.create("blockstate", IBlockState.class); +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/IContext.java b/src/main/java/net/minecraftforge/server/permission/context/IContext.java new file mode 100644 index 000000000..becbeeb31 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/IContext.java @@ -0,0 +1,56 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +/** + * Use {@link BlockPosContext} or {@link PlayerContext} when possible + */ +public interface IContext +{ + /** + * World from where permission is requested. Can be null + */ + @Nullable + World getWorld(); + + /** + * @return Player requesting permission. Can be null + */ + @Nullable + EntityPlayer getPlayer(); + + /** + * @param key Context key + * @return Context object + */ + @Nullable + T get(ContextKey key); + + /** + * @param key Context key + * @return true if context contains this key + */ + boolean has(ContextKey key); +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/PlayerContext.java b/src/main/java/net/minecraftforge/server/permission/context/PlayerContext.java new file mode 100644 index 000000000..c522787b4 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/PlayerContext.java @@ -0,0 +1,46 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import com.google.common.base.Preconditions; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +public class PlayerContext extends Context +{ + private final EntityPlayer player; + + public PlayerContext(EntityPlayer ep) + { + player = Preconditions.checkNotNull(ep, "Player can't be null in PlayerContext!"); + } + + @Override + public World getWorld() + { + return player.getEntityWorld(); + } + + @Override + public EntityPlayer getPlayer() + { + return player; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/TargetContext.java b/src/main/java/net/minecraftforge/server/permission/context/TargetContext.java new file mode 100644 index 000000000..7e8ef52b0 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/TargetContext.java @@ -0,0 +1,49 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.EntityPlayer; + +import javax.annotation.Nullable; + +public class TargetContext extends PlayerContext +{ + private final Entity target; + + public TargetContext(EntityPlayer ep, @Nullable Entity entity) + { + super(ep); + target = entity; + } + + @Override + @Nullable + public T get(ContextKey key) + { + return key.equals(ContextKeys.TARGET) ? (T) target : super.get(key); + } + + @Override + protected boolean covers(ContextKey key) + { + return target != null && key.equals(ContextKeys.TARGET); + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/WorldContext.java b/src/main/java/net/minecraftforge/server/permission/context/WorldContext.java new file mode 100644 index 000000000..ced75d285 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/WorldContext.java @@ -0,0 +1,49 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +package net.minecraftforge.server.permission.context; + +import com.google.common.base.Preconditions; +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.world.World; + +import javax.annotation.Nullable; + +public class WorldContext extends Context +{ + private final World world; + + public WorldContext(World w) + { + world = Preconditions.checkNotNull(w, "World can't be null in WorldContext!"); + } + + @Override + public World getWorld() + { + return world; + } + + @Override + @Nullable + public EntityPlayer getPlayer() + { + return null; + } +} \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/context/package-info.java b/src/main/java/net/minecraftforge/server/permission/context/package-info.java new file mode 100644 index 000000000..35acccc32 --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/context/package-info.java @@ -0,0 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@javax.annotation.ParametersAreNonnullByDefault +@mcp.MethodsReturnNonnullByDefault +package net.minecraftforge.server.permission.context; \ No newline at end of file diff --git a/src/main/java/net/minecraftforge/server/permission/package-info.java b/src/main/java/net/minecraftforge/server/permission/package-info.java new file mode 100644 index 000000000..706a0accb --- /dev/null +++ b/src/main/java/net/minecraftforge/server/permission/package-info.java @@ -0,0 +1,22 @@ +/* + * Minecraft Forge + * Copyright (c) 2016. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1 + * of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +@javax.annotation.ParametersAreNonnullByDefault +@mcp.MethodsReturnNonnullByDefault +package net.minecraftforge.server.permission; \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/test/PermissionTest.java b/src/test/java/net/minecraftforge/test/PermissionTest.java new file mode 100644 index 000000000..61afb5c0b --- /dev/null +++ b/src/test/java/net/minecraftforge/test/PermissionTest.java @@ -0,0 +1,177 @@ +package net.minecraftforge.test; + +import net.minecraft.block.Block; +import net.minecraft.block.state.IBlockState; +import net.minecraft.command.CommandBase; +import net.minecraft.command.CommandException; +import net.minecraft.command.ICommandSender; +import net.minecraft.command.WrongUsageException; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.server.MinecraftServer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.text.TextComponentString; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.server.permission.DefaultPermissionLevel; +import net.minecraftforge.server.permission.PermissionAPI; +import net.minecraftforge.server.permission.context.BlockPosContext; +import net.minecraftforge.server.permission.context.ContextKey; + +@Mod(modid = PermissionTest.MOD_ID, name = "PermissionTest", version = "1.0.0") +public class PermissionTest +{ + public static final String MOD_ID = "PermissionTest"; + + @Mod.Instance(PermissionTest.MOD_ID) + public static PermissionTest inst; + + @Mod.EventHandler + public void onInit(FMLInitializationEvent event) + { + Permissions.init(); + } + + @Mod.EventHandler + public void onServerStarted(FMLServerStartingEvent event) + { + event.registerServerCommand(new CommandPermissionTest()); + } + + public static class Permissions + { + public static final String CLAIM_CHUNK = "testmod.chunk.claim"; + public static final String UNCLAIM_CHUNK = "testmod.chunk.unclaim"; + public static final String SET_BLOCK = "testmod.block.set"; + public static final String READ_TILE = "testmod.tileentity.read"; + + public static void init() + { + PermissionAPI.registerNode(CLAIM_CHUNK, DefaultPermissionLevel.ALL, "Node for claiming chunks"); + PermissionAPI.registerNode(UNCLAIM_CHUNK, DefaultPermissionLevel.ALL, "Node for unclaiming chunks"); + PermissionAPI.registerNode(SET_BLOCK, DefaultPermissionLevel.OP, "Node for setting blocks with a command"); + PermissionAPI.registerNode(READ_TILE, DefaultPermissionLevel.NONE, "Node for reading and printing TileEntity data"); + } + } + + public static class ContextKeys + { + public static final ContextKey TILE_ENTITY = ContextKey.create("tile_entity", TileEntity.class); + } + + public static class CommandPermissionTest extends CommandBase + { + @Override + public String getCommandName() + { + return "permission_test"; + } + + @Override + public String getCommandUsage(ICommandSender sender) + { + return "commands.permission_test.usage"; + } + + @Override + public boolean checkPermission(MinecraftServer server, ICommandSender sender) + { + return true; + } + + @Override + public void execute(MinecraftServer server, ICommandSender sender, String[] args) throws CommandException + { + EntityPlayerMP player = getCommandSenderAsPlayer(sender); + + if(args.length < 1) + { + sender.addChatMessage(new TextComponentString("claim, unclaim, setblock, read_tile")); + return; + } + + //Example using BlockPosContext with ChunkPos and permission available to players by default + boolean b = args[0].equals("claim"); + if(b || args[0].equals("unclaim")) + { + ChunkPos chunkPos = new ChunkPos(parseInt(args[1]), parseInt(args[2])); + + if(PermissionAPI.hasPermission(player.getGameProfile(), b ? Permissions.CLAIM_CHUNK : Permissions.UNCLAIM_CHUNK, new BlockPosContext(player, chunkPos))) + { + if(b) + { + //claim chunk + sender.addChatMessage(new TextComponentString("Chunk claimed!")); + } + else + { + //unclaim chunk + sender.addChatMessage(new TextComponentString("Chunk unclaimed!")); + } + } + else + { + throw new CommandException("commands.generic.permission"); + } + } + //Example using BlockPosContext and permission available to only OPs by default + else if(args[0].equals("setblock")) + { + if(args.length < 5) + { + throw new WrongUsageException("commands.setblock.usage"); + } + + BlockPos blockpos = parseBlockPos(sender, args, 1, false); + Block block = CommandBase.getBlockByText(sender, args[4]); + int i = 0; + + if(args.length >= 6) + { + i = parseInt(args[5], 0, 15); + } + + if(!player.worldObj.isBlockLoaded(blockpos)) + { + throw new CommandException("commands.setblock.outOfWorld"); + } + else + { + IBlockState state = block.getStateFromMeta(i); + + if(!PermissionAPI.hasPermission(player.getGameProfile(), Permissions.SET_BLOCK, new BlockPosContext(player, blockpos, state, null))) + { + throw new CommandException("commands.generic.permission"); + } + else if(!player.worldObj.setBlockState(blockpos, state, 2)) + { + throw new CommandException("commands.setblock.noChange"); + } + } + } + //Example using custom ContextKey and permission available to only OPs by default + else if(args[0].equals("read_tile")) + { + BlockPos blockpos = parseBlockPos(sender, args, 1, false); + TileEntity tileEntity = player.worldObj.getTileEntity(blockpos); + + if(PermissionAPI.hasPermission(player.getGameProfile(), Permissions.READ_TILE, new BlockPosContext(player, blockpos, null, null).set(ContextKeys.TILE_ENTITY, tileEntity))) + { + NBTTagCompound tag = tileEntity == null ? null : tileEntity.serializeNBT(); + sender.addChatMessage(new TextComponentString(String.valueOf(tag))); + } + else + { + throw new CommandException("commands.generic.permission"); + } + } + else + { + throw new CommandException("commands.generic.permission"); + } + } + } +} \ No newline at end of file