Add wildcard permissions

This commit is contained in:
Luck 2016-08-07 01:16:05 +02:00
parent e07b677632
commit e14ea73626
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
25 changed files with 265 additions and 107 deletions

View File

@ -8,6 +8,7 @@ A permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
## Features
* **Group inheritance** - users can be members of multiple groups, groups can inherit other groups
* **Temporary permissions** - users/groups can be given permissions that expire after a given time
* **Wildcard permissions** - users/groups can be given wildcard permissions (e.g. "minecraft.command.*"), even when plugins haven't implemented their own wildcards.
* **Temporary groups** - users/groups can be added to/inherit other groups temporarily
* **Multi-server support** - data is synced across all servers/platforms
* **Full offline-mode/mixed-mode support** - player permissions are synced properly over offline-mode or mixed online/offline-mode networks.
@ -34,23 +35,31 @@ You can define the settings for per-server permissions, the storage method and c
## Info
### Permission Calculation
Permissions are calculated based on a priority system as follows.
#### Permissions are calculated based on a priority system as follows.
* Temporary permissions will override non-temporary permissions.
* **Non wildcard permissions will override wildcard permissions**
Example: if a user has a true permission set for "luckperms.\*", and a false permission set for "luckperms.something", the non-wildcard permission will override the wildcard, and "luckperms.something" will be set to false, despite the wildcard.
* **More specific wildcards override less specific ones**
Example: if a user has "luckperms.\*" set to true, but "luckperms.user.\*" set to false, all of the user permissions will be set to false, despite the more generic wildcard for "luckperms.*".
* **Temporary permissions will override non-temporary permissions.**
Example: if a user has a false permission set for "test.node", and a temporary true permission set for "test.node", the temporary permission will override the permanent one, and the user will be granted the true node.
* World specific permissions will override generic permissions.
* **World specific permissions will override generic permissions.**
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission in the "world_nether" world, the world specific permission will override the globally defined one, and the user will be granted the negated node (provided they're in that world, of course.).
* Server specific permissions will override generic/global permissions.
* **Server specific permissions will override generic/global permissions.**
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission on the "factions" server, the server specific permission will override the globally defined one, and the user will be granted the negated node.
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission on the "factions" server, the server specific permission will override the globally defined one, and the user will be granted the negated node (provided they're on that server).
* Inherited permissions will be overridden by an objects own permissions.
* **Inherited permissions will be overridden by an objects own permissions.**
Example: A user is a member of the default group, which grants "some.thing.perm", but the users own permissions has "some.thing.perm" set to false. The inherited permission will be overridden by the users own permissions, and the user will be granted the negative node (provided they're on that server).
Example: A user is a member of the default group, which grants "some.thing.perm", but the users own permissions has "some.thing.perm" set to false. The inherited permission will be overridden by the users own permissions, and the user will be granted the negative node.
### Temporary Permissions
Temporary permissions are checked each time a user/group is loaded, and when the sync task runs. This means if you set a temporary permission to expire after 30 seconds, it won't actually be removed until the sync task runs.
@ -102,7 +111,7 @@ You can add LuckPerms as a Maven dependency by adding the following to your proj
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>2.0</version>
<version>2.1</version>
</dependency>
</dependencies>
````

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -59,6 +59,11 @@ public interface LPConfiguration {
*/
boolean getOnlineMode();
/**
* @return if LuckPerms is applying wildcard permissions
*/
boolean getApplyWildcards();
/**
* @return the database values set in the configuration
*/

View File

@ -262,6 +262,16 @@ public interface PermissionHolder {
*/
void unsetPermission(String node, String server, String world, boolean temporary) throws ObjectLacksException;
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
@ -273,8 +283,17 @@ public interface PermissionHolder {
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for (can be null)
* @param excludedGroups Groups that shouldn't be inherited, can be null (to prevent circular inheritance issues)
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups);

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -40,7 +40,6 @@ import me.lucko.luckperms.users.UserManager;
import me.lucko.luckperms.utils.LPConfiguration;
import me.lucko.luckperms.utils.LogUtil;
import me.lucko.luckperms.utils.UuidCache;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
@ -48,6 +47,7 @@ import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@ -71,7 +71,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
configuration = new BukkitConfig(this);
// register events
PluginManager pm = Bukkit.getPluginManager();
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BukkitListener(this), this);
// register commands
@ -155,12 +155,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
@Override
public void doAsync(Runnable r) {
Bukkit.getScheduler().runTaskAsynchronously(this, r);
getServer().getScheduler().runTaskAsynchronously(this, r);
}
@Override
public void doSync(Runnable r) {
Bukkit.getScheduler().runTask(this, r);
getServer().getScheduler().runTask(this, r);
}
@Override
@ -183,6 +183,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
final List<String> perms = new ArrayList<>();
getServer().getPluginManager().getPermissions().forEach(p -> {
perms.add(p.getName());
p.getChildren().keySet().forEach(perms::add);
});
return perms;
}
@Override
public void runUpdateTask() {
getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this));

View File

@ -22,6 +22,11 @@ include-global: true
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode: true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards: true
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, flatfile
# Fill out connection info below if you're using MySQL

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -29,14 +29,13 @@ import me.lucko.luckperms.utils.UuidCache;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.api.event.*;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -49,6 +48,27 @@ class BungeeListener extends AbstractListener implements Listener {
this.plugin = plugin;
}
@EventHandler
public void onPlayerPermissionCheck(PermissionCheckEvent e) {
if (!(e.getSender() instanceof ProxiedPlayer)) {
return;
}
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
final User user = plugin.getUserManager().getUser(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) return;
final String server = player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
Map<String, Boolean> local = user.getLocalPermissions(plugin.getConfiguration().getServer(), server, null, Collections.singletonList(e.getPermission()));
for (Map.Entry<String, Boolean> en : local.entrySet()) {
if (en.getKey().equalsIgnoreCase(e.getPermission())) {
e.setHasPermission(en.getValue());
return;
}
}
}
@EventHandler
public void onPlayerLogin(LoginEvent e) {
/* Delay the login here, as we want to cache UUID data before the player is connected to a backend bukkit server.

View File

@ -41,6 +41,7 @@ import me.lucko.luckperms.utils.UuidCache;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@ -143,6 +144,12 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
// No such thing on Bungee. Wildcards are processed in the listener instead.
return Collections.emptyList();
}
@Override
public void runUpdateTask() {
doAsync(new UpdateTask(this));

View File

@ -23,38 +23,20 @@
package me.lucko.luckperms.users;
import me.lucko.luckperms.LPBungeePlugin;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
public class BungeeUser extends User {
private final LPBungeePlugin plugin;
BungeeUser(UUID uuid, LPBungeePlugin plugin) {
super(uuid, plugin);
this.plugin = plugin;
}
BungeeUser(UUID uuid, String username, LPBungeePlugin plugin) {
super(uuid, username, plugin);
this.plugin = plugin;
}
@Override
public void refreshPermissions() {
ProxiedPlayer player = plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
if (player == null) return;
// Clear existing permissions
Collection<String> perms = new ArrayList<>(player.getPermissions());
perms.forEach(p -> player.setPermission(p, false));
// Re-add all defined permissions for the user
final String server = player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
Map<String, Boolean> local = getLocalPermissions(getPlugin().getConfiguration().getServer(), server, null);
local.entrySet().forEach(e -> player.setPermission(e.getKey(), e.getValue()));
// Do nothing. Permissions are applied when needed in a listener.
}
}

View File

@ -22,6 +22,11 @@ include-global: false
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode: true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards: true
# Which storage method the plugin should use.
# Currently supported: mysql & flatfile
# Fill out connection info below if you're using MySQL

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -106,6 +106,12 @@ public interface LuckPermsPlugin {
*/
List<String> getPlayerList();
/**
* Gets all possible permission nodes, used for resolving wildcards
* @return a {@link List} of permission nodes
*/
List<String> getPossiblePermissions();
/**
* Runs an update task
*/

View File

@ -63,6 +63,11 @@ public class LPConfigurationLink implements LPConfiguration {
return master.getOnlineMode();
}
@Override
public boolean getApplyWildcards() {
return master.getApplyWildcards();
}
@Override
public MySQLConfiguration getDatabaseValues() {
return master.getDatabaseValues();

View File

@ -175,11 +175,21 @@ class PermissionHolderLink implements PermissionHolder {
master.unsetPermission(checkNode(node), checkServer(server), world, temporary);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, world, excludedGroups, possibleNodes);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return master.getLocalPermissions(server, world, excludedGroups);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, excludedGroups, possibleNodes);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return master.getLocalPermissions(server, excludedGroups);

View File

@ -23,7 +23,6 @@
package me.lucko.luckperms.constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.commands.Sender;
@SuppressWarnings("SpellCheckingInspection")
@ -42,74 +41,56 @@ public enum Permission {
DELETE_TRACK("deletetrack", null),
LIST_TRACKS("listtracks", null),
USER_INFO("info", PermissionGroup.USER),
USER_GETUUID("getuuid", PermissionGroup.USER),
USER_LISTNODES("listnodes", PermissionGroup.USER),
USER_HASPERMISSION("haspermission", PermissionGroup.USER),
USER_INHERITSPERMISSION("inheritspermission", PermissionGroup.USER),
USER_SETPERMISSION("setpermission", PermissionGroup.USER),
USER_UNSETPERMISSION("unsetpermission", PermissionGroup.USER),
USER_ADDGROUP("addgroup", PermissionGroup.USER),
USER_REMOVEGROUP("removegroup", PermissionGroup.USER),
USER_SET_TEMP_PERMISSION("settemppermission", PermissionGroup.USER),
USER_UNSET_TEMP_PERMISSION("unsettemppermission", PermissionGroup.USER),
USER_ADDTEMPGROUP("addtempgroup", PermissionGroup.USER),
USER_REMOVETEMPGROUP("removetempgroup", PermissionGroup.USER),
USER_SETPRIMARYGROUP("setprimarygroup", PermissionGroup.USER),
USER_SHOWTRACKS("showtracks", PermissionGroup.USER),
USER_PROMOTE("promote", PermissionGroup.USER),
USER_DEMOTE("demote", PermissionGroup.USER),
USER_SHOWPOS("showpos", PermissionGroup.USER),
USER_CLEAR("clear", PermissionGroup.USER),
USER_INFO("info", "user"),
USER_GETUUID("getuuid", "user"),
USER_LISTNODES("listnodes", "user"),
USER_HASPERMISSION("haspermission", "user"),
USER_INHERITSPERMISSION("inheritspermission", "user"),
USER_SETPERMISSION("setpermission", "user"),
USER_UNSETPERMISSION("unsetpermission", "user"),
USER_ADDGROUP("addgroup", "user"),
USER_REMOVEGROUP("removegroup", "user"),
USER_SET_TEMP_PERMISSION("settemppermission", "user"),
USER_UNSET_TEMP_PERMISSION("unsettemppermission", "user"),
USER_ADDTEMPGROUP("addtempgroup", "user"),
USER_REMOVETEMPGROUP("removetempgroup", "user"),
USER_SETPRIMARYGROUP("setprimarygroup", "user"),
USER_SHOWTRACKS("showtracks", "user"),
USER_PROMOTE("promote", "user"),
USER_DEMOTE("demote", "user"),
USER_SHOWPOS("showpos", "user"),
USER_CLEAR("clear", "user"),
GROUP_INFO("info", PermissionGroup.GROUP),
GROUP_LISTNODES("listnodes", PermissionGroup.GROUP),
GROUP_HASPERMISSION("haspermission", PermissionGroup.GROUP),
GROUP_INHERITSPERMISSION("inheritspermission", PermissionGroup.GROUP),
GROUP_SETPERMISSION("setpermission", PermissionGroup.GROUP),
GROUP_UNSETPERMISSION("unsetpermission", PermissionGroup.GROUP),
GROUP_SETINHERIT("setinherit", PermissionGroup.GROUP),
GROUP_UNSETINHERIT("unsetinherit", PermissionGroup.GROUP),
GROUP_SET_TEMP_PERMISSION("settemppermission", PermissionGroup.GROUP),
GROUP_UNSET_TEMP_PERMISSION("unsettemppermission", PermissionGroup.GROUP),
GROUP_SET_TEMP_INHERIT("settempinherit", PermissionGroup.GROUP),
GROUP_UNSET_TEMP_INHERIT("unsettempinherit", PermissionGroup.GROUP),
GROUP_SHOWTRACKS("showtracks", PermissionGroup.GROUP),
GROUP_CLEAR("clear", PermissionGroup.GROUP),
GROUP_INFO("info", "group"),
GROUP_LISTNODES("listnodes", "group"),
GROUP_HASPERMISSION("haspermission", "group"),
GROUP_INHERITSPERMISSION("inheritspermission", "group"),
GROUP_SETPERMISSION("setpermission", "group"),
GROUP_UNSETPERMISSION("unsetpermission", "group"),
GROUP_SETINHERIT("setinherit", "group"),
GROUP_UNSETINHERIT("unsetinherit", "group"),
GROUP_SET_TEMP_PERMISSION("settemppermission", "group"),
GROUP_UNSET_TEMP_PERMISSION("unsettemppermission", "group"),
GROUP_SET_TEMP_INHERIT("settempinherit", "group"),
GROUP_UNSET_TEMP_INHERIT("unsettempinherit", "group"),
GROUP_SHOWTRACKS("showtracks", "group"),
GROUP_CLEAR("clear", "group"),
TRACK_INFO("info", PermissionGroup.TRACK),
TRACK_APPEND("append", PermissionGroup.TRACK),
TRACK_INSERT("insert", PermissionGroup.TRACK),
TRACK_REMOVE("remove", PermissionGroup.TRACK),
TRACK_CLEAR("clear", PermissionGroup.TRACK);
TRACK_INFO("info", "track"),
TRACK_APPEND("append", "track"),
TRACK_INSERT("insert", "track"),
TRACK_REMOVE("remove", "track"),
TRACK_CLEAR("clear", "track");
private String node;
private PermissionGroup group;
private String group;
public boolean isAuthorized(Sender sender) {
if (sender.hasPermission("luckperms.*")) {
return true;
}
if (group != null) {
return group.isAuthorized(sender) || sender.hasPermission("luckperms." + group.getNode() + "." + node);
return sender.hasPermission("luckperms." + group + "." + node);
}
return sender.hasPermission("luckperms." + node);
}
@Getter
@AllArgsConstructor
private enum PermissionGroup {
USER("user"),
GROUP("group"),
TRACK("track");
private String node;
private boolean isAuthorized(Sender sender) {
return sender.hasPermission("luckperms." + node + ".*");
}
}
}

View File

@ -282,7 +282,7 @@ public class Group extends PermissionHolder {
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal);
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])

View File

@ -313,7 +313,7 @@ public abstract class User extends PermissionHolder {
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal);
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])

