Per-world permissions

This commit is contained in:
Luck
2016-07-25 18:19:36 +01:00
Unverified
parent 9ad40be210
commit ebeb69dd3a
38 changed files with 950 additions and 296 deletions
@@ -7,6 +7,7 @@ import java.util.regex.Pattern;
@UtilityClass
public class Patterns {
public static final Pattern SERVER_SPLIT = Pattern.compile("\\/");
public static final Pattern WORLD_SPLIT = Pattern.compile("\\-");
public static final Pattern TEMP_SPLIT = Pattern.compile("\\$");
public static final Pattern DOT_SPLIT = Pattern.compile("\\.");
public static final Pattern GROUP_MATCH = Pattern.compile("group\\..*");
@@ -89,6 +89,18 @@ public abstract class PermissionObject {
return hasPermission(server + "/" + node, b);
}
/**
* Checks to see the the object has a permission on a certain server
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @return true if the user has the permission
*/
public boolean hasPermission(String node, boolean b, String server, String world) {
return hasPermission(server + "-" + world + "/" + node, b);
}
/**
* Checks to see the the object has a permission on a certain server
* @param node The permission node
@@ -100,6 +112,31 @@ public abstract class PermissionObject {
return hasPermission(node + (temporary ? "$a" : ""), b);
}
/**
* Checks to see the the object has a permission on a certain server
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server to check on
* @param temporary if the permission is temporary
* @return true if the user has the permission
*/
public boolean hasPermission(String node, boolean b, String server, boolean temporary) {
return hasPermission(server + "/" + node + (temporary ? "$a" : ""), b);
}
/**
* Checks to see the the object has a permission on a certain server
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server to check on
* @param world The world to check on
* @param temporary if the permission is temporary
* @return true if the user has the permission
*/
public boolean hasPermission(String node, boolean b, String server, String world, boolean temporary) {
return hasPermission(server + "-" + world + "/" + node + (temporary ? "$a" : ""), b);
}
/**
* Checks to see if the object inherits a certain permission
* @param node The permission node
@@ -124,10 +161,29 @@ public abstract class PermissionObject {
* @return true if the user inherits the permission
*/
public boolean inheritsPermission(String node, boolean b, String server) {
if (server.contains("-")) {
// Use other method
final String[] parts = Patterns.WORLD_SPLIT.split(server, 2);
return inheritsPermission(node, b, parts[0], parts[1]);
}
final Map<String, Boolean> local = getLocalPermissions(server, null);
return hasPermission(local, node, b);
}
/**
* Checks to see the the object inherits a permission on a certain server
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @return true if the user inherits the permission
*/
public boolean inheritsPermission(String node, boolean b, String server, String world) {
final Map<String, Boolean> local = getLocalPermissions(server, world, null);
return hasPermission(local, node, b);
}
/**
* Checks to see if the object inherits a certain permission
* @param node The permission node
@@ -139,6 +195,31 @@ public abstract class PermissionObject {
return inheritsPermission(node + (temporary ? "$a" : ""), b);
}
/**
* Checks to see if the object inherits a certain permission
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param temporary if the permission is temporary
* @return true if the user inherits the permission
*/
public boolean inheritsPermission(String node, boolean b, String server, boolean temporary) {
return inheritsPermission(server + "/" + node + (temporary ? "$a" : ""), b);
}
/**
* Checks to see if the object inherits a certain permission
* @param node The permission node
* @param b If the node is true/false(negated)
* @param server The server
* @param world The world
* @param temporary if the permission is temporary
* @return true if the user inherits the permission
*/
public boolean inheritsPermission(String node, boolean b, String server, String world, boolean temporary) {
return inheritsPermission(server + "-" + world + "/" + node + (temporary ? "$a" : ""), b);
}
/**
* Sets a permission for the object
* @param node The node to be set
@@ -164,6 +245,18 @@ public abstract class PermissionObject {
setPermission(server + "/" + node, value);
}
/**
* Sets a permission for the object
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param server The server to set the permission on
* @param world The world to set the permission on
* @throws ObjectAlreadyHasException if the object already has the permission
*/
public void setPermission(String node, boolean value, String server, String world) throws ObjectAlreadyHasException {
setPermission(server + "-" + world + "/" + node, value);
}
/**
* Sets a permission for the object
* @param node The node to set
@@ -187,6 +280,19 @@ public abstract class PermissionObject {
setPermission(node + "$" + expireAt, value, server);
}
/**
* Sets a permission for the object
* @param node The node to set
* @param value What to set the node to - true/false(negated)
* @param server The server to set the permission on
* @param world The world to set the permission on
* @param expireAt The time in unixtime when the permission will expire
* @throws ObjectAlreadyHasException if the object already has the permission
*/
public void setPermission(String node, boolean value, String server, String world, long expireAt) throws ObjectAlreadyHasException {
setPermission(node + "$" + expireAt, value, server, world);
}
/**
* Unsets a permission for the object
* @param node The node to be unset
@@ -234,6 +340,17 @@ public abstract class PermissionObject {
unsetPermission(server + "/" + node);
}
/**
* Unsets a permission for the object
* @param node The node to be unset
* @param server The server to unset the node on
* @param world The world to unset the node on
* @throws ObjectLacksException if the node wasn't already set
*/
public void unsetPermission(String node, String server, String world) throws ObjectLacksException {
unsetPermission(server + "-" + world + "/" + node);
}
/**
* Unsets a permission for the object
* @param node The node to be unset
@@ -245,6 +362,29 @@ public abstract class PermissionObject {
unsetPermission(server + "/" + node, temporary);
}
/**
* Unsets a permission for the object
* @param node The node to be unset
* @param server The server to unset the node on
* @param world The world to unset the node on
* @param temporary if the permission being unset is temporary
* @throws ObjectLacksException if the node wasn't already set
*/
public void unsetPermission(String node, String server, String world, boolean temporary) throws ObjectLacksException {
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)
* @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());
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
@@ -252,7 +392,7 @@ public abstract class PermissionObject {
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return getPermissions(server, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms());
return getLocalPermissions(server, null, excludedGroups);
}
/**
@@ -287,7 +427,7 @@ public abstract class PermissionObject {
.forEach(s -> this.nodes.remove(s));
}
protected Map<String, Boolean> convertTemporaryPerms() {
private Map<String, Boolean> convertTemporaryPerms() {
auditTemporaryPermissions();
Map<String, Boolean> nodes = new HashMap<>();
@@ -306,7 +446,7 @@ public abstract class PermissionObject {
return nodes;
}
private Map<String, Boolean> getPermissions(String server, List<String> excludedGroups, boolean includeGlobal) {
protected Map<String, Boolean> getPermissions(String server, String world, List<String> excludedGroups, boolean includeGlobal) {
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
}
@@ -318,17 +458,25 @@ public abstract class PermissionObject {
server = "global";
}
if (world != null && world.equalsIgnoreCase("")) {
world = null;
}
/*
Priority:
1. server specific nodes
2. user nodes
3. server specific group nodes
4. group nodes
1. server+world specific nodes
2. server specific nodes
3. user nodes
4. server+world specific group nodes
5. server specific group nodes
6. group nodes
*/
final Map<String, Boolean> serverWorldSpecificNodes = new HashMap<>();
final Map<String, Boolean> serverSpecificNodes = new HashMap<>();
final Map<String, Boolean> userNodes = new HashMap<>();
final Map<String, Boolean> serverWorldSpecificGroups = new HashMap<>();
final Map<String, Boolean> serverSpecificGroups = new HashMap<>();
final Map<String, Boolean> groupNodes = new HashMap<>();
@@ -337,6 +485,33 @@ public abstract class PermissionObject {
serverSpecific:
if (node.getKey().contains("/")) {
String[] parts = Patterns.SERVER_SPLIT.split(node.getKey(), 2);
// 0=server(+world) 1=node
// WORLD SPECIFIC
if (parts[0].contains("-")) {
String[] serverParts = Patterns.WORLD_SPLIT.split(parts[0], 2);
// 0=server 1=world
if ((!serverParts[0].equalsIgnoreCase("global") || !includeGlobal) && (!serverParts[0].equalsIgnoreCase(server))) {
// GLOBAL AND UNWANTED OR SERVER SPECIFIC BUT DOES NOT APPLY :(((
continue;
}
if (world != null && !serverParts[1].equalsIgnoreCase(world)) {
// WORLD SPECIFIC BUT DOES NOT APPLY
continue;
}
if (Patterns.GROUP_MATCH.matcher(parts[1]).matches()) {
// SERVER+WORLD SPECIFIC AND GROUP
serverWorldSpecificGroups.put(node.getKey(), node.getValue());
continue;
}
// SERVER+WORLD SPECIFIC
serverWorldSpecificNodes.put(node.getKey(), node.getValue());
continue;
}
if (parts[0].equalsIgnoreCase("global")) {
// REGULAR
@@ -362,17 +537,30 @@ public abstract class PermissionObject {
// Skip adding global permissions if they are not requested
if (!includeGlobal) continue;
if (Patterns.GROUP_MATCH.matcher(node.getKey()).matches()) {
// Could be here if the server was set to global.
String n = node.getKey();
if (n.contains("/")) {
n = Patterns.SERVER_SPLIT.split(n, 2)[0];
}
if (Patterns.GROUP_MATCH.matcher(n).matches()) {
// GROUP
groupNodes.put(node.getKey(), node.getValue());
groupNodes.put(n, node.getValue());
continue;
}
// JUST NORMAL
userNodes.put(node.getKey(), node.getValue());
userNodes.put(n, node.getValue());
}
// If a group is negated at a higher priority, the group should not then be applied at a lower priority
serverWorldSpecificGroups.entrySet().stream().filter(node -> !node.getValue()).forEach(node -> {
groupNodes.remove(node.getKey());
groupNodes.remove(Patterns.SERVER_SPLIT.split(node.getKey(), 2)[1]);
serverSpecificGroups.remove(node.getKey());
serverSpecificGroups.remove(Patterns.SERVER_SPLIT.split(node.getKey(), 2)[1]);
serverSpecificGroups.remove(Patterns.WORLD_SPLIT.split(node.getKey(), 2)[0] + "/" + Patterns.SERVER_SPLIT.split(node.getKey(), 2)[1]);
});
serverSpecificGroups.entrySet().stream().filter(node -> !node.getValue()).forEach(node -> {
groupNodes.remove(node.getKey());
groupNodes.remove(Patterns.SERVER_SPLIT.split(node.getKey(), 2)[1]);
@@ -399,24 +587,26 @@ public abstract class PermissionObject {
}
}
// Apply next priority: serverSpecificGroups
for (Map.Entry<String, Boolean> groupNode : serverSpecificGroups.entrySet()) {
final String rawNode = Patterns.SERVER_SPLIT.split(groupNode.getKey())[1];
// Apply next priorities: serverSpecificGroups and then serverWorldSpecificGroups
for (Map<String, Boolean> m : Arrays.asList(serverSpecificGroups, serverWorldSpecificGroups)) {
for (Map.Entry<String, Boolean> groupNode : m.entrySet()) {
final String rawNode = Patterns.SERVER_SPLIT.split(groupNode.getKey())[1];
// Add the actual group perm node, so other plugins can hook
perms.put(rawNode, groupNode.getValue());
// Add the actual group perm node, so other plugins can hook
perms.put(rawNode, groupNode.getValue());
// Don't add negated groups
if (!groupNode.getValue()) continue;
// Don't add negated groups
if (!groupNode.getValue()) continue;
String groupName = Patterns.DOT_SPLIT.split(rawNode, 2)[1];
if (!excludedGroups.contains(groupName)) {
Group group = plugin.getGroupManager().getGroup(groupName);
if (group != null) {
perms.putAll(group.getLocalPermissions(server, excludedGroups));
} else {
plugin.getLogger().warning("Error whilst refreshing the permissions of '" + objectName + "'." +
"\n The group '" + groupName + "' is not loaded.");
String groupName = Patterns.DOT_SPLIT.split(rawNode, 2)[1];
if (!excludedGroups.contains(groupName)) {
Group group = plugin.getGroupManager().getGroup(groupName);
if (group != null) {
perms.putAll(group.getLocalPermissions(server, excludedGroups));
} else {
plugin.getLogger().warning("Error whilst refreshing the permissions of '" + objectName + "'." +
"\n The group '" + groupName + "' is not loaded.");
}
}
}
}
@@ -424,10 +614,12 @@ public abstract class PermissionObject {
// Apply next priority: userNodes
perms.putAll(userNodes);
// Apply highest priority: serverSpecificNodes
for (Map.Entry<String, Boolean> node : serverSpecificNodes.entrySet()) {
final String rawNode = Patterns.SERVER_SPLIT.split(node.getKey())[1];
perms.put(rawNode, node.getValue());
// Apply final priorities: serverSpecificNodes and then serverWorldSpecificNodes
for (Map<String, Boolean> m : Arrays.asList(serverSpecificNodes, serverWorldSpecificNodes)) {
for (Map.Entry<String, Boolean> node : m.entrySet()) {
final String rawNode = Patterns.SERVER_SPLIT.split(node.getKey())[1];
perms.put(rawNode, node.getValue());
}
}
return perms;
@@ -3,12 +3,14 @@ package me.lucko.luckperms.utils;
import lombok.Getter;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
public class UuidCache {
private Map<String, UUID> cache;
// External UUID --> Internal UUID
private Map<UUID, UUID> cache;
@Getter
private final boolean onlineMode;
@@ -21,18 +23,25 @@ public class UuidCache {
}
}
public UUID getUUID(String name, UUID fallback) {
return onlineMode ? fallback : (cache.containsKey(name) ? cache.get(name) : fallback);
public UUID getUUID(UUID external) {
return onlineMode ? external : (cache.containsKey(external) ? cache.get(external) : external);
}
public void addToCache(String name, UUID uuid) {
if (onlineMode) return;
cache.put(name, uuid);
public UUID getExternalUUID(UUID internal) {
if (onlineMode) return internal;
Optional<UUID> external = cache.entrySet().stream().filter(e -> e.getValue().equals(internal)).map(Map.Entry::getKey).findFirst();
return external.isPresent() ? external.get() : internal;
}
public void clearCache(String name) {
public void addToCache(UUID external, UUID internal) {
if (onlineMode) return;
cache.remove(name);
cache.put(external, internal);
}
public void clearCache(UUID external) {
if (onlineMode) return;
cache.remove(external);
}
}