- removed fabric permission api, done by cloud now

- updated GeyserPermission to 2.0
- removed mod platform specific permission checkers

TODO:
- test neoforge permission registration event
- fix: exception handling
This commit is contained in:
onebeastchris 2024-03-08 19:42:05 +01:00
parent f2a3feac05
commit 677f79dbd7
13 changed files with 49 additions and 96 deletions

View File

@ -30,9 +30,10 @@ import org.geysermc.geyser.api.util.TriState;
/**
* Fired by anything that wishes to gather permission nodes and defaults.
* <br><br>
* <p>
* This event is not guaranteed to be fired, as certain Geyser platforms do not have a native permission system.
* It can be expected to fire on Geyser-Spigot and Geyser-Standalone.
* It can be expected to fire on Geyser-Spigot, Geyser-NeoForge and Geyser-Standalone. Note: NeoForge allows registering permissions,
* but does so without registering default values.
* It may still be fired on other platforms due to a 3rd party.
*/
public interface GeyserRegisterPermissionsEvent extends Event {

View File

@ -23,9 +23,6 @@ dependencies {
exclude(group = "io.netty.incubator")
}
modImplementation(libs.fabric.permissions)
include(libs.fabric.permissions)
modImplementation(libs.cloud.fabric)
include(libs.cloud.fabric)
}

View File

@ -25,7 +25,6 @@
package org.geysermc.geyser.platform.fabric;
import me.lucko.fabric.api.permissions.v0.Permissions;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
@ -33,7 +32,6 @@ import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.entity.player.Player;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.command.CommandSourceConverter;
@ -67,7 +65,6 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit
this.onGeyserInitialize();
// TODO: verify
var sourceConverter = CommandSourceConverter.layered(
CommandSourceStack.class,
id -> getServer().getPlayerList().getPlayer(id),
@ -82,8 +79,4 @@ public class GeyserFabricBootstrap extends GeyserModBootstrap implements ModInit
this.setCommandRegistry(new CommandRegistry(GeyserImpl.getInstance(), cloud));
}
@Override
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode) {
return Permissions.check(source, permissionNode, source.getServer().getOperatorUserPermissionLevel());
}
}

View File

@ -34,7 +34,6 @@ import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.command.CommandSourceConverter;
@ -49,8 +48,6 @@ import org.incendo.cloud.neoforge.NeoForgeServerCommandManager;
@Mod(ModConstants.MOD_ID)
public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
private final GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
public GeyserNeoForgeBootstrap() {
super(new GeyserNeoForgePlatform());
@ -61,11 +58,12 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
NeoForge.EVENT_BUS.addListener(this::onServerStopping);
NeoForge.EVENT_BUS.addListener(this::onPlayerJoin);
NeoForge.EVENT_BUS.addListener(this.permissionHandler::onPermissionGather);
GeyserNeoForgePermissionHandler permissionHandler = new GeyserNeoForgePermissionHandler();
NeoForge.EVENT_BUS.addListener(permissionHandler::onPermissionGather);
this.onGeyserInitialize();
// TODO: verify; idek how to make permissions on neoforge work with this...
var sourceConverter = CommandSourceConverter.layered(
CommandSourceStack.class,
id -> getServer().getPlayerList().getPlayer(id),
@ -92,10 +90,4 @@ public class GeyserNeoForgeBootstrap extends GeyserModBootstrap {
private void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) {
GeyserModUpdateListener.onPlayReady(event.getEntity());
}
@Override
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode) {
return this.permissionHandler.hasPermission(source, permissionNode);
}
}

View File

