Changed permission system from maps/lists to object based supporting inheritance with unit testing.
This commit is contained in:
@@ -6,33 +6,27 @@ import me.libraryaddict.disguise.utilities.DisguiseUtilities;
|
||||
import me.libraryaddict.disguise.utilities.LibsMsg;
|
||||
import me.libraryaddict.disguise.utilities.TranslateType;
|
||||
import me.libraryaddict.disguise.utilities.parser.params.ParamInfo;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Monster;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class DisguiseParser {
|
||||
private static void doCheck(CommandSender sender, HashMap<ArrayList<String>, Boolean> optionPermissions,
|
||||
ArrayList<String> usedOptions) throws DisguiseParseException {
|
||||
private static void doCheck(CommandSender sender, DisguisePermissions permissions, DisguisePerm disguisePerm,
|
||||
Collection<String> usedOptions) throws DisguiseParseException {
|
||||
|
||||
if (!passesCheck(sender, optionPermissions, usedOptions)) {
|
||||
throw new DisguiseParseException(LibsMsg.D_PARSE_NOPERM, usedOptions.get(usedOptions.size() - 1));
|
||||
if (!permissions.isAllowedDisguise(disguisePerm, usedOptions)) {
|
||||
throw new DisguiseParseException(LibsMsg.D_PARSE_NOPERM,
|
||||
usedOptions.stream().reduce((first, second) -> second).orElse(null));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,213 +95,11 @@ public class DisguiseParser {
|
||||
return perms;
|
||||
}
|
||||
|
||||
private static Pair<ArrayList<String>, Boolean> getOptions(String perm, boolean permitted) {
|
||||
ArrayList<String> list = new ArrayList<>();
|
||||
String[] split = perm.split("\\.");
|
||||
|
||||
for (int i = 1; i < split.length; i++) {
|
||||
String option = split[i];
|
||||
boolean value = option.startsWith("-");
|
||||
|
||||
if (value) {
|
||||
option = option.substring(1);
|
||||
permitted = false;
|
||||
}
|
||||
|
||||
if (option.equals("baby")) {
|
||||
option = "setbaby";
|
||||
}
|
||||
|
||||
list.add(option);
|
||||
}
|
||||
|
||||
return Pair.of(list, permitted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get perms for the node. Returns a hashmap of allowed disguisetypes and their options
|
||||
*/
|
||||
public static HashMap<DisguisePerm, HashMap<ArrayList<String>, Boolean>> getPermissions(CommandSender sender,
|
||||
String permissionNode) {
|
||||
HashMap<DisguisePerm, HashMap<ArrayList<String>, Boolean>> singleDisguises = new HashMap<>();
|
||||
HashMap<DisguisePerm, HashMap<ArrayList<String>, Boolean>> rangeDisguises = new HashMap<>();
|
||||
HashMap<String, Boolean> perms = new HashMap<>();
|
||||
|
||||
for (PermissionAttachmentInfo permission : sender.getEffectivePermissions()) {
|
||||
String perm = permission.getPermission().toLowerCase();
|
||||
|
||||
if (perm.startsWith(permissionNode) && (!perms.containsKey(perm) || !permission.getValue())) {
|
||||
perms.put(perm, permission.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
if (!perms.containsKey(permissionNode + "*") && sender.hasPermission(permissionNode + "*")) {
|
||||
perms.put(permissionNode + "*", true);
|
||||
}
|
||||
|
||||
if (!perms.containsKey(permissionNode + "*.*") && sender.hasPermission(permissionNode + "*.*")) {
|
||||
perms.put(permissionNode + "*.*", true);
|
||||
}
|
||||
|
||||
// The first passthrough
|
||||
// This sets what permissions they can use where a negated permission is refering to the parameters
|
||||
for (Entry<String, Boolean> entry : perms.entrySet()) {
|
||||
String perm = entry.getKey().substring(permissionNode.length());
|
||||
String[] split = perm.split("\\.");
|
||||
|
||||
String disguiseType = split[0];
|
||||
|
||||
// Permission was negated, wasn't refering to parameters
|
||||
if (!entry.getValue() && split.length == 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
DisguisePerm dPerm = DisguiseParser.getDisguisePerm(disguiseType);
|
||||
|
||||
if (dPerm != null) {
|
||||
HashMap<ArrayList<String>, Boolean> list;
|
||||
|
||||
if (singleDisguises.containsKey(dPerm)) {
|
||||
list = singleDisguises.get(dPerm);
|
||||
} else {
|
||||
list = new HashMap<>();
|
||||
singleDisguises.put(dPerm, list);
|
||||
}
|
||||
|
||||
Pair<ArrayList<String>, Boolean> options = getOptions(perm, entry.getValue());
|
||||
|
||||
list.put(options.getKey(), options.getValue());
|
||||
} else {
|
||||
for (DisguisePerm type : getDisguisePerms()) {
|
||||
Pair<ArrayList<String>, Boolean> options = null;
|
||||
Class entityClass = type.getEntityClass();
|
||||
|
||||
if (disguiseType.equals("mob")) {
|
||||
if (type.isMob()) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
} else if (disguiseType.equals("animal") || disguiseType.equals("animals")) {
|
||||
if (Animals.class.isAssignableFrom(entityClass)) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
} else if (disguiseType.equals("monster") || disguiseType.equals("monsters")) {
|
||||
if (Monster.class.isAssignableFrom(entityClass)) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
} else if (disguiseType.equals("misc")) {
|
||||
if (type.isMisc()) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
} else if (disguiseType.equals("ageable")) {
|
||||
if (Ageable.class.isAssignableFrom(entityClass)) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
} else if (disguiseType.equals("*")) {
|
||||
options = getOptions(perm, entry.getValue());
|
||||
}
|
||||
|
||||
if (options != null) {
|
||||
HashMap<ArrayList<String>, Boolean> list = rangeDisguises
|
||||
.computeIfAbsent(type, k -> new HashMap<>());
|
||||
|
||||
list.put(new ArrayList<>(options.getKey()), options.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Find disguises to negate, only removes does not add
|
||||
for (String perm : perms.keySet()) {
|
||||
// If not negated, continue
|
||||
if (perms.get(perm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
perm = perm.substring(permissionNode.length());
|
||||
|
||||
String[] split = perm.split("\\.");
|
||||
|
||||
// Permission has parameters, which means the parameters were negated not the disguise
|
||||
if (split.length > 1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String disguiseType = split[0];
|
||||
|
||||
DisguisePerm dType = DisguiseParser.getDisguisePerm(disguiseType);
|
||||
|
||||
if (dType != null) {
|
||||
singleDisguises.remove(dType);
|
||||
rangeDisguises.remove(dType);
|
||||
} else {
|
||||
for (DisguisePerm type : getDisguisePerms()) {
|
||||
boolean foundDisguiseType = false;
|
||||
Class entityClass = type.getEntityClass();
|
||||
|
||||
switch (disguiseType) {
|
||||
case "mob":
|
||||
if (type.isMob()) {
|
||||
foundDisguiseType = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case "animal":
|
||||
case "animals":
|
||||
if (Animals.class.isAssignableFrom(entityClass)) {
|
||||
foundDisguiseType = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case "monster":
|
||||
case "monsters":
|
||||
if (Monster.class.isAssignableFrom(entityClass)) {
|
||||
foundDisguiseType = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case "misc":
|
||||
if (type.isMisc()) {
|
||||
foundDisguiseType = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case "ageable":
|
||||
if (Ageable.class.isAssignableFrom(entityClass)) {
|
||||
foundDisguiseType = true;
|
||||
}
|
||||
|
||||
break;
|
||||
case "*":
|
||||
foundDisguiseType = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (foundDisguiseType) {
|
||||
rangeDisguises.remove(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HashMap<DisguisePerm, HashMap<ArrayList<String>, Boolean>> map = new HashMap<>();
|
||||
|
||||
for (DisguisePerm type : getDisguisePerms()) {
|
||||
HashMap<ArrayList<String>, Boolean> temp = new HashMap<>();
|
||||
|
||||
if (singleDisguises.containsKey(type)) {
|
||||
temp.putAll(singleDisguises.get(type));
|
||||
}
|
||||
|
||||
if (rangeDisguises.containsKey(type)) {
|
||||
temp.putAll(rangeDisguises.get(type));
|
||||
}
|
||||
|
||||
if (!temp.isEmpty()) {
|
||||
map.put(type, temp);
|
||||
}
|
||||
}
|
||||
|
||||
return map;
|
||||
public static DisguisePermissions getPermissions(CommandSender sender, String commandName) {
|
||||
return new DisguisePermissions(sender, commandName);
|
||||
}
|
||||
|
||||
private static boolean isDouble(String string) {
|
||||
@@ -352,13 +144,13 @@ public class DisguiseParser {
|
||||
* disguise has been feed a proper disguisetype.
|
||||
*/
|
||||
public static Disguise parseDisguise(CommandSender sender, String permNode, String[] args,
|
||||
HashMap<DisguisePerm, HashMap<ArrayList<String>, Boolean>> permissionMap) throws DisguiseParseException,
|
||||
IllegalAccessException, InvocationTargetException {
|
||||
DisguisePermissions permissions) throws DisguiseParseException, IllegalAccessException,
|
||||
InvocationTargetException {
|
||||
if (sender instanceof Player) {
|
||||
DisguiseUtilities.setCommandsUsed();
|
||||
}
|
||||
|
||||
if (permissionMap.isEmpty()) {
|
||||
if (!permissions.hasPermissions()) {
|
||||
throw new DisguiseParseException(LibsMsg.NO_PERM);
|
||||
}
|
||||
|
||||
@@ -372,7 +164,7 @@ public class DisguiseParser {
|
||||
int toSkip = 1;
|
||||
ArrayList<String> usedOptions = new ArrayList<>();
|
||||
Disguise disguise = null;
|
||||
HashMap<ArrayList<String>, Boolean> optionPermissions;
|
||||
DisguisePerm disguisePerm;
|
||||
|
||||
if (args[0].startsWith("@")) {
|
||||
if (sender.hasPermission("libsdisguises.disguise.disguiseclone")) {
|
||||
@@ -385,11 +177,21 @@ public class DisguiseParser {
|
||||
throw new DisguiseParseException(LibsMsg.PARSE_NO_PERM_REF);
|
||||
}
|
||||
|
||||
optionPermissions = (permissionMap.containsKey(new DisguisePerm(disguise.getType())) ?
|
||||
permissionMap.get(new DisguisePerm(disguise.getType())) :
|
||||
new HashMap<ArrayList<String>, Boolean>());
|
||||
disguisePerm = new DisguisePerm(disguise.getType());
|
||||
|
||||
if (disguisePerm.isUnknown()) {
|
||||
throw new DisguiseParseException(LibsMsg.PARSE_CANT_DISG_UNKNOWN);
|
||||
}
|
||||
|
||||
if (disguisePerm.getEntityType() == null) {
|
||||
throw new DisguiseParseException(LibsMsg.PARSE_CANT_LOAD);
|
||||
}
|
||||
|
||||
if (!permissions.isAllowedDisguise(disguisePerm)) {
|
||||
throw new DisguiseParseException(LibsMsg.NO_PERM_DISGUISE);
|
||||
}
|
||||
} else {
|
||||
DisguisePerm disguisePerm = getDisguisePerm(args[0]);
|
||||
disguisePerm = getDisguisePerm(args[0]);
|
||||
Entry<String, Disguise> customDisguise = DisguiseConfig.getCustomDisguise(args[0]);
|
||||
|
||||
if (customDisguise != null) {
|
||||
@@ -408,12 +210,10 @@ public class DisguiseParser {
|
||||
throw new DisguiseParseException(LibsMsg.PARSE_CANT_LOAD);
|
||||
}
|
||||
|
||||
if (!permissionMap.containsKey(disguisePerm)) {
|
||||
if (!permissions.isAllowedDisguise(disguisePerm)) {
|
||||
throw new DisguiseParseException(LibsMsg.NO_PERM_DISGUISE);
|
||||
}
|
||||
|
||||
optionPermissions = permissionMap.get(disguisePerm);
|
||||
|
||||
HashMap<String, Boolean> disguiseOptions = getDisguiseOptions(sender, permNode, disguisePerm);
|
||||
|
||||
if (disguise == null) {
|
||||
@@ -441,7 +241,7 @@ public class DisguiseParser {
|
||||
if (args[1].equalsIgnoreCase(TranslateType.DISGUISE_OPTIONS.get("baby")) ||
|
||||
args[1].equalsIgnoreCase(TranslateType.DISGUISE_OPTIONS.get("adult"))) {
|
||||
usedOptions.add("setbaby");
|
||||
doCheck(sender, optionPermissions, usedOptions);
|
||||
doCheck(sender, permissions, disguisePerm, usedOptions);
|
||||
adult = args[1].equalsIgnoreCase(TranslateType.DISGUISE_OPTIONS.get("adult"));
|
||||
|
||||
toSkip++;
|
||||
@@ -539,15 +339,15 @@ public class DisguiseParser {
|
||||
if (disguisePerm.getType() == DisguiseType.FALLING_BLOCK) {
|
||||
usedOptions.add("setblock");
|
||||
|
||||
doCheck(sender, optionPermissions, usedOptions);
|
||||
doCheck(sender, permissions, disguisePerm, usedOptions);
|
||||
} else if (disguisePerm.getType() == DisguiseType.PAINTING) {
|
||||
usedOptions.add("setpainting");
|
||||
|
||||
doCheck(sender, optionPermissions, usedOptions);
|
||||
doCheck(sender, permissions, disguisePerm, usedOptions);
|
||||
} else if (disguisePerm.getType() == DisguiseType.SPLASH_POTION) {
|
||||
usedOptions.add("setpotionid");
|
||||
|
||||
doCheck(sender, optionPermissions, usedOptions);
|
||||
doCheck(sender, permissions, disguisePerm, usedOptions);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,14 +366,14 @@ public class DisguiseParser {
|
||||
String[] newArgs = new String[args.length - toSkip];
|
||||
System.arraycopy(args, toSkip, newArgs, 0, args.length - toSkip);
|
||||
|
||||
callMethods(sender, disguise, optionPermissions, usedOptions, newArgs);
|
||||
callMethods(sender, disguise, permissions, disguisePerm, usedOptions, newArgs);
|
||||
|
||||
// Alright. We've constructed our disguise.
|
||||
return disguise;
|
||||
}
|
||||
|
||||
public static void callMethods(CommandSender sender, Disguise disguise,
|
||||
HashMap<ArrayList<String>, Boolean> optionPermissions, ArrayList<String> usedOptions,
|
||||
public static void callMethods(CommandSender sender, Disguise disguise, DisguisePermissions disguisePermission,
|
||||
DisguisePerm disguisePerm, Collection<String> usedOptions,
|
||||
String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException,
|
||||
DisguiseParseException {
|
||||
Method[] methods = ParamInfoManager.getDisguiseWatcherMethods(disguise.getWatcher().getClass());
|
||||
@@ -642,7 +442,7 @@ public class DisguiseParser {
|
||||
usedOptions.add(methodToUse.getName().toLowerCase());
|
||||
}
|
||||
|
||||
doCheck(sender, optionPermissions, usedOptions);
|
||||
doCheck(sender, disguisePermission, disguisePerm, usedOptions);
|
||||
|
||||
if (FlagWatcher.class.isAssignableFrom(methodToUse.getDeclaringClass())) {
|
||||
methodToUse.invoke(disguise.getWatcher(), valueToSet);
|
||||
@@ -651,35 +451,4 @@ public class DisguiseParser {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean passesCheck(CommandSender sender, HashMap<ArrayList<String>, Boolean> theirPermissions,
|
||||
ArrayList<String> usedOptions) {
|
||||
if (theirPermissions == null)
|
||||
return false;
|
||||
|
||||
boolean hasPermission = false;
|
||||
|
||||
for (ArrayList<String> list : theirPermissions.keySet()) {
|
||||
boolean myPerms = true;
|
||||
|
||||
for (String option : usedOptions) {
|
||||
if (!sender.getName().equals("CONSOLE") && option.equalsIgnoreCase("setInvisible") &&
|
||||
DisguiseConfig.isDisabledInvisibility()) {
|
||||
myPerms = false;
|
||||
}
|
||||
|
||||
if (!(theirPermissions.get(list) && list.contains("*")) &&
|
||||
(list.contains(option) != theirPermissions.get(list))) {
|
||||
myPerms = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (myPerms) {
|
||||
hasPermission = true;
|
||||
}
|
||||
}
|
||||
|
||||
return hasPermission;
|
||||
}
|
||||
}
|
||||
|
@@ -85,4 +85,9 @@ public class DisguisePerm {
|
||||
|
||||
return Objects.equals(permName, other.permName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DisguisePerm{" + "disguiseType=" + disguiseType + ", permName='" + permName + '\'' + '}';
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,441 @@
|
||||
package me.libraryaddict.disguise.utilities.parser;
|
||||
|
||||
import me.libraryaddict.disguise.DisguiseConfig;
|
||||
import me.libraryaddict.disguise.disguisetypes.DisguiseType;
|
||||
import org.bukkit.entity.Ageable;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.Monster;
|
||||
import org.bukkit.permissions.Permissible;
|
||||
import org.bukkit.permissions.PermissionAttachmentInfo;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* Created by libraryaddict on 14/10/2018.
|
||||
*/
|
||||
public class DisguisePermissions {
|
||||
private class PermissionStorage {
|
||||
private DisguisePerm disguisePerm;
|
||||
private List<String> permittedOptions = new ArrayList<>();
|
||||
private List<String> negatedOptions = new ArrayList<>();
|
||||
private boolean wildcardAllow = false;
|
||||
|
||||
public PermissionStorage(DisguisePerm disguisePerm) {
|
||||
this.disguisePerm = disguisePerm;
|
||||
}
|
||||
|
||||
public DisguisePerm getDisguise() {
|
||||
return this.disguisePerm;
|
||||
}
|
||||
}
|
||||
|
||||
private class ParsedPermission {
|
||||
private Vector<DisguisePerm> disguisePerm;
|
||||
private HashMap<String, Boolean> options;
|
||||
private boolean negated;
|
||||
/**
|
||||
* 0 = Names a specific disguise
|
||||
* 1 = Animal
|
||||
* 2 = Monster
|
||||
* 3... = etc
|
||||
* 4 = * = Disguise wildcard
|
||||
*/
|
||||
private byte inheritance;
|
||||
private boolean wildcardCommand;
|
||||
|
||||
public ParsedPermission(DisguisePerm[] disguisePerm, HashMap<String, Boolean> options, byte inheritance,
|
||||
boolean wildcardCommand) {
|
||||
this.disguisePerm = new Vector<>(Arrays.asList(disguisePerm));
|
||||
this.options = options;
|
||||
this.inheritance = inheritance;
|
||||
this.wildcardCommand = wildcardCommand;
|
||||
}
|
||||
|
||||
public boolean isWildcardCommand() {
|
||||
return wildcardCommand;
|
||||
}
|
||||
|
||||
public boolean isDisguise(DisguisePerm perm) {
|
||||
return disguisePerm.contains(perm);
|
||||
}
|
||||
|
||||
public boolean isNegated() {
|
||||
return negated;
|
||||
}
|
||||
|
||||
public void setNegated(boolean negated) {
|
||||
this.negated = negated;
|
||||
}
|
||||
|
||||
public byte getInheritance() {
|
||||
return inheritance;
|
||||
}
|
||||
}
|
||||
|
||||
class DisguisePermitted {
|
||||
private boolean strictAllowed;
|
||||
private List<String> optionsAllowed;
|
||||
private List<String> optionsForbidden;
|
||||
|
||||
public DisguisePermitted(List<String> optionsAllowed, List<String> optionsForbidden, boolean strict) {
|
||||
this.strictAllowed = strict;
|
||||
this.optionsAllowed = optionsAllowed;
|
||||
this.optionsForbidden = optionsForbidden;
|
||||
}
|
||||
|
||||
public boolean isStrictAllowed() {
|
||||
return strictAllowed;
|
||||
}
|
||||
|
||||
public List<String> getOptionsAllowed() {
|
||||
return optionsAllowed;
|
||||
}
|
||||
|
||||
public List<String> getOptionsForbidden() {
|
||||
return optionsForbidden;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* List of PermissionStorage that the permission holder is able to use
|
||||
*/
|
||||
private List<PermissionStorage> disguises = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* @param permissionHolder The permissions to check
|
||||
* @param commandName A lowercase string consisting of the name of one of Lib's Disguises commands
|
||||
*/
|
||||
public DisguisePermissions(Permissible permissionHolder, String commandName) {
|
||||
loadPermissions(permissionHolder, commandName.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* @return If any of the disguises can be used
|
||||
*/
|
||||
public boolean hasPermissions() {
|
||||
return !disguises.isEmpty();
|
||||
}
|
||||
|
||||
public Collection<DisguisePerm> getAllowed() {
|
||||
ArrayList<DisguisePerm> list = new ArrayList<>();
|
||||
|
||||
for (PermissionStorage allowed : disguises) {
|
||||
if (list.contains(allowed.getDisguise())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(allowed.getDisguise());
|
||||
}
|
||||
|
||||
list.sort((perm1, perm2) -> String.CASE_INSENSITIVE_ORDER.compare(perm1.toReadable(), perm2.toReadable()));
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
private ParsedPermission parsePermission(String permission) {
|
||||
// libsdisguises.disguise.sheep
|
||||
String[] split = permission.split("\\.");
|
||||
|
||||
String disguiseName = split[2];
|
||||
|
||||
DisguisePerm dPerm = DisguiseParser.getDisguisePerm(disguiseName);
|
||||
HashMap<String, Boolean> options = getOptions(permission);
|
||||
|
||||
// If this refers to a specific disguise
|
||||
if (dPerm != null) {
|
||||
return new ParsedPermission(new DisguisePerm[]{dPerm}, options, (byte) 0, split[1].equals("*"));
|
||||
}
|
||||
|
||||
// If the disguise can't be found, it may be refering to a range
|
||||
List<DisguisePerm> disguisePerms = new ArrayList<>();
|
||||
int inheritance = 0;
|
||||
|
||||
for (DisguisePerm disguisePerm : DisguiseParser.getDisguisePerms()) {
|
||||
int inherit = getInheritance(disguisePerm, disguiseName);
|
||||
|
||||
if (inherit < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
inheritance = inherit;
|
||||
|
||||
disguisePerms.add(disguisePerm);
|
||||
}
|
||||
|
||||
// If there were no disguises that can be found by that name
|
||||
if (disguisePerms.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ParsedPermission(disguisePerms.toArray(new DisguisePerm[0]), options, (byte) inheritance,
|
||||
split[1].equals("*"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate permissions.
|
||||
* <p>
|
||||
* A specified disguise (cow) and disguise range (animal) differs in that
|
||||
* A disguise range cannot negate a specific disguise, players will be allowed to use cow if animal is negated
|
||||
* <p>
|
||||
* Options on a permission limits the player, if the options start with a - then only those options can't be used
|
||||
* on a disguise
|
||||
* If they're using multiple permissions targetting the same disguise, it attempts to check for a permission that
|
||||
* can be used with the provided requirements
|
||||
* If a permission is negated, then unless specifically permitted, those permissions can't be used. It obeys the
|
||||
* laws of ranges and specific disguises
|
||||
*/
|
||||
private void loadPermissions(Permissible sender, String commandName) {
|
||||
String permissionNode = "libsdisguises." + commandName + ".";
|
||||
Map<String, Boolean> permissions = new HashMap<>();
|
||||
|
||||
// If the command sender is OP, then this will work even as the below code doesn't
|
||||
for (String perm : new String[]{permissionNode + "*", "libsdisguises.*.*"}) {
|
||||
if (!sender.hasPermission(perm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
permissions.put(perm, true);
|
||||
}
|
||||
|
||||
for (PermissionAttachmentInfo permission : sender.getEffectivePermissions()) {
|
||||
String perm = permission.getPermission().toLowerCase();
|
||||
|
||||
String[] split = perm.split("\\.");
|
||||
|
||||
// If there are not enough arguments
|
||||
if (split.length < 3) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this is not a lib's disguises permission
|
||||
if (!split[0].equals("libsdisguises")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the command name does not match
|
||||
if (!split[1].equals("*") && !split[1].equals(commandName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's already contained in the map, and is true. Allow negating permissions to continue
|
||||
if (permissions.containsKey(perm) && permission.getValue()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
permissions.put(perm, permission.getValue());
|
||||
}
|
||||
|
||||
// First get all the disguises that can be affected
|
||||
// Then load all the permissions we can
|
||||
// Each time there's a parent permission set, the child inherits unless specified in a child of that parent
|
||||
|
||||
// DisguisePerm[]
|
||||
// Option[]
|
||||
// Negated
|
||||
|
||||
List<ParsedPermission> list = new ArrayList<>();
|
||||
|
||||
for (Map.Entry<String, Boolean> entry : permissions.entrySet()) {
|
||||
ParsedPermission temp = parsePermission(entry.getKey());
|
||||
|
||||
if (temp == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
temp.setNegated(!entry.getValue());
|
||||
|
||||
list.add(temp);
|
||||
}
|
||||
|
||||
// Sorted from 5 to 0 where "*" is first and "Cow" is last
|
||||
// Negated permissions are last in each inheritance, so false, false, true, true
|
||||
|
||||
list.sort((t1, t2) -> {
|
||||
// Wilcard commands have little say, so they go first so they can be negated by following permissions
|
||||
if (t1.isWildcardCommand() != t2.isWildcardCommand()) {
|
||||
return Boolean.compare(t2.isWildcardCommand(), t1.isWildcardCommand());
|
||||
}
|
||||
|
||||
if (t1.getInheritance() == t2.getInheritance()) {
|
||||
return Boolean.compare(t1.isNegated(), t2.isNegated());
|
||||
}
|
||||
|
||||
return t2.getInheritance() - t1.getInheritance();
|
||||
});
|
||||
|
||||
for (DisguisePerm disguisePerm : DisguiseParser.getDisguisePerms()) {
|
||||
// Use boolean instead of setting to null, to inherit
|
||||
boolean disabled = true;
|
||||
PermissionStorage storage = new PermissionStorage(disguisePerm);
|
||||
|
||||
for (ParsedPermission parsedPermission : list) {
|
||||
// If this parsed permission doesn't handle this disguise type
|
||||
if (!parsedPermission.isDisguise(disguisePerm)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// A negated permission with no options, disables the disguise
|
||||
if (parsedPermission.isNegated() && parsedPermission.options.isEmpty()) {
|
||||
// Remove disguise
|
||||
disabled = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// The permission is negated, and only has negated options. Should mean something, but to most people
|
||||
// it's nonsense and should be ignored.
|
||||
if (parsedPermission.isNegated() && !parsedPermission.options.values().contains(true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parsedPermission.isNegated()) {
|
||||
// Enable the disguise if permission isn't negated
|
||||
// A negated permission cannot enable access
|
||||
if (disabled) {
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
// If the child disguise does not have any options defined, give them wildcard by default
|
||||
if (parsedPermission.options.isEmpty()) {
|
||||
storage.wildcardAllow = true;
|
||||
// If this disguise has options defined, unless wildcard was explictly given then remove it
|
||||
} else if (!storage.permittedOptions.contains("*")) {
|
||||
storage.wildcardAllow = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (Map.Entry<String, Boolean> entry : parsedPermission.options.entrySet()) {
|
||||
// If permission is negated, reverse the option from 'allowed' to 'denied' or vice versa
|
||||
boolean allowUse = parsedPermission.isNegated() ? !entry.getValue() : entry.getValue();
|
||||
|
||||
storage.permittedOptions.remove(entry.getKey());
|
||||
storage.negatedOptions.remove(entry.getKey());
|
||||
|
||||
// Handle wildcard options
|
||||
if (entry.getKey().equals("*")) {
|
||||
// If it's a negated wildcard, then they don't want the user to use anything
|
||||
// If it's a permitted wildcard, then they want the user to use everything
|
||||
|
||||
// Both want to clear the existing restrictions
|
||||
storage.permittedOptions.clear();
|
||||
storage.negatedOptions.clear();
|
||||
|
||||
// Add wildcard allow so if the user later defines "setBaby" just to be sure, it doesn't
|
||||
// limit them to setbaby
|
||||
storage.wildcardAllow = allowUse;
|
||||
|
||||
// Negated wants to prevent the use of all options
|
||||
if (!allowUse) {
|
||||
storage.permittedOptions.add("nooptions");
|
||||
}
|
||||
}
|
||||
|
||||
if (allowUse) {
|
||||
storage.permittedOptions.add(entry.getKey());
|
||||
} else {
|
||||
storage.negatedOptions.add(entry.getKey());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Disguise is not allowed, continue
|
||||
if (disabled) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If invisibility was disabled in the config, ignore permissions and make sure it's disabled
|
||||
if (DisguiseConfig.isDisabledInvisibility()) {
|
||||
storage.permittedOptions.remove("setinvisible");
|
||||
storage.negatedOptions.add("setinvisible");
|
||||
}
|
||||
|
||||
disguises.add(storage);
|
||||
}
|
||||
}
|
||||
|
||||
private int getInheritance(DisguisePerm disguisePerm, String permissionName) {
|
||||
DisguiseType disguiseType = disguisePerm.getType();
|
||||
|
||||
if (permissionName.equals("ageable")) {
|
||||
if (Ageable.class.isAssignableFrom(disguiseType.getEntityClass())) {
|
||||
return 1;
|
||||
}
|
||||
} else if (permissionName.equals("monster") || permissionName.equals("monsters")) {
|
||||
if (Monster.class.isAssignableFrom(disguiseType.getEntityClass())) {
|
||||
return 2;
|
||||
}
|
||||
} else if (permissionName.equals("animal") || permissionName.equals("animals")) {
|
||||
if (Animals.class.isAssignableFrom(disguiseType.getEntityClass())) {
|
||||
return 2;
|
||||
}
|
||||
} else if (permissionName.equals("mob")) {
|
||||
if (disguiseType.isMob()) {
|
||||
return 3;
|
||||
}
|
||||
} else if (permissionName.equals("misc")) {
|
||||
if (disguiseType.isMisc()) {
|
||||
return 3;
|
||||
}
|
||||
} else if (permissionName.equals("*")) {
|
||||
return 4;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private HashMap<String, Boolean> getOptions(String perm) {
|
||||
HashMap<String, Boolean> options = new HashMap<>();
|
||||
String[] split = perm.split("\\.");
|
||||
|
||||
for (int i = 3; i < split.length; i++) {
|
||||
String option = split[i];
|
||||
boolean negated = option.startsWith("-");
|
||||
|
||||
if (negated) {
|
||||
option = option.substring(1);
|
||||
}
|
||||
|
||||
if (option.equals("baby")) {
|
||||
option = "setbaby";
|
||||
}
|
||||
|
||||
options.put(option, !negated);
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
/**
|
||||
* If this DisguisePermission can use the provided disguise and options
|
||||
*
|
||||
* @param disguisePerm
|
||||
* @param disguiseOptions
|
||||
* @return true if permitted
|
||||
*/
|
||||
public boolean isAllowedDisguise(DisguisePerm disguisePerm, Collection<String> disguiseOptions) {
|
||||
PermissionStorage storage = getStorage(disguisePerm);
|
||||
|
||||
if (storage == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the disguise doesn't have a wildcard allow on it
|
||||
// If the user is limited to a select range of options, and not all the options were found in the allowed
|
||||
// options
|
||||
if (!storage.wildcardAllow && !storage.permittedOptions.isEmpty() &&
|
||||
!disguiseOptions.stream().allMatch(option -> storage.permittedOptions.contains(option.toLowerCase()))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the user is using a forbidden option, return false. Otherwise true
|
||||
return disguiseOptions.stream().noneMatch(option -> storage.negatedOptions.contains(option.toLowerCase()));
|
||||
}
|
||||
|
||||
public boolean isAllowedDisguise(DisguisePerm disguisePerm) {
|
||||
return getStorage(disguisePerm) != null;
|
||||
}
|
||||
|
||||
private PermissionStorage getStorage(DisguisePerm disguisePerm) {
|
||||
return disguises.stream().filter(disguise -> disguise.getDisguise().equals(disguisePerm)).findAny()
|
||||
.orElse(null);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user