/* * To change this template, choose Tools | Templates * and open the template in the editor. */ package org.anjocaido.groupmanager.permissions; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import org.anjocaido.groupmanager.GroupManager; import org.anjocaido.groupmanager.data.Group; import org.anjocaido.groupmanager.data.User; import org.anjocaido.groupmanager.dataholder.WorldDataHolder; import org.anjocaido.groupmanager.utils.PermissionCheckResult; import org.bukkit.Bukkit; import org.bukkit.entity.Player; /** * Everything here maintains the model created by Nijikokun * * But implemented to use GroupManager system. Which provides instant changes, * without file access. * * It holds permissions only for one single world. * * @author gabrielcouto, ElgarL */ public class AnjoPermissionsHandler extends PermissionsReaderInterface { WorldDataHolder ph = null; /** * It needs a WorldDataHolder to work with. * * @param holder */ public AnjoPermissionsHandler(final WorldDataHolder holder) { ph = holder; } @Override public void addGroupInfo(final String name, final String path, final Object data) { ph.getGroup(name).getVariables().addVar(path, data); } @Override public void addUserInfo(final String name, final String path, final Object data) { ph.getUser(name).getVariables().addVar(path, data); } /** * Checks the specified group for the Info Build node. Does NOT check * inheritance * * @param groupName * @return true if can build */ @Override public boolean canGroupBuild(final String groupName) { final Group g = ph.getGroup(groupName); if (g == null) { return false; } return g.getVariables().getVarBoolean("build"); } /** * Check if user can build. Checks inheritance and subgroups. * * @param userName * Player's name * @return true if the user can build */ public boolean canUserBuild(final String userName) { return getPermissionBoolean(userName, "build"); } /** * Wrapper for offline server checks. * Looks for the 'groupmanager.noofflineperms' permissions and reports no permissions on servers set to offline. * * Check user and groups with inheritance and Bukkit if bukkit = true return * a PermissionCheckResult. * * @param user * @param targetPermission * @param checkBukkit * @return PermissionCheckResult */ public PermissionCheckResult checkFullGMPermission(final User user, final String targetPermission, final Boolean checkBukkit) { /* * Report no permissions under the following conditions. * * We are in offline mode * and the player has the 'groupmanager.noofflineperms' permission. */ if (user == null || targetPermission == null || targetPermission.isEmpty() || (!Bukkit.getServer().getOnlineMode() && (checkPermission(user, "groupmanager.noofflineperms", false).resultType == PermissionCheckResult.Type.FOUND))) { final PermissionCheckResult result = new PermissionCheckResult(); result.accessLevel = targetPermission; result.resultType = PermissionCheckResult.Type.NOTFOUND; return result; } return checkPermission(user, targetPermission, checkBukkit); } /** * Do what checkUserPermission did before. But now returning a * PermissionCheckResult. * * @param user * @param targetPermission * @return PermissionCheckResult */ public PermissionCheckResult checkFullUserPermission(final User user, final String targetPermission) { return checkFullGMPermission(user, targetPermission, true); } /** * Returns the node responsible for that permission. Does not include User's * group permission. * * @param group * @param permission * @return the node if permission is found. if not found, return null */ public PermissionCheckResult checkGroupOnlyPermission(final Group group, final String permission) { group.sortPermissions(); final PermissionCheckResult result = new PermissionCheckResult(); result.owner = group; result.askedPermission = permission; for (final String access : group.getPermissionList()) { result.resultType = comparePermissionString(access, permission); if (result.resultType != PermissionCheckResult.Type.NOTFOUND) { result.accessLevel = access; return result; } } result.resultType = PermissionCheckResult.Type.NOTFOUND; return result; } /** * Returns the result of permission check. Including inheritance. If found * anything, the PermissionCheckResult that retuns will include the Group * name, and the result type. Result types will be EXCEPTION, NEGATION, * FOUND. * * If returned type NOTFOUND, the owner will be null, and ownerType too. * * It does Breadth-first search * * @param start * @param targetPermission * @return PermissionCheckResult */ public PermissionCheckResult checkGroupPermissionWithInheritance(final Group start, final String targetPermission) { if (start == null || targetPermission == null) { return null; } final LinkedList stack = new LinkedList(); final List alreadyVisited = new ArrayList(); PermissionCheckResult result = new PermissionCheckResult(); stack.push(start); alreadyVisited.add(start); // Set defaults. result.askedPermission = targetPermission; result.resultType = PermissionCheckResult.Type.NOTFOUND; while (!stack.isEmpty()) { final Group now = stack.pop(); final PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targetPermission); if (!resultNow.resultType.equals(PermissionCheckResult.Type.NOTFOUND)) { if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION)) { resultNow.accessLevel = targetPermission; return resultNow; } // Negation found so store for later // as we need to continue looking for an Exception. result = resultNow; } for (final String sonName : now.getInherits()) { final Group son = ph.getGroup(sonName); if (son != null && !alreadyVisited.contains(son)) { // Add rather than push to retain inheritance order. stack.add(son); alreadyVisited.add(son); } } } return result; } /** * Does not include User's group permission * * @param user * @param permission * @return PermissionCheckResult */ public PermissionCheckResult checkUserOnlyPermission(final User user, final String permission) { user.sortPermissions(); final PermissionCheckResult result = new PermissionCheckResult(); result.askedPermission = permission; result.owner = user; for (final String access : user.getPermissionList()) { result.resultType = comparePermissionString(access, permission); if (result.resultType != PermissionCheckResult.Type.NOTFOUND) { result.accessLevel = access; return result; } } result.resultType = PermissionCheckResult.Type.NOTFOUND; return result; } /** * Check permissions, including it's group and inheritance. * * @param user * @param permission * @return true if permission was found. false if not, or was negated. */ public boolean checkUserPermission(final User user, final String permission) { final PermissionCheckResult result = checkFullGMPermission(user, permission, true); if (result.resultType == PermissionCheckResult.Type.EXCEPTION || result.resultType == PermissionCheckResult.Type.FOUND) { return true; } return false; } /** * Compare a user permission like 'myplugin.*' against a full plugin * permission name, like 'myplugin.dosomething'. As the example above, will * return true. * * Please sort permissions before sending them here. So negative tokens get * priority. * * You must test if it start with negative outside this method. It will only * tell if the nodes are matching or not. * * Every '-' or '+' in the beginning is ignored. It will match only node * names. * * @param userAccessLevel * @param fullPermissionName * @return PermissionCheckResult.Type */ public PermissionCheckResult.Type comparePermissionString(final String userAccessLevel, final String fullPermissionName) { int userAccessLevelLength; if (userAccessLevel == null || fullPermissionName == null || fullPermissionName.length() == 0 || (userAccessLevelLength = userAccessLevel.length()) == 0) { return PermissionCheckResult.Type.NOTFOUND; } PermissionCheckResult.Type result = PermissionCheckResult.Type.FOUND; int userAccessLevelOffset = 0; if (userAccessLevel.charAt(0) == '+') { userAccessLevelOffset = 1; result = PermissionCheckResult.Type.EXCEPTION; } else if (userAccessLevel.charAt(0) == '-') { userAccessLevelOffset = 1; result = PermissionCheckResult.Type.NEGATION; } if (fullPermissionName.equals(userAccessLevel)) { return result; } if ("groupmanager.noofflineperms".equals(fullPermissionName)) { result = PermissionCheckResult.Type.NOTFOUND; } if ("*".regionMatches(0, userAccessLevel, userAccessLevelOffset, userAccessLevelLength - userAccessLevelOffset)) { return result; } int fullPermissionNameOffset; if (fullPermissionName.charAt(0) == '+' || fullPermissionName.charAt(0) == '-') { fullPermissionNameOffset = 1; } else { fullPermissionNameOffset = 0; } if (userAccessLevel.charAt(userAccessLevel.length() - 1) == '*') { return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, userAccessLevelLength - userAccessLevelOffset - 1) ? result : PermissionCheckResult.Type.NOTFOUND; } return userAccessLevel.regionMatches(true, userAccessLevelOffset, fullPermissionName, fullPermissionNameOffset, Math.max(userAccessLevelLength - userAccessLevelOffset, fullPermissionName.length() - fullPermissionNameOffset)) ? result : PermissionCheckResult.Type.NOTFOUND; } /** * Returns All permissions (including inheritance and sub groups) for the * player, including child nodes from Bukkit. * * @param userName * @return List of all players permissions. */ @Override public List getAllPlayersPermissions(final String userName) { final List perms = new ArrayList(); perms.addAll(getAllPlayersPermissions(userName, true)); return perms; } /** * Returns All permissions (including inheritance and sub groups) for the * player. With or without Bukkit child nodes. * * @param userName * @return Set of all players permissions. */ @Override public Set getAllPlayersPermissions(final String userName, final Boolean includeChildren) { final Set playerPermArray = new LinkedHashSet(); final Set overrides = new LinkedHashSet(); // Add the players own permissions. playerPermArray.addAll(populatePerms(ph.getUser(userName).getPermissionList(), includeChildren)); final ArrayList alreadyProcessed = new ArrayList(); // fetch all group permissions for (final String group : getGroups(userName)) { // Don't process a group more than once. if (!alreadyProcessed.contains(group)) { alreadyProcessed.add(group); Set groupPermArray = new LinkedHashSet(); if (group.startsWith("g:") && GroupManager.getGlobalGroups().hasGroup(group)) { // GlobalGroups groupPermArray = populatePerms(GroupManager.getGlobalGroups().getGroupsPermissions(group), includeChildren); } else { // World Groups groupPermArray = populatePerms(ph.getGroup(group).getPermissionList(), includeChildren); } // Add all group permissions, unless negated by earlier permissions. for (final String perm : groupPermArray) { final boolean negated = (perm.startsWith("-")); // Overridden (Exception) permission defeats negation. if (perm.startsWith("+")) { overrides.add(perm.substring(1)); continue; } // Perm doesn't already exists and there is no negation for it // or It's a negated perm where a normal perm doesn't exists (don't allow inheritance to negate higher perms) if ((!negated && !playerPermArray.contains(perm) && !wildcardNegation(playerPermArray, perm)) || (negated && !playerPermArray.contains(perm.substring(1)) && !wildcardNegation(playerPermArray, perm.substring(1)))) playerPermArray.add(perm); } } } // Process overridden permissions final Iterator itr = overrides.iterator(); while (itr.hasNext()) { final String node = itr.next(); if (playerPermArray.contains("-" + node)) { playerPermArray.remove("-" + node); } playerPermArray.add(node); } // Collections.sort(playerPermArray, StringPermissionComparator.getInstance()); return playerPermArray; } @Override public Group getDefaultGroup() { return ph.getDefaultGroup(); } /** * Returns the name of the group of that player name. * * @param userName * @return String of players group name. */ @Override public String getGroup(final String userName) { return ph.getUser(userName).getGroup().getName(); } /** * Returns a boolean for given variable in INFO node. It will harvest * inheritance for value. * * @param group * @param variable * @return false if not found/not parseable. */ @Override public boolean getGroupPermissionBoolean(final String group, final String variable) { final Group start = ph.getGroup(group); if (start == null) { return false; } final Group result = nextGroupWithVariable(start, variable); if (result == null) { return false; } return result.getVariables().getVarBoolean(variable); } /** * Returns a double value for the given variable name in INFO node. It will * harvest inheritance for value. * * @param group * @param variable * @return -1 if not found / not parseable. */ @Override public double getGroupPermissionDouble(final String group, final String variable) { final Group start = ph.getGroup(group); if (start == null) { return -1; } final Group result = nextGroupWithVariable(start, variable); if (result == null) { return -1; } return result.getVariables().getVarDouble(variable); } /** * It returns a Integer variable value It will harvest inheritance for * value. * * @param groupName * @param variable * @return -1 if none found or not parseable. */ @Override public int getGroupPermissionInteger(final String groupName, final String variable) { final Group start = ph.getGroup(groupName); if (start == null) { return -1; } final Group result = nextGroupWithVariable(start, variable); if (result == null) { return -1; } return result.getVariables().getVarInteger(variable); } /** * It returns a string variable value, set in the INFO node of the group. It * will harvest inheritance for value. * * @param groupName * @param variable * @return null if no group with that variable is found. */ @Override public String getGroupPermissionString(final String groupName, final String variable) { final Group start = ph.getGroup(groupName); if (start == null) { return null; } final Group result = nextGroupWithVariable(start, variable); if (result == null) { return null; } return result.getVariables().getVarString(variable); } /** * Returns the String prefix for the given group * * @param groupName * @return empty string if found none. */ @Override public String getGroupPrefix(final String groupName) { final Group g = ph.getGroup(groupName); if (g == null) { return ""; } return g.getVariables().getVarString("prefix"); } /** * Returns a list of all groups. * * Including subgroups. * * @param userName * @return String[] of all group names. */ @Override public String[] getGroups(final String userName) { final ArrayList allGroups = listAllGroupsInherited(ph.getUser(userName).getGroup()); for (final Group subg : ph.getUser(userName).subGroupListCopy()) { allGroups.addAll(listAllGroupsInherited(subg)); } final String[] arr = new String[allGroups.size()]; return allGroups.toArray(arr); } /** * Return the suffix for the given group name * * @param groupName * @return empty string if not found. */ @Override public String getGroupSuffix(final String groupName) { final Group g = ph.getGroup(groupName); if (g == null) { return ""; } return g.getVariables().getVarString("suffix"); } @Override public boolean getInfoBoolean(final String entryName, final String path, final boolean isGroup) { if (isGroup) { final Group data = ph.getGroup(entryName); if (data == null) { return false; } return data.getVariables().getVarBoolean(path); } final User data = ph.getUser(entryName); if (data == null) { return false; } return data.getVariables().getVarBoolean(path); } @Override public double getInfoDouble(final String entryName, final String path, final boolean isGroup) { if (isGroup) { final Group data = ph.getGroup(entryName); if (data == null) { return -1; } return data.getVariables().getVarDouble(path); } final User data = ph.getUser(entryName); if (data == null) { return -1; } return data.getVariables().getVarDouble(path); } @Override public int getInfoInteger(final String entryName, final String path, final boolean isGroup) { if (isGroup) { final Group data = ph.getGroup(entryName); if (data == null) { return -1; } return data.getVariables().getVarInteger(path); } final User data = ph.getUser(entryName); if (data == null) { return -1; } return data.getVariables().getVarInteger(path); } @Override public String getInfoString(final String entryName, final String path, final boolean isGroup) { if (isGroup) { final Group data = ph.getGroup(entryName); if (data == null) { return null; } return data.getVariables().getVarString(path); } final User data = ph.getUser(entryName); if (data == null) { return null; } return data.getVariables().getVarString(path); } /** * Returns the variable value of the user, in INFO node. If not found, it * will search for his Group variables. It will harvest the inheritance and * subgroups. * * @param user * @param variable * @return false if not found or not parseable to true. */ @Override public boolean getPermissionBoolean(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return false; } if (auser.getVariables().hasVar(variable)) { return auser.getVariables().getVarBoolean(variable); } final Group start = auser.getGroup(); if (start == null) { return false; } Group result = nextGroupWithVariable(start, variable); if (result == null) { // Check sub groups if (!auser.isSubGroupsEmpty()) for (final Group subGroup : auser.subGroupListCopy()) { result = nextGroupWithVariable(subGroup, variable); // Found value? if (result != null) continue; } if (result == null) return false; } return result.getVariables().getVarBoolean(variable); // return getUserPermissionBoolean(user, string1); } /** * Returns the variable value of the user, in INFO node. If not found, it * will search for his Group variables. It will harvest the inheritance and * subgroups. * * @param user * @param variable * @return -1 if not found. */ @Override public double getPermissionDouble(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return -1.0D; } if (auser.getVariables().hasVar(variable)) { return auser.getVariables().getVarDouble(variable); } final Group start = auser.getGroup(); if (start == null) { return -1.0D; } Group result = nextGroupWithVariable(start, variable); if (result == null) { // Check sub groups if (!auser.isSubGroupsEmpty()) for (final Group subGroup : auser.subGroupListCopy()) { result = nextGroupWithVariable(subGroup, variable); // Found value? if (result != null) continue; } if (result == null) return -1.0D; } return result.getVariables().getVarDouble(variable); // return getUserPermissionDouble(string, string1); } /** * Returns the variable value of the user, in INFO node. If not found, it * will search for his Group variables. It will harvest the inheritance and * subgroups. * * @param user * @param variable * @return -1 if not found */ @Override public int getPermissionInteger(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return -1; } if (auser.getVariables().hasVar(variable)) { return auser.getVariables().getVarInteger(variable); } final Group start = auser.getGroup(); if (start == null) { return -1; } Group result = nextGroupWithVariable(start, variable); if (result == null) { // Check sub groups if (!auser.isSubGroupsEmpty()) for (final Group subGroup : auser.subGroupListCopy()) { result = nextGroupWithVariable(subGroup, variable); // Found value? if (result != null) continue; } if (result == null) return -1; } return result.getVariables().getVarInteger(variable); // return getUserPermissionInteger(string, string1); } /** * Returns the variable value of the user, in INFO node. If not found, it * will search for his Group variables. It will harvest the inheritance and * subgroups. * * @param user * @param variable * @return empty string if not found */ @Override public String getPermissionString(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return ""; } if (auser.getVariables().hasVar(variable)) { return auser.getVariables().getVarString(variable); } final Group start = auser.getGroup(); if (start == null) { return ""; } Group result = nextGroupWithVariable(start, variable); if (result == null) { // Check sub groups if (!auser.isSubGroupsEmpty()) for (final Group subGroup : auser.subGroupListCopy()) { result = nextGroupWithVariable(subGroup, variable); // Found value? if (result != null) continue; } if (result == null) return ""; } return result.getVariables().getVarString(variable); // return getUserPermissionString(user, variable); } /** * Gets name of the primary group of the user. Returns the name of the * default group if user has no parent groups, or "Default" if there is no * default group for that world. * * @param user * Player's name * @return Name of player's primary group */ public String getPrimaryGroup(final String user) { return getGroup(user); } /** * Returns the variable value of the user, in INFO node. * * @param user * @param variable * @return boolean value */ @Override public boolean getUserPermissionBoolean(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return false; } return auser.getVariables().getVarBoolean(variable); } /** * Returns the variable value of the user, in INFO node. * * @param user * @param variable * @return -1 if not found */ @Override public double getUserPermissionDouble(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return -1; } return auser.getVariables().getVarDouble(variable); } /** * Returns the variable value of the user, in INFO node. * * @param user * @param variable * @return -1 if not found */ @Override public int getUserPermissionInteger(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return -1; } return auser.getVariables().getVarInteger(variable); } /** * Returns the variable value of the user, in INFO node. * * @param user * @param variable * @return empty string if not found */ @Override public String getUserPermissionString(final String user, final String variable) { final User auser = ph.getUser(user); if (auser == null) { return ""; } return auser.getVariables().getVarString(variable); } /** * Gets the appropriate prefix for the user. This method is a utility method * for chat plugins to get the user's prefix without having to look at every * one of the user's ancestors. Returns an empty string if user has no * parent groups. * * @param user * Player's name * @return Player's prefix */ @Override public String getUserPrefix(final String user) { final String prefix = ph.getUser(user).getVariables().getVarString("prefix"); if (prefix.length() != 0) { return prefix; } return getGroupPrefix(getGroup(user)); } /** * Gets the appropriate prefix for the user. This method is a utility method * for chat plugins to get the user's prefix without having to look at every * one of the user's ancestors. Returns an empty string if user has no * parent groups. * * @param user * Player's name * @return Player's prefix */ @Override public String getUserSuffix(final String user) { final String suffix = ph.getUser(user).getVariables().getVarString("suffix"); if (suffix.length() != 0) { return suffix; } return getGroupSuffix(getGroup(user)); } /** * A short name method, for permission method. * * @param player * @param permission * @return true if the player has the permission */ @Override public boolean has(final Player player, final String permission) { return permission(player, permission); } /** * Check if given group inherits another group. * * It does Breadth-first search * * @param start * The group to start the search. * @param askedGroup * Name of the group you're looking for * @return true if it inherits the group. */ public boolean hasGroupInInheritance(final Group start, final String askedGroup) { if (start == null || askedGroup == null) { return false; } final LinkedList stack = new LinkedList(); final ArrayList alreadyVisited = new ArrayList(); stack.push(start); alreadyVisited.add(start); while (!stack.isEmpty()) { final Group now = stack.pop(); if (now.getName().equalsIgnoreCase(askedGroup)) { return true; } for (final String sonName : now.getInherits()) { final Group son = ph.getGroup(sonName); if (son != null && !alreadyVisited.contains(son)) { stack.push(son); alreadyVisited.add(son); } } } return false; } /** * Verify if player is in such group. It will check it's groups inheritance. * * So if you have a group Admin > Moderator * * And verify the player 'MyAdmin', which is Admin, it will return true for * both Admin or Moderator groups. * * If you have a player 'MyModerator', which is Moderator, it will give * false if you pass Admin in group parameter. * * @param name * @param group * @return true if in group (with inheritance) */ @Override public boolean inGroup(final String name, final String group) { if (hasGroupInInheritance(ph.getUser(name).getGroup(), group)) { return true; } for (final Group subGroup : ph.getUser(name).subGroupListCopy()) { if (hasGroupInInheritance(subGroup, group)) { return true; } } return false; } /** * Return whole list of names of groups in a inheritance chain. Including a * starting group. * * It does Breadth-first search. So closer groups will appear first in list. * * @param start * @return the group that passed on test. null if no group passed. */ public ArrayList listAllGroupsInherited(final Group start) { if (start == null) { return null; } final LinkedList stack = new LinkedList(); final ArrayList alreadyVisited = new ArrayList(); stack.push(start); alreadyVisited.add(start.getName()); while (!stack.isEmpty()) { final Group now = stack.pop(); for (final String sonName : now.getInherits()) { final Group son = ph.getGroup(sonName); if (son != null && !alreadyVisited.contains(son.getName())) { stack.push(son); alreadyVisited.add(son.getName()); } } } return alreadyVisited; } /** * Returns the next group, including inheritance, which contains that * variable name. * * It does Breadth-first search * * @param start * the starting group to look for * @param targetVariable * the variable name * @return The group if found. Null if not. */ public Group nextGroupWithVariable(final Group start, final String targetVariable) { if (start == null || targetVariable == null) { return null; } final LinkedList stack = new LinkedList(); final ArrayList alreadyVisited = new ArrayList(); stack.push(start); alreadyVisited.add(start); while (!stack.isEmpty()) { final Group now = stack.pop(); if (now.getVariables().hasVar(targetVariable)) { return now; } for (final String sonName : now.getInherits()) { final Group son = ph.getGroup(sonName); if (son != null && !alreadyVisited.contains(son)) { stack.push(son); alreadyVisited.add(son); } } } return null; } /** * Checks if a player can use that permission node. * * @param player * @param permission * @return true if the player has the permission */ @Override public boolean permission(final Player player, final String permission) { return checkUserPermission(ph.getUser(player.getName()).updatePlayer(player), permission); } /** * Checks if a player can use that permission node. * * @param playerName * @param permission * @return true if the player has the permission */ public boolean permission(final String playerName, final String permission) { return checkUserPermission(ph.getUser(playerName), permission); } @Override public void removeGroupInfo(final String name, final String path) { ph.getGroup(name).getVariables().removeVar(path); } @Override public void removeUserInfo(final String name, final String path) { ph.getUser(name).getVariables().removeVar(path); } /** * A Breadth-first search thru inheritance model. * * Just a model to copy and paste. This will guarantee the closer groups * will be checked first. * * @param start * @param targerPermission * @return */ @SuppressWarnings("unused") private Group breadthFirstSearch(final Group start, final String targerPermission) { if (start == null || targerPermission == null) { return null; } final LinkedList stack = new LinkedList(); final ArrayList alreadyVisited = new ArrayList(); stack.push(start); alreadyVisited.add(start); while (!stack.isEmpty()) { final Group now = stack.pop(); final PermissionCheckResult resultNow = checkGroupOnlyPermission(now, targerPermission); if (resultNow.resultType.equals(PermissionCheckResult.Type.EXCEPTION) || resultNow.resultType.equals(PermissionCheckResult.Type.FOUND)) { return now; } if (resultNow.resultType.equals(PermissionCheckResult.Type.NEGATION)) { return null; } for (final String sonName : now.getInherits()) { final Group son = ph.getGroup(sonName); if (son != null && !alreadyVisited.contains(son)) { stack.push(son); alreadyVisited.add(son); } } } return null; } /** * * Check user and groups with inheritance and Bukkit if bukkit = true return * a PermissionCheckResult. * * @param user * @param targetPermission * @param checkBukkit * @return PermissionCheckResult */ private PermissionCheckResult checkPermission(final User user, final String targetPermission, final Boolean checkBukkit) { PermissionCheckResult result = new PermissionCheckResult(); result.accessLevel = targetPermission; result.resultType = PermissionCheckResult.Type.NOTFOUND; if (checkBukkit) { // Check Bukkit perms to support plugins which add perms via code // (Heroes). final Player player = user.getBukkitPlayer(); // final Permission bukkitPerm = Bukkit.getPluginManager().getPermission(targetPermission); if ((player != null) && player.hasPermission(targetPermission)) { result.resultType = PermissionCheckResult.Type.FOUND; result.owner = user; return result; } } final PermissionCheckResult resultUser = checkUserOnlyPermission(user, targetPermission); if (resultUser.resultType != PermissionCheckResult.Type.NOTFOUND) { resultUser.accessLevel = targetPermission; if (resultUser.resultType == PermissionCheckResult.Type.EXCEPTION) { return resultUser; } result = resultUser; } // IT ONLY CHECKS GROUPS PERMISSIONS IF RESULT FOR USER IS NOT AN EXCEPTION final PermissionCheckResult resultGroup = checkGroupPermissionWithInheritance(user.getGroup(), targetPermission); if (resultGroup.resultType != PermissionCheckResult.Type.NOTFOUND) { resultGroup.accessLevel = targetPermission; if (resultGroup.resultType == PermissionCheckResult.Type.EXCEPTION) { return resultGroup; } // Do not override higher level permissions with negations. if (result.resultType == PermissionCheckResult.Type.NOTFOUND) { result = resultGroup; } } // Do we have a high level negation? final boolean negated = (result.resultType == PermissionCheckResult.Type.NEGATION); // SUBGROUPS CHECK for (final Group subGroup : user.subGroupListCopy()) { final PermissionCheckResult resultSubGroup = checkGroupPermissionWithInheritance(subGroup, targetPermission); if (resultSubGroup.resultType != PermissionCheckResult.Type.NOTFOUND) { resultSubGroup.accessLevel = targetPermission; // Allow exceptions to override higher level negations // but low level negations can not remove higher level permissions. if (resultSubGroup.resultType == PermissionCheckResult.Type.EXCEPTION) { return resultSubGroup; } else if ((resultSubGroup.resultType == PermissionCheckResult.Type.FOUND) && (result.resultType != PermissionCheckResult.Type.NEGATION) && !negated) { result = resultSubGroup; } else if ((resultSubGroup.resultType == PermissionCheckResult.Type.NEGATION) && !negated) { result = resultSubGroup; } } } // THEN IT RETURNS A NOT FOUND // OR THE RESULT OF THE SUBGROUP SEARCH. return result; } private Set populatePerms(final List permsList, final boolean includeChildren) { // Create a new array so it's modifiable. final List perms = new ArrayList(permsList); final Set permArray = new LinkedHashSet(); Boolean allPerms = false; // Allow * node to populate ALL permissions to Bukkit. if (perms.contains("*")) { permArray.addAll(GroupManager.BukkitPermissions.getAllRegisteredPermissions(includeChildren)); allPerms = true; perms.remove("*"); // Remove the no offline perms node as this should not be given. perms.remove("groupmanager.noofflineperms"); } for (final String perm : perms) { /** * all permission sets are passed here pre-sorted, alphabetically. * This means negated nodes will be processed before all permissions * other than *. */ final boolean negated = perm.startsWith("-"); if (!permArray.contains(perm)) { permArray.add(perm); if ((negated) && (permArray.contains(perm.substring(1)))) permArray.remove(perm.substring(1)); /** * Process child nodes if required, * or this is a negated node AND we used * to include all * permissions, * in which case we need to remove all children of that node. */ if ((includeChildren) || (negated && allPerms)) { final Map children = GroupManager.BukkitPermissions.getAllChildren((negated ? perm.substring(1) : perm), new LinkedHashSet()); if (children != null) { if (negated) if (allPerms) { // Remove children of negated nodes for (final String child : children.keySet()) if (children.get(child)) if (permArray.contains(child)) permArray.remove(child); } else { // Add child nodes for (final String child : children.keySet()) if (children.get(child)) if ((!permArray.contains(child)) && (!permArray.contains("-" + child))) permArray.add(child); } } } } } return permArray; } /** * Is there a direct or wildcard negation in the list which covers this permission node. * * @param playerPermArray * @param node * @return */ private boolean wildcardNegation(final Set playerPermArray, final String node) { /* * Check for a negated parent with a wildcard or negated permission */ if (playerPermArray.contains("-" + node)) return true; final String[] parts = node.split("\\."); final StringBuilder builder = new StringBuilder(node.length()); for (final String part : parts) { builder.append('*'); if (playerPermArray.contains("-" + builder.toString())) { GroupManager.logger.fine("Wildcard Negation found for " + node); return true; } builder.deleteCharAt(builder.length() - 1); builder.append(part).append('.'); } /* * No negated parent found so return false. */ GroupManager.logger.fine("No Negation found for " + node); return false; } }