Need to operate on perms that match a given format.
Wh1rledPeas opened this issue ยท 15 comments
I know that there's no way to get a list of a user's permissions, but I need to remove a set of permissions that match a certain format. For example:
myplugin.classification.*
The discussion as to why I would need to do this is probably too long for this ticket, but rest assured, other implementation requirements are forcing me down this path. I need to remove any permissions that match a particular pattern, then add one known permission back. The list of available permissions not known, with the exception of the permission that must be added. So my plugin has no idea what other permission nodes matching that format, might already exist.
Is there any way to accomplish this?
-Peas
So... Just so I'm clear on things...
If I have the following three permissions granted to a user:
myplugin.classification.this
myplugin.classification.that
myplugin.classification.theotherthing
...and I issue the following api call:
perms.playerRemove("world", "playerName", "myplugin.classification.*");
...that all three of the above permissions should be removed?
-Peas
Vault does not translate invalid permission structures. It will pass-through the permission removal request to the API of the plugin the server is using. If it's a bukkit-perms based plugin this will mean that whatever is registered under myplugin.classification.* will be removed. This does not mean that anything under that namespace will be removed, only those that are registered/grouped into the .* - This is the correct operation, any permission plugin that overrides this functionality is not using bukkit-permission compatible testing. Furthermore, Vault has no control over how permission system implementations function with * permissions. Unfortunately, you're trying to solve a problem that shouldn't exist, because .* permissions are just permissions themselves (based on what bukkit implemented), not wildcard permissions that mean everything.
short result: You're on your own.
Thank you for the clarification. (and for your time answering me) I truly appreciate your insight, as I'm just trying to do this the most efficient way possible.
In my case, the security nodes that could exist for a user are based on programmatic need. In reality, any one user would never have more than 3 or 4 perms at a time, but the total number of possible permissions is about 45 (at this time).
When I change these perms, I need to make sure that I am removing any perms in this node hierarchy before adding the ones that are needed. While it is possible for me to call playerRemove() 45 times, just to make sure there are no existing entries, I don't suppose that is the most efficient way to do this. If the method had an overload that allowed me to pass in an array of perms to remove, this might have been an option, but still probably more overhead than I need.
I have to find a way to implement this. At this point, the only two options I see are...
- Issue the playerRemove() 45 times for all known permutations of possible permissions.
- Use Bukkit's EffectivePermissions() and scan for the nodes I'm interested in, then issue playerRemove().
I've read that using EffectivePermissions() is slow and people have warned against using it. This is a command that will be issued every now and then to change a player's "state" in the game. I can't see it being used more than once or twice a day, even at busy times.
Is this a viable alternative?
Again... Thank you for your insight.
-Peas
@Sleaker is correct about plugins having to supply the -wildcard manually. Not all permission plugins support it, and the Bukkit permissions API doesn't support it at all. In my plugins I do a 'hasPermission' check on all . versions as well when checking permissions. By default the .* node is on FALSE, authors can add the .* node and my plugin will automatically detect it.
Only downside is that adding the .* permission is slow on some permission plugins (recalculating permissibles is slow in Bukkit) and it does require a small test-routine on startup to see if the current permissions plugin supports the *-wildcard.
I handle all of this here (if anyone needs examples) https://github.com/bergerkiller/BKCommonLib/blob/master/src/main/java/com/bergerkiller/bukkit/common/internal/PermissionHandler.java
Similarly, it should be possible to provide your own check on all permissions initialized in Bukkit and disable/remove those that match your wildcard.
No. the result of your operation is 'undefined' - Normal Bukkit permissions require there to be a permission 'myplugin.classification.*' defined that includes the 3 permissions in your top section for what you want to occur. Bukkit-permissions has no sense of a wildcard catch-all. There is no proper way to do what you're wanting to.
@bergerkiller: Thanks for chiming in. At this point, the server I'm developing custom functionality for is using PEX, which seems to handle (.*) just fine (as well as regular expressions if I so choose) So I really don't have any need to get all fancy right now. I'm programming against Vault, to ensure we don't wind up with issues moving forward, if the server owner decides to change permissions back-ends.
The issue I was trying to resolve is not whether or not my plugin has rights to something, but rather what rights does the user have altogether, under a given permission node, so I could remove any nodes defined for the user within that space, before adding back only the ones I wanted.
-Peas
Your other issue is PEX is discontinued, in addition developing against one feature set that has 'unknown' behaviour is going to end up very poorly when switching permission systems.
@Sleaker Well, that also seems to be "up in the air", as there seems to be others maintaining the PEX 1.x code at this time, albeit not very regularly.
But that's exactly why I'm using Vault and not coding directly against PEX. If the server has to dump PEX eventually, I want the code to work without modification. The whole reason Vault exists, right?
I was simply hoping that Vault would give me an easy way to remove a group of permissions, all in one call. Instead, I have to use a loop and attempt to remove each permission that COULD possibly be there. Even if Vault had an overload on the playerRemove() method, that accepted an array of permissions, that might be more efficient. Or if it had the ability to give me a list of permissions on the specified user, that matched a given "search", so I could loop through those perms and remove the ones I want, without having to issue 30+ removal requests, just to find and eradicate one or two perms that happen to exist.
If you want to remove groups of permissions that's what using groups, or grouped permissions through a parent-permission are for. The best case is to have the server owner construct their permissions in a way that is not going to break when they move permission systems. This means either A) use groups for all of these permissions or B) use bukkit-perms parent permissions to group all the permissions they need.
@Sleaker I understand what you're saying, and I truly understand parent permissions an inheritance, but in this case, those types of permissions won't work. Each user can have a plethora of different options enabled or disabled. I had been avoiding getting into the details of the implementation, as it's fairly complex, but here is an example, so hopefully you will understand the situation.
member1:
group: group2_worker_male
permissions:
- plugin.membergender.male
- plugin.memberclass.worker
- plugin.preference3.value
- plugin.preference4.value
...etc...
These "options" which are defined on the user, are used to customize their experience, as well as determining what group they belong in, when they are promoted or demoted. For example...
group2:
inheritance:
- group1
prefix: '&0[&4Group2&0]&7'
permissions:
- plugin.grouptype.member
- groupperm.option1
- groupperm.option2
group2_visitor_male:
inheritance
- group2
prefix: '&0[&6Visitor&0]&7'
permissions:
- -plugin.grouptype.membergroup
- plugin.grouptype.memberclass
- groupperm.option1
group2_visitor_female:
inheritance
- group2
prefix: '&0[&6Visitor&0]&7'
permissions:
- -plugin.grouptype.membergroup
- plugin.grouptype.memberclass
- groupperm.option1
group2_worker_male:
inheritance
- group2_visitor_male
prefix: '&0[&6Worker&0]&7'
permissions:
- groupperm.option1
group2_worker_female:
inheritance
- group2_visitor_female
prefix: '&0[&6Worker&0]&7'
permissions:
- groupperm.option1
(these are just examples. obviously there are more well-thought out differences between groups in the real-world implementation)
So the plugin.membergender.male and plugin.memberclass.worker are used to determine which exact group the member belongs in when they rank up, as well as being used by the plugin to customize their experience. The number of "classes" available, is completely dependent on how many groups the operator defines in their permissions file. I just used Visitor and Worker as two examples.
Then... When the operator issues commands to change someone's class, they are presented with a list of classes available in the permissions file, based on all the groups that have the plugin.grouptype.memberclass permission.
Likewise... When the operator issues commands to change someone's group, they are only presented with a list of groups that have the plugin.grouptype.membergroup permission. The actual group the user is placed in, is calculated by the plugin, based on the parent group that the operator chose, combined with the member's class and gender settings.
So... When the operator chooses to change someone's class, I was hoping to be able to simply remove any permissions that started with "plugin.memberclass.". Since that isn't possible, I instead have to scan the list of groups, looking at the sub-set that have plugin.grouptype.memberclass, parsing out their name to determine the name of the class, then take that resulting list of classes and issue a vault.playerRemove(world, playerName, "plugin.memberclass.{classname}", for each of the classes the operator has defined.
It would have been a lot easier (and less overhead), to have the ability to simply remove any permissions that match a given pattern.
I have solved most (if not all) performance issues, by implementing a local cache of objects, so I can store these calculated lists (classes and groups) after the first time they are generated. It would be nice if I had an event that told me the permissions had been reloaded, but instead I just set the cache timeout to something the operator can deal with.
-Peas
We resolve 'classes' and class-based permissions in heroes by simply assigning groups of permissions to the classes. If they are in the class, they get all the permissions if they aren't they get removed. This is configured in the configs, and the plugin tracks when they should or shouldn't have these permissions. I don't really see any difference to what you're trying to do. You don't need to be using grouped in .* permissions, you can simply have them defined in a config and grouped together.
Also another issue is going to come up with negated nodes having undefined behaviour as bukkit uses hashmapped - non-ordered permissions. Attempting to get a consistency outside of PEX is going to produce undefined results if you have 2 groups both adding and removing a specific permission.
I'm still not getting why you don't think it can't be handled, we have a config for heroes permissions. Any number of classes, any number of specializations. multiple classes at a time, unlimited levels. Permissions can be unlocked at any level. it's all just additive. I have a feeling you might be over-engineering something as I've never run into problems you've described when handling permissions like this. If you are persistent on handling it with wildcards, or scanning then the suggestion is to just program it for one specific permission system.
Just throwing this out there: PEX is not discontinued (anymore): http://dev.bukkit.org/bukkit-plugins/permissionsex/files/ https://github.com/PEXPlugins/PermissionsEx/commits/master
@turt2live Thanks for the references, I knew I saw a post about someone picking up the 1.x version path and continuing on with it. Just couldn't find the post.
@Sleaker Perhaps I am over-engineering it. It wouldn't be the first time this 43 year old software architect has learned new. But I still don't understand how in the world you're going to achieve 50 unique prefixes, with only a handful of "class groups"? There is no way to configure the chat manager with a "formula" to construct prefixes dynamically. It's going to use whatever the highest most setting is, from the inherited permissions.
If I add a class, with a prefix, I still need a different prefix for males vs. females for that class. So that's at least 2 "class groups" per class. So if I have 5 different classes, I have a minimum of 10 "class groups". (10 different prefixes)
Now... When the member ranks up to the next donor rank, the prefixes are all DIFFERENT for the next level of donors. They don't match the prefixes used at the lower rank. And each successive rank, has different prefixes for the classes, than the one before it. So I can't reuse the "class groups" that I used for the first rank level. I have to create all new ones.
Their initial "class" gets reduced down to a designator, and their member rank takes precedence. Their member rank is actually different if they are male or female. Such as a Lord/Lady, Duke/Dutchess, Prince/Princess, King/Queen (best example I can give) With their class designation becoming a single character ahead of their member rank.
So (using only two classes) we have prefixes that look something like the following...
Rank #0:
[Visitor] - Standard perks package
Rank #1:
[Farmer] - Perks package A
[Miner] - Perks Package B
Rank #2
[F Lord] - Perks package A + C
[F Lady] - Perks package A + D
[M Lord] - Perks Package B + E
[M Lady] - Perks Package B + F
Rank #3
[F Duke] - Perks package A + C + G
[F Dutchess] - Perks package A + D + H
[M Duke] - Perks package B + E + I
[M Dutchess] - Perks package B + F + J
Rank #4
[F Prince] - Perks package A + C + G + K
[F Princess] - Perks package A + D + H + L
[M Prince] - Perks package B + E + I + M
[M Princess] - Perks package B + F + J + N
Rank #5
[F King] - Perks package A + C + G + K + O
[F Queen] - Perks package A + D + H + L + P
[M King] - Perks package B + E + I + M + Q
[M Queen] - Perks package B + F + J + N + R
...and this is only representing 2 classes. I have 5 I am dealing with.
As illustrated, I need those additional "class group"s to add additional permissions that were not included with the "donor level 1" classes. Class #1 will add different perks and permissions than Class #2 does, etc. And in certain circumstances, the male classes get different perks than the female classes, as the ranks increase, so I can't even combine the gender.
So... Even if I could somehow make the chat manager construct the user's prefix in some programmatic fashion, I'm still going to need the 50 "class groups", to define the separate sets of permissions, perks, and kits that each of the various classes get at the various rank levels.
If I'm missing something, please help enlighten me. I just don't see how I'm going to apply 50 different perks packages and 50 different prefixes, with only a hand full of different "class groups".
-Peas
Well, the difference boils down to the fact that I need each class/gender combination to have separate prefixes (i.e. male and female players have different prefixes for the same class) and different permissions based on what "perks" they have access to on the server. In addition to that, the "class perks" that apply to one level of donor, are not the same as the ones that apply to the next level of donor. When a user picks a class early in the game, they get some perks, relating to that specific class. As they rank up, even more perks are applied that are relevant only to that class. So I can't just have one class group that applies perks. It's not granular enough.
At best, I at least need a male class and a female class for each class, for each group. So if I have 5 groups of donors, 5 classes, and 2 genders, I have 50 different class groups.
The "classes" in this case affect the members' prefixes and permissions in the game. So it really has a lot less to do with what the plugin needs, and more to do with the user's permissions in-game. (at this point) In order to make this work, I have no choice (that I know of) than requiring a separate group for each of those combinations. .
For instance, the worker class inherits from the traveler class, but contains additional permissions/perks. (i.e access to in-game commands, etc.) And in order to have separate prefixes for Male and Female, I wind up having to have two class groups for each. (I know I didn't represent that in my example)
Whether I add the players to groups, or the groups to players, really doesn't make much difference. That's just a matter of preference. With vault, I can't get a list of players in a group, or a list of groups attached to a player, so I still wind up having to scan the entire set of permissions to build an internal list within my plugin.
If permissions outside of PEX aren't going to be able to support negated permissions, then I hardly see them as a viable solution for anyone that wants to properly use permission inheritance, etc. If that's the case, I guess we'd better pull the source for PEX and keep it around so when things break, we can roll our own.
Sounds like bukkit permissions are a step in the wrong direction.
-Peas