Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,20 @@
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() {
Expand All @@ -40,4 +48,18 @@ PermissionHandler providePermissionHandler() {
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();
}

}
Original file line number Diff line number Diff line change
@@ -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));
}

}
Original file line number Diff line number Diff line change
@@ -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);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,12 @@
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;
Expand All @@ -47,13 +45,11 @@
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;
Expand Down Expand Up @@ -150,77 +146,13 @@ private void callEvent(final @NonNull Event event) {
}
}

@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
Expand Down
5 changes: 5 additions & 0 deletions Core/src/main/java/com/plotsquared/core/PlotPlatform.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import com.plotsquared.core.inject.annotations.DefaultGenerator;
import com.plotsquared.core.location.World;
import com.plotsquared.core.permissions.PermissionHandler;
import com.plotsquared.core.permissions.RangedPermissionResolver;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.expiration.ExpireManager;
import com.plotsquared.core.plot.world.PlotAreaManager;
Expand Down Expand Up @@ -349,6 +350,10 @@ public interface PlotPlatform<P> extends LocaleHolder {
return injector().getInstance(PermissionHandler.class);
}

default @NonNull RangedPermissionResolver rangedPermissionResolver() {
return injector().getInstance(RangedPermissionResolver.class);
}

/**
* Get the {@link ServicePipeline} implementation
*
Expand Down
Loading
Loading