From 1772b941149e7d93bcd16fbd70dec10c4c1d28ce Mon Sep 17 00:00:00 2001 From: jglrxavpok Date: Fri, 31 Jul 2020 22:31:58 +0200 Subject: [PATCH 1/4] Start of Permission API --- build.gradle | 4 + .../server/command/CommandSender.java | 76 ++++++++++++++ .../server/command/ConsoleSender.java | 13 +++ .../net/minestom/server/entity/Player.java | 8 ++ .../server/permission/BasicPermission.java | 14 +++ .../server/permission/Permission.java | 18 ++++ .../java/permissions/TestPermissions.java | 99 +++++++++++++++++++ 7 files changed, 232 insertions(+) create mode 100644 src/main/java/net/minestom/server/permission/BasicPermission.java create mode 100644 src/main/java/net/minestom/server/permission/Permission.java create mode 100644 src/test/java/permissions/TestPermissions.java diff --git a/build.gradle b/build.gradle index fc57cfc04..0164d3ef1 100644 --- a/build.gradle +++ b/build.gradle @@ -34,6 +34,10 @@ sourceSets { } } +test { + useJUnitPlatform() +} + dependencies { // Junit Testing Framework testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2' diff --git a/src/main/java/net/minestom/server/command/CommandSender.java b/src/main/java/net/minestom/server/command/CommandSender.java index 523471b7c..589edbf21 100644 --- a/src/main/java/net/minestom/server/command/CommandSender.java +++ b/src/main/java/net/minestom/server/command/CommandSender.java @@ -1,6 +1,9 @@ package net.minestom.server.command; import net.minestom.server.entity.Player; +import net.minestom.server.permission.Permission; + +import java.util.Collection; /** * Represent something which can send commands to the server @@ -27,6 +30,62 @@ public interface CommandSender { } } + /** + * Return all permissions associated to this command sender. + * The returned collection should be modified only by subclasses + * @return + */ + Collection getAllPermissions(); + + /** + * Adds a permission to this commandSender + * @param permission + */ + default void addPermission(Permission permission) { + getAllPermissions().add(permission); + } + + /** + * Removes a permission from this commandSender + * @param permission + */ + default void removePermission(Permission permission) { + getAllPermissions().remove(permission); + } + + /** + * Checks if the given permission is possessed by this command sender. + * Simple shortcut to
getAllPermissions().contains(permission)
for readability. + * @param p permission to check against + * @return + */ + default boolean hasPermission(Permission p) { + return getAllPermissions().contains(p); + } + + /** + * Checks if the given permission is possessed by this command sender. + * Will call {@link #hasPermission(Permission)} on all permissions that are an instance of permissionClass. + * If no matching permission is found, this result returns false. + * + * @param permissionClass + * @see #getAllPermissions() + * @return + */ + default boolean hasPermission(Class permissionClass) { + boolean result = true; + boolean foundPerm = false; + for(Permission p : getAllPermissions()) { + if(permissionClass.isInstance(p)) { + foundPerm = true; + result &= p.isValidFor(this); + } + } + if(!foundPerm) + return false; + return result; + } + /** * Get if the sender is a player * @@ -45,4 +104,21 @@ public interface CommandSender { return this instanceof ConsoleSender; } + /** + * Casts this object to a Player + * No checks are performed, {@link ClassCastException} can very much happen + * @see #isPlayer() + */ + default Player asPlayer() { + return (Player)this; + } + + /** + * Casts this object to a ConsoleSender + * No checks are performed, {@link ClassCastException} can very much happen + * @see #isConsole() + */ + default ConsoleSender asConsole() { + return (ConsoleSender)this; + } } diff --git a/src/main/java/net/minestom/server/command/ConsoleSender.java b/src/main/java/net/minestom/server/command/ConsoleSender.java index 445c02a5c..2f1e9d266 100644 --- a/src/main/java/net/minestom/server/command/ConsoleSender.java +++ b/src/main/java/net/minestom/server/command/ConsoleSender.java @@ -1,12 +1,25 @@ package net.minestom.server.command; +import net.minestom.server.permission.Permission; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; + /** * Represent the console when sending a command to the server */ public class ConsoleSender implements CommandSender { + private final List permissions = new LinkedList<>(); + @Override public void sendMessage(String message) { System.out.println(message); } + + @Override + public Collection getAllPermissions() { + return permissions; + } } diff --git a/src/main/java/net/minestom/server/entity/Player.java b/src/main/java/net/minestom/server/entity/Player.java index 6351b80be..09b5a7208 100644 --- a/src/main/java/net/minestom/server/entity/Player.java +++ b/src/main/java/net/minestom/server/entity/Player.java @@ -31,6 +31,7 @@ import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.login.JoinGamePacket; import net.minestom.server.network.packet.server.play.*; import net.minestom.server.network.player.PlayerConnection; +import net.minestom.server.permission.Permission; import net.minestom.server.recipe.Recipe; import net.minestom.server.recipe.RecipeManager; import net.minestom.server.resourcepack.ResourcePack; @@ -138,6 +139,8 @@ public class Player extends LivingEntity implements CommandSender { // Tick related private final PlayerTickEvent playerTickEvent = new PlayerTickEvent(this); + private final List permissions = new LinkedList<>(); + public Player(UUID uuid, String username, PlayerConnection playerConnection) { super(EntityType.PLAYER); this.uuid = uuid; // Override Entity#uuid defined in the constructor @@ -627,6 +630,11 @@ public class Player extends LivingEntity implements CommandSender { sendMessage(ColoredText.of(message)); } + @Override + public Collection getAllPermissions() { + return permissions; + } + /** * Send a message to the player * diff --git a/src/main/java/net/minestom/server/permission/BasicPermission.java b/src/main/java/net/minestom/server/permission/BasicPermission.java new file mode 100644 index 000000000..c79919723 --- /dev/null +++ b/src/main/java/net/minestom/server/permission/BasicPermission.java @@ -0,0 +1,14 @@ +package net.minestom.server.permission; + +import net.minestom.server.command.CommandSender; + +/** + * Basic Permission implementation that only requires the permission to be given to a player to be considered applied + * (eg. no arguments) + */ +public class BasicPermission implements Permission { + @Override + public boolean isValidFor(CommandSender commandSender) { + return true; + } +} diff --git a/src/main/java/net/minestom/server/permission/Permission.java b/src/main/java/net/minestom/server/permission/Permission.java new file mode 100644 index 000000000..1bd40a25e --- /dev/null +++ b/src/main/java/net/minestom/server/permission/Permission.java @@ -0,0 +1,18 @@ +package net.minestom.server.permission; + +import net.minestom.server.command.CommandSender; + +/** + * Representation of a permission granted to a CommandSender + */ +public interface Permission { + + /** + * Does the given commandSender have the permission represented by this object? + * @param commandSender + * @return true if the commandSender possesses this permission + */ + boolean isValidFor(CommandSender commandSender); + + // TODO: Serialization? +} diff --git a/src/test/java/permissions/TestPermissions.java b/src/test/java/permissions/TestPermissions.java new file mode 100644 index 000000000..e7c448414 --- /dev/null +++ b/src/test/java/permissions/TestPermissions.java @@ -0,0 +1,99 @@ +package permissions; + +import net.minestom.server.MinecraftServer; +import net.minestom.server.command.CommandSender; +import net.minestom.server.entity.Player; +import net.minestom.server.permission.Permission; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +// TODO: more tests +public class TestPermissions { + + private Player player; + + @BeforeEach + public void init() { + MinecraftServer.init(); // for entity manager + player = new Player(UUID.randomUUID(), "TestPlayer", null) { + @Override + protected void playerConnectionInit() {} + + @Override + public boolean isOnline() { + return false; + } + }; + } + + @Test + public void noPermission() { + assertFalse(player.hasPermission(Permission.class)); + } + + class PermTest1 implements Permission { + @Override + public boolean isValidFor(CommandSender commandSender) { + return true; + } + } + class PermTest2 implements Permission { + @Override + public boolean isValidFor(CommandSender commandSender) { + return true; + } + } + + @Test + public void hasPermissionClass() { + assertFalse(player.hasPermission(Permission.class)); + player.addPermission(new PermTest1()); + assertTrue(player.hasPermission(PermTest1.class)); + assertFalse(player.hasPermission(PermTest2.class)); + assertTrue(player.hasPermission(Permission.class)); // allow superclasses + + player.addPermission(new PermTest2()); + assertTrue(player.hasPermission(PermTest2.class)); + } + + class BooleanPerm implements Permission { + private final boolean value; + + BooleanPerm(boolean v) { + this.value = v; + } + + @Override + public boolean isValidFor(CommandSender commandSender) { + return value; + } + } + + @Test + public void hasTwoPermissionsOfSameClassButContradictEachOther() { + player.addPermission(new BooleanPerm(true)); + assertTrue(player.hasPermission(BooleanPerm.class)); + player.addPermission(new BooleanPerm(false)); + assertFalse(player.hasPermission(BooleanPerm.class)); // all permissions must be valid + } + + @Test + public void singlePermission() { + Permission p = commandSender -> true; + player.addPermission(p); + assertTrue(p.isValidFor(player)); + assertTrue(player.hasPermission(p)); + assertTrue(player.hasPermission(Permission.class)); + } + + @AfterEach + public void cleanup() { + + } +} From 4782d6e899a6687599e25039155c8c83094a176a Mon Sep 17 00:00:00 2001 From: jglrxavpok Date: Fri, 31 Jul 2020 22:37:33 +0200 Subject: [PATCH 2/4] Fixed inconsistency between hasPermission(Permission) and hasPermission(Class) --- .../java/net/minestom/server/command/CommandSender.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/minestom/server/command/CommandSender.java b/src/main/java/net/minestom/server/command/CommandSender.java index 589edbf21..93e218d5c 100644 --- a/src/main/java/net/minestom/server/command/CommandSender.java +++ b/src/main/java/net/minestom/server/command/CommandSender.java @@ -55,17 +55,17 @@ public interface CommandSender { /** * Checks if the given permission is possessed by this command sender. - * Simple shortcut to
getAllPermissions().contains(permission)
for readability. + * Simple shortcut to
getAllPermissions().contains(permission) && permission.isValidFor(this)
for readability. * @param p permission to check against * @return */ default boolean hasPermission(Permission p) { - return getAllPermissions().contains(p); + return getAllPermissions().contains(p) && p.isValidFor(this); } /** * Checks if the given permission is possessed by this command sender. - * Will call {@link #hasPermission(Permission)} on all permissions that are an instance of permissionClass. + * Will call {@link Permission#isValidFor(Permission)} on all permissions that are an instance of permissionClass. * If no matching permission is found, this result returns false. * * @param permissionClass From 5a8f58d9dd3dfc6c6c200e8c798c65f804f2d32e Mon Sep 17 00:00:00 2001 From: jglrxavpok Date: Fri, 31 Jul 2020 22:38:03 +0200 Subject: [PATCH 3/4] oops wrong javadoc --- src/main/java/net/minestom/server/command/CommandSender.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/command/CommandSender.java b/src/main/java/net/minestom/server/command/CommandSender.java index 93e218d5c..6ca2ec5fd 100644 --- a/src/main/java/net/minestom/server/command/CommandSender.java +++ b/src/main/java/net/minestom/server/command/CommandSender.java @@ -65,7 +65,7 @@ public interface CommandSender { /** * Checks if the given permission is possessed by this command sender. - * Will call {@link Permission#isValidFor(Permission)} on all permissions that are an instance of permissionClass. + * Will call {@link Permission#isValidFor(CommandSender)} on all permissions that are an instance of permissionClass. * If no matching permission is found, this result returns false. * * @param permissionClass From d2df5fdc60a90b4c302a31ea044f5fe96aee6db8 Mon Sep 17 00:00:00 2001 From: jglrxavpok Date: Mon, 10 Aug 2020 21:42:54 +0200 Subject: [PATCH 4/4] Serialization methods --- .../server/permission/Permission.java | 19 ++++++++++++++++++- .../java/permissions/TestPermissions.java | 3 +++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main/java/net/minestom/server/permission/Permission.java b/src/main/java/net/minestom/server/permission/Permission.java index 1bd40a25e..8f7e31d12 100644 --- a/src/main/java/net/minestom/server/permission/Permission.java +++ b/src/main/java/net/minestom/server/permission/Permission.java @@ -1,10 +1,14 @@ package net.minestom.server.permission; import net.minestom.server.command.CommandSender; +import net.minestom.server.data.Data; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Representation of a permission granted to a CommandSender */ +@FunctionalInterface public interface Permission { /** @@ -14,5 +18,18 @@ public interface Permission { */ boolean isValidFor(CommandSender commandSender); - // TODO: Serialization? + /** + * Writes any required data for this permission inside the given destination + * @param destination Data to write to + */ + default void write(@NotNull Data destination) {} + + /** + * Reads any required data for this permission from the given destination + * @param source Data to read from + * @return this for chaining + */ + default Permission read(@Nullable Data source) { + return this; + } } diff --git a/src/test/java/permissions/TestPermissions.java b/src/test/java/permissions/TestPermissions.java index e7c448414..e2b87e416 100644 --- a/src/test/java/permissions/TestPermissions.java +++ b/src/test/java/permissions/TestPermissions.java @@ -2,8 +2,11 @@ package permissions; import net.minestom.server.MinecraftServer; import net.minestom.server.command.CommandSender; +import net.minestom.server.data.Data; import net.minestom.server.entity.Player; import net.minestom.server.permission.Permission; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test;