mirror of
https://github.com/IntellectualSites/PlotSquared.git
synced 2025-07-22 23:34:44 +02:00
feat: inheritance-aware plot limits / permission ranges
This commit is contained in:
@ -22,12 +22,20 @@ import com.google.inject.AbstractModule;
|
||||
import com.google.inject.Provides;
|
||||
import com.google.inject.Singleton;
|
||||
import com.plotsquared.bukkit.permissions.BukkitPermissionHandler;
|
||||
import com.plotsquared.bukkit.permissions.BukkitRangedPermissionResolver;
|
||||
import com.plotsquared.bukkit.permissions.LuckPermsRangedPermissionResolver;
|
||||
import com.plotsquared.bukkit.permissions.VaultPermissionHandler;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.permissions.PermissionHandler;
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
public class PermissionModule extends AbstractModule {
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger("PlotSquared/" + PermissionModule.class.getSimpleName());
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
PermissionHandler providePermissionHandler() {
|
||||
@ -40,4 +48,18 @@ public class PermissionModule extends AbstractModule {
|
||||
return new BukkitPermissionHandler();
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
RangedPermissionResolver provideRangedPermissionResolver() {
|
||||
if (Settings.Permissions.USE_LUCKPERMS_RANGE_RESOLVER) {
|
||||
if (Bukkit.getPluginManager().isPluginEnabled("LuckPerms")) {
|
||||
LOGGER.info("Using experimental LuckPerms ranged permission resolver");
|
||||
return new LuckPermsRangedPermissionResolver();
|
||||
}
|
||||
LOGGER.warn("Enabled LuckPerms ranged permission resolver, but LuckPerms is not installed. " +
|
||||
"Falling back to default Bukkit ranged permission resolver");
|
||||
}
|
||||
return new BukkitRangedPermissionResolver();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.bukkit.permissions;
|
||||
|
||||
import com.plotsquared.bukkit.player.BukkitPlayer;
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class BukkitRangedPermissionResolver implements RangedPermissionResolver {
|
||||
|
||||
private static boolean CHECK_EFFECTIVE = true;
|
||||
|
||||
@Override
|
||||
public @NonNegative int getPermissionRange(
|
||||
final @NonNull PlotPlayer<?> generic,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
if (!(generic instanceof BukkitPlayer player)) {
|
||||
throw new IllegalArgumentException("PlotPlayer is not a BukkitPlayer");
|
||||
}
|
||||
if (hasWildcardRange(player, stub, worldContext)) {
|
||||
return INFINITE_RANGE_VALUE;
|
||||
}
|
||||
int max = 0;
|
||||
if (CHECK_EFFECTIVE) {
|
||||
boolean hasAny = false;
|
||||
String stubPlus = stub + ".";
|
||||
final Set<PermissionAttachmentInfo> effective = player.getPlatformPlayer().getEffectivePermissions();
|
||||
if (!effective.isEmpty()) {
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
// Ignore all "false" permissions
|
||||
if (!attach.getValue()) {
|
||||
continue;
|
||||
}
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith(stubPlus)) {
|
||||
hasAny = true;
|
||||
String end = permStr.substring(stubPlus.length());
|
||||
if (MathMan.isInteger(end)) {
|
||||
int val = Integer.parseInt(end);
|
||||
if (val > range) {
|
||||
return val;
|
||||
}
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasAny) {
|
||||
return max;
|
||||
}
|
||||
// Workaround
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith("plots.") && !permStr.equals("plots.use")) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
CHECK_EFFECTIVE = false;
|
||||
}
|
||||
}
|
||||
for (int i = range; i > 0; i--) {
|
||||
if (player.hasPermission(worldContext, stub + "." + i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull IntStream streamFullPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
return IntStream.of(getPermissionRange(player, stub, worldContext, range));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* PlotSquared, a land and world management plugin for Minecraft.
|
||||
* Copyright (C) IntellectualSites <https://intellectualsites.com>
|
||||
* Copyright (C) IntellectualSites team and contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.plotsquared.bukkit.permissions;
|
||||
|
||||
import com.plotsquared.core.permissions.RangedPermissionResolver;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import net.luckperms.api.LuckPerms;
|
||||
import net.luckperms.api.context.ImmutableContextSet;
|
||||
import net.luckperms.api.model.user.User;
|
||||
import net.luckperms.api.node.NodeType;
|
||||
import net.luckperms.api.node.types.PermissionNode;
|
||||
import net.luckperms.api.query.QueryOptions;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class LuckPermsRangedPermissionResolver implements RangedPermissionResolver {
|
||||
|
||||
private final LuckPerms luckPerms;
|
||||
|
||||
public LuckPermsRangedPermissionResolver() {
|
||||
this.luckPerms = Objects.requireNonNull(
|
||||
Bukkit.getServicesManager().getRegistration(LuckPerms.class),
|
||||
"LuckPerms is not available"
|
||||
).getProvider();
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNegative int getPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
final @NonNegative int range
|
||||
) {
|
||||
// no need to use LuckPerms for basic checks
|
||||
if (this.hasWildcardRange(player, stub, worldContext)) {
|
||||
return INFINITE_RANGE_VALUE;
|
||||
}
|
||||
return this.streamFullPermissionRange(player, stub, worldContext, range)
|
||||
.sorted()
|
||||
.reduce((first, second) -> second)
|
||||
.orElse(0);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
public IntStream streamFullPermissionRange(
|
||||
final @NonNull PlotPlayer<?> player,
|
||||
final @NonNull String stub,
|
||||
final @Nullable String worldContext,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
final User user = this.luckPerms.getUserManager().getUser(player.getUUID());
|
||||
if (user == null) {
|
||||
throw new IllegalStateException("Luckperms User is null - is the Player online? (UUID: %s)".formatted(player.getUUID()));
|
||||
}
|
||||
final QueryOptions queryOptions = worldContext == null ?
|
||||
QueryOptions.nonContextual() :
|
||||
QueryOptions.contextual(ImmutableContextSet.of("world", worldContext));
|
||||
return user.resolveInheritedNodes(queryOptions).stream()
|
||||
// only support normal permission nodes (regex permission nodes would be a pita to support)
|
||||
.filter(NodeType.PERMISSION::matches)
|
||||
.map(node -> ((PermissionNode) node).getPermission())
|
||||
// check that the node actually has additional data after the stub
|
||||
.filter(permission -> permission.startsWith(stub + "."))
|
||||
// extract the raw data after the stub
|
||||
.map(permission -> permission.substring(stub.length() + 1))
|
||||
// check if data is integer and parse
|
||||
.filter(MathMan::isInteger)
|
||||
.mapToInt(Integer::parseInt)
|
||||
// only use values that are positive
|
||||
.filter(value -> value > -1);
|
||||
}
|
||||
|
||||
}
|
@ -24,14 +24,12 @@ import com.plotsquared.core.PlotSquared;
|
||||
import com.plotsquared.core.configuration.Settings;
|
||||
import com.plotsquared.core.events.TeleportCause;
|
||||
import com.plotsquared.core.location.Location;
|
||||
import com.plotsquared.core.permissions.Permission;
|
||||
import com.plotsquared.core.permissions.PermissionHandler;
|
||||
import com.plotsquared.core.player.ConsolePlayer;
|
||||
import com.plotsquared.core.player.PlotPlayer;
|
||||
import com.plotsquared.core.plot.PlotWeather;
|
||||
import com.plotsquared.core.plot.world.PlotAreaManager;
|
||||
import com.plotsquared.core.util.EventDispatcher;
|
||||
import com.plotsquared.core.util.MathMan;
|
||||
import com.plotsquared.core.util.WorldUtil;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.extension.platform.Actor;
|
||||
@ -47,13 +45,11 @@ import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.event.EventException;
|
||||
import org.bukkit.event.player.PlayerTeleportEvent;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
import org.bukkit.plugin.RegisteredListener;
|
||||
import org.bukkit.potion.PotionEffectType;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
|
||||
import static com.sk89q.worldedit.world.gamemode.GameModes.ADVENTURE;
|
||||
@ -150,77 +146,13 @@ public class BukkitPlayer extends PlotPlayer<Player> {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("StringSplitter")
|
||||
@Override
|
||||
@NonNegative
|
||||
public int hasPermissionRange(
|
||||
final @NonNull String stub,
|
||||
@NonNegative final int range
|
||||
) {
|
||||
if (hasPermission(Permission.PERMISSION_ADMIN.toString())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
final String[] nodes = stub.split("\\.");
|
||||
final StringBuilder n = new StringBuilder();
|
||||
// Wildcard check from less specific permission to more specific permission
|
||||
for (int i = 0; i < (nodes.length - 1); i++) {
|
||||
n.append(nodes[i]).append(".");
|
||||
if (!stub.equals(n + Permission.PERMISSION_STAR.toString())) {
|
||||
if (hasPermission(n + Permission.PERMISSION_STAR.toString())) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Wildcard check for the full permission
|
||||
if (hasPermission(stub + ".*")) {
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
// Permission value cache for iterative check
|
||||
int max = 0;
|
||||
if (CHECK_EFFECTIVE) {
|
||||
boolean hasAny = false;
|
||||
String stubPlus = stub + ".";
|
||||
final Set<PermissionAttachmentInfo> effective = player.getEffectivePermissions();
|
||||
if (!effective.isEmpty()) {
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
// Ignore all "false" permissions
|
||||
if (!attach.getValue()) {
|
||||
continue;
|
||||
}
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith(stubPlus)) {
|
||||
hasAny = true;
|
||||
String end = permStr.substring(stubPlus.length());
|
||||
if (MathMan.isInteger(end)) {
|
||||
int val = Integer.parseInt(end);
|
||||
if (val > range) {
|
||||
return val;
|
||||
}
|
||||
if (val > max) {
|
||||
max = val;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (hasAny) {
|
||||
return max;
|
||||
}
|
||||
// Workaround
|
||||
for (PermissionAttachmentInfo attach : effective) {
|
||||
String permStr = attach.getPermission();
|
||||
if (permStr.startsWith("plots.") && !permStr.equals("plots.use")) {
|
||||
return max;
|
||||
}
|
||||
}
|
||||
CHECK_EFFECTIVE = false;
|
||||
}
|
||||
}
|
||||
for (int i = range; i > 0; i--) {
|
||||
if (hasPermission(stub + "." + i)) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return max;
|
||||
return PlotSquared.platform().rangedPermissionResolver().getPermissionRange(this, stub, null, range);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Reference in New Issue
Block a user