@ -25,23 +25,16 @@
package org.geysermc.geyser.platform.neoforge;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.level.ServerPlayer;
import net.neoforged.neoforge.server.permission.PermissionAPI;
import net.neoforged.neoforge.server.permission.events.PermissionGatherEvent;
import net.neoforged.neoforge.server.permission.nodes.PermissionDynamicContextKey;
import net.neoforged.neoforge.server.permission.nodes.PermissionNode;
import net.neoforged.neoforge.server.permission.nodes.PermissionType;
import net.neoforged.neoforge.server.permission.nodes.PermissionTypes;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.Constants;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.command.CommandRegistry;
import org.geysermc.geyser.api.event.lifecycle.GeyserRegisterPermissionsEvent;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;
public class GeyserNeoForgePermissionHandler {
@ -63,49 +56,10 @@ public class GeyserNeoForgePermissionHandler {
}
}
private final Map<String, PermissionNode<Boolean>> permissionNodes = new HashMap<>();
public void onPermissionGather(PermissionGatherEvent.Nodes event) {
this.registerNode(Constants.UPDATE_PERMISSION, event);
CommandRegistry commandManager = GeyserImpl.getInstance().commandRegistry();
for (Map.Entry<String, Command> entry : commandManager.commands().entrySet()) {
Command command = entry.getValue();
// Don't register aliases
if (!command.name().equals(entry.getKey())) {
continue;
}
this.registerNode(command.permission(), event);
}
for (Map<String, Command> commands : commandManager.extensionCommands().values()) {
for (Map.Entry<String, Command> entry : commands.entrySet()) {
Command command = entry.getValue();
// Don't register aliases
if (!command.name().equals(entry.getKey())) {
continue;
}
this.registerNode(command.permission(), event);
}
}
}
public boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode) {
ServerPlayer player = source.getPlayer();
if (!source.isPlayer() || player == null) {
return true;
}
PermissionNode<Boolean> node = this.permissionNodes.get(permissionNode);
if (node == null) {
GeyserImpl.getInstance().getLogger().warning("Unable to find permission node " + permissionNode);
return false;
}
return PermissionAPI.getPermission(player, node);
GeyserImpl.getInstance().eventBus().fire((GeyserRegisterPermissionsEvent) (permission, defaultValue) -> this.registerNode(permission, event));
}
private void registerNode(String node, PermissionGatherEvent.Nodes event) {
@ -114,7 +68,6 @@ public class GeyserNeoForgePermissionHandler {
// NeoForge likes to crash if you try and register a duplicate node
if (!event.getNodes().contains(permissionNode)) {
event.addNodes(permissionNode);
this.permissionNodes.put(node, permissionNode);
}
}

View File

@ -28,7 +28,6 @@ package org.geysermc.geyser.platform.mod;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.Setter;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import org.apache.logging.log4j.LogManager;
import org.checkerframework.checker.nullness.qual.NonNull;
@ -60,7 +59,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
private static GeyserModBootstrap instance;
private final GeyserModPlatform platform;
private GeyserImpl geyser;
private Path dataFolder;
@ -201,8 +199,6 @@ public abstract class GeyserModBootstrap implements GeyserBootstrap {
return this.platform.resolveResource(resource);
}
public abstract boolean hasPermission(@NonNull CommandSourceStack source, @NonNull String permissionNode);
@SuppressWarnings("BooleanMethodIsAlwaysInverted")
private boolean loadConfig() {
try {

View File

@ -25,7 +25,6 @@
package org.geysermc.geyser.platform.mod;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.world.entity.player.Player;
import org.geysermc.geyser.Constants;
import org.geysermc.geyser.platform.mod.command.ModCommandSource;
@ -33,9 +32,9 @@ import org.geysermc.geyser.util.VersionCheckUtils;
public final class GeyserModUpdateListener {
public static void onPlayReady(Player player) {
CommandSourceStack stack = player.createCommandSourceStack();
if (GeyserModBootstrap.getInstance().hasPermission(stack, Constants.UPDATE_PERMISSION)) {
VersionCheckUtils.checkForGeyserUpdate(() -> new ModCommandSource(stack));
ModCommandSource source = new ModCommandSource(player.createCommandSourceStack());
if (source.hasPermission(Constants.UPDATE_PERMISSION)) {
VersionCheckUtils.checkForGeyserUpdate(() -> source);
}
}

View File

@ -33,7 +33,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.platform.mod.GeyserModBootstrap;
import org.geysermc.geyser.text.ChatColor;
import java.util.Objects;
@ -86,7 +85,10 @@ public class ModCommandSource implements GeyserCommandSource {
@Override
public boolean hasPermission(String permission) {
return GeyserModBootstrap.getInstance().hasPermission(source, permission);
// Unlike other bootstraps; we delegate to cloud here too:
// On NeoForge; we'd have to keep track of all PermissionNodes - cloud already does that
// For Fabric, we won't need to include the Fabric Permissions API anymore - cloud already does that too :p
return GeyserImpl.getInstance().commandRegistry().cloud().hasPermission(this, permission);
}
@Override

View File

@ -36,7 +36,6 @@ import org.geysermc.geyser.command.GeyserCommandSource;
import org.geysermc.geyser.text.GeyserLocale;
import java.util.Locale;
import java.util.Optional;
import java.util.UUID;
public class VelocityCommandSource implements GeyserCommandSource {

View File

@ -55,6 +55,7 @@ import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
import org.geysermc.geyser.text.ChatColor;
import org.geysermc.geyser.text.GeyserLocale;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.context.CommandContext;
import org.incendo.cloud.exception.ArgumentParseException;
import org.incendo.cloud.exception.CommandExecutionException;
import org.incendo.cloud.exception.InvalidCommandSenderException;
@ -256,7 +257,7 @@ public class CommandRegistry {
}
try {
handleThrowable(source, throwable);
handleThrowable(source, result.commandContext(), throwable);
} catch (Throwable secondary) {
// otherwise it gets swallowed by whenComplete.
// we assume this won't throw.
@ -265,8 +266,9 @@ public class CommandRegistry {
});
}
private void handleThrowable(@NonNull GeyserCommandSource source, @NonNull Throwable throwable) {
private void handleThrowable(@NonNull GeyserCommandSource source, @NonNull CommandContext<GeyserCommandSource> commandContext, @NonNull Throwable throwable) {
if (throwable instanceof Exception exception) {
cloud.exceptionController().handleException(commandContext, exception);
for (ExceptionHandler<?> handler : exceptionHandlers) {
if (handler.handle(source, exception)) {
return;
@ -316,8 +318,7 @@ public class CommandRegistry {
E e = (E) exception;
// if cloud has a registered exception handler for this type, use it, otherwise use this handler.
// we register all the exception handlers to cloud, so it will likely just be cloud invoking this same handler.
cloud.exceptionController().handleException(,exception);
cloud.handleException(source, type, e, handler);
cloud.exceptionController().handleException(source, type, e, handler);
return true;
}
return false;

View File

@ -26,7 +26,11 @@
package org.geysermc.geyser.command;
import lombok.AllArgsConstructor;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.key.CloudKey;
import org.incendo.cloud.permission.Permission;
import org.incendo.cloud.permission.PermissionResult;
import org.incendo.cloud.permission.PredicatePermission;
@AllArgsConstructor
@ -37,11 +41,6 @@ public class GeyserPermission implements PredicatePermission<GeyserCommandSource
private final String permission;
private final CommandManager<GeyserCommandSource> manager;
@Override
public boolean hasPermission(GeyserCommandSource source) {
return check(source).toBoolean();
}
public Result check(GeyserCommandSource source) {
if (bedrockOnly) {
if (source.connection() == null) {
@ -60,6 +59,16 @@ public class GeyserPermission implements PredicatePermission<GeyserCommandSource
return Result.NO_PERMISSION;
}
@Override
public @NonNull CloudKey<Void> key() {
return CloudKey.cloudKey(permission);
}
@Override
public @NonNull PermissionResult testPermission(@NonNull GeyserCommandSource sender) {
return check(sender).toPermission(permission);
}
public enum Result {
/**
@ -82,8 +91,8 @@ public class GeyserPermission implements PredicatePermission<GeyserCommandSource
*/
ALLOWED;
public boolean toBoolean() {
return this == ALLOWED;
public PermissionResult toPermission(String permission) {
return PermissionResult.of(this == ALLOWED, Permission.of(permission));
}
}
}

View File

@ -27,6 +27,7 @@ package org.geysermc.geyser.extension.command;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.command.Command;
import org.geysermc.geyser.api.command.CommandExecutor;
import org.geysermc.geyser.api.command.CommandSource;
@ -110,6 +111,12 @@ public abstract class GeyserExtensionCommand extends GeyserCommand {
@Override
public Builder<T> permission(@NonNull String permission) {
this.permission = Objects.requireNonNull(permission, "command permission");
if (!permission.contains(".")) {
String newPermission = extension.description().id() + "." + permission;
GeyserImpl.getInstance().getLogger().error("Extension " + extension.name() + " tried to register an invalid permission (" + permission + ")." +
"Changing it to " + newPermission + "!");
this.permission = newPermission;
}
return this;
}
@ -117,6 +124,12 @@ public abstract class GeyserExtensionCommand extends GeyserCommand {
public Builder<T> permission(@NonNull String permission, @NonNull TriState defaultValue) {
this.permission = Objects.requireNonNull(permission, "command permission");
this.permissionDefault = Objects.requireNonNull(defaultValue, "command permission defaultValue");
if (!permission.contains(".")) {
String newPermission = extension.description().id() + "." + permission;
GeyserImpl.getInstance().getLogger().error("Extension " + extension.name() + " tried to register an invalid permission (" + permission + ")." +
"Changing it to " + newPermission + "!");
this.permission = newPermission;
}
return this;
}

View File

@ -33,7 +33,6 @@ viaproxy = "3.2.0-SNAPSHOT"
fabric-minecraft = "1.20.4"
fabric-loader = "0.15.2"
fabric-api = "0.91.2+1.20.4"
fabric-permissions = "0.2-SNAPSHOT"
neoforge-minecraft = "20.4.48-beta"
mixin = "0.8.5"
@ -100,7 +99,6 @@ mixin = { group = "org.spongepowered", name = "mixin", version.ref = "mixin" }
fabric-minecraft = { group = "com.mojang", name = "minecraft", version.ref = "fabric-minecraft" }
fabric-loader = { group = "net.fabricmc", name = "fabric-loader", version.ref = "fabric-loader" }
fabric-api = { group = "net.fabricmc.fabric-api", name = "fabric-api", version.ref = "fabric-api" }
fabric-permissions = { group = "me.lucko", name = "fabric-permissions-api", version.ref = "fabric-permissions" }
neoforge-minecraft = { group = "net.neoforged", name = "neoforge", version.ref = "neoforge-minecraft" }