View File

@ -88,6 +88,10 @@ public abstract class LPConfiguration<T extends LuckPermsPlugin> {
return getBoolean("online-mode", true);
}
public boolean getApplyWildcards() {
return getBoolean("apply-wildcards", true);
}
public MySQLConfiguration getDatabaseValues() {
return new MySQLConfiguration(
getString("sql.address", null),

View File

@ -396,6 +396,18 @@ public abstract class PermissionHolder {
unsetPermission(server + "-" + world + "/" + node, temporary);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms(), possibleNodes);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
@ -404,7 +416,18 @@ public abstract class PermissionHolder {
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms());
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms(), null);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return getLocalPermissions(server, null, excludedGroups, possibleNodes);
}
/**
@ -414,7 +437,7 @@ public abstract class PermissionHolder {
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return getLocalPermissions(server, null, excludedGroups);
return getLocalPermissions(server, null, excludedGroups, null);
}
/**
@ -468,7 +491,7 @@ public abstract class PermissionHolder {
return nodes;
}
protected Map<String, Boolean> getPermissions(String server, String world, List<String> excludedGroups, boolean includeGlobal) {
protected Map<String, Boolean> getPermissions(String server, String world, List<String> excludedGroups, boolean includeGlobal, List<String> possibleNodes) {
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
}
@ -643,9 +666,61 @@ public abstract class PermissionHolder {
}
}
if (plugin.getConfiguration().getApplyWildcards()) {
if (possibleNodes != null && !possibleNodes.isEmpty()) {
return applyWildcards(perms, possibleNodes);
}
return applyWildcards(perms, plugin.getPossiblePermissions());
}
return perms;
}
private Map<String, Boolean> applyWildcards(Map<String, Boolean> input, List<String> possibleNodes) {
// Add all group nodes, so wildcard group.* and '*' can apply.
plugin.getGroupManager().getGroups().keySet().forEach(s -> possibleNodes.add("group." + s));
SortedMap<Integer, Map<String, Boolean>> wildcards = new TreeMap<>(Collections.reverseOrder());
for (Map.Entry<String, Boolean> e : input.entrySet()) {
if (e.getKey().equals("*") || e.getKey().equals("'*'")) {
wildcards.put(0, Collections.singletonMap("*", e.getValue()));
continue;
}
if (!e.getKey().endsWith(".*")) {
continue;
}
final String node = e.getKey().substring(0, e.getKey().length() - 2);
final String[] parts = Patterns.DOT.split(node);
if (!wildcards.containsKey(parts.length)) {
wildcards.put(parts.length, new HashMap<>());
}
wildcards.get(parts.length).put(node, e.getValue());
}
for (Map.Entry<Integer, Map<String, Boolean>> e : wildcards.entrySet()) {
if (e.getKey() == 0) {
// Apply all permissions
possibleNodes.stream()
.filter(n -> !input.containsKey(n)) // Don't override existing nodes
.forEach(n -> input.put(n, e.getValue().get("*")));
break;
}
for (Map.Entry<String, Boolean> wc : e.getValue().entrySet()) {
possibleNodes.stream()
.filter(n -> n.startsWith(wc.getKey() + ".")) // Only nodes that match the wildcard are applied
.filter(n -> !input.containsKey(n)) // Don't override existing nodes
.forEach(n -> input.put(n, wc.getValue()));
}
}
return input;
}
private static String stripTime(String s) {
if (s.contains("$")) {
return Patterns.TEMP_DELIMITER.split(s)[0];

View File

@ -6,7 +6,7 @@
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms</artifactId>
<version>2.0</version>
<version>2.1</version>
<modules>
<module>common</module>
<module>api</module>

View File

@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.1</version>
</parent>
<modelVersion>4.0.0</modelVersion>

View File

@ -50,6 +50,8 @@ import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import java.io.File;
import java.nio.file.Path;
@ -181,6 +183,12 @@ public class LPSpongePlugin implements LuckPermsPlugin {
return game.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
PermissionService p = game.getServiceManager().provideUnchecked(PermissionService.class);
return p.getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList());
}
@Override
public void runUpdateTask() {
scheduler.createTaskBuilder().async().execute(new UpdateTask(this)).submit(LPSpongePlugin.this);

View File

@ -22,6 +22,11 @@ include-global=true
# matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode=true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards=true
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, flatfile
# Fill out connection info below if you're using MySQL