Add support for regex permissions/servers/worlds and shorthand permissions

This commit is contained in:
Luck 2016-08-09 11:09:45 +02:00
parent 90e074d3ab
commit b70b6f8af1
No known key found for this signature in database
GPG Key ID: EFA9B3EC5FD90F8B
43 changed files with 374 additions and 92 deletions

View File

@ -19,6 +19,8 @@ A permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
* **Developer API** - easily integrate LuckPerms into your own projects
* **Easy and simple setup and configuration using commands** - no editing yml files, yuck
* **Negated permissions and groups** - define special rules for certain users/groups
* **Regex permissions** - define special permissions using regex
* **Shorthand nodes** - add nodes using the LuckPerms shorthand system
* **Full support for UUIDs, even in Offline Mode** - users can change their usernames without losing permissions. In offline mode, a single user has the same internal UUID across a network.
* **Permission data stored within MySQL in a json format** - easily integrate the LuckPerms backend into your other projects
* **Well documented** - API methods have comprehensive Java docs, it's clear what each method does.
@ -37,7 +39,7 @@ You can define the settings for per-server permissions, the storage method and c
### Permission Calculation
#### Permissions are calculated based on a priority system as follows.
* **Non wildcard permissions will override wildcard permissions**
* **Non wildcard/regex permissions will be overridden by normal permissions**
Example: if a user has a true permission set for "luckperms.\*", and a false permission set for "luckperms.something", the non-wildcard permission will override the wildcard, and "luckperms.something" will be set to false, despite the wildcard.
@ -66,6 +68,40 @@ Temporary permissions are checked each time a user/group is loaded, and when the
The only way around this is to decrease the sync interval.
### Shorthand Permissions
LuckPerms has it's own system (although it's quite similar to PermissionsEx :P) that allows you to set permissions in a shorthand format.
Using the LuckPerms permission nodes as an example, say for instance, you wanted to let a user set and unset permissions for both groups and users.
Without shorthand, you would have to apply 4 nodes.
```
luckperms.user.setpermission
luckperms.user.unsetpermission
luckperms.group.setpermission
luckperms.group.unsetpermission
```
However, with shorthand, you can just apply the following node:
`luckperms.(user|group).(setpermission|unsetpermission)`
You use brackets to define part of a node as a shorthand group, and then use the vertical bar `|` to separate entries.
There are some limitations, firstly, you cannot use shorthand in the first part of the node. (The "luckperms" part in the example above)
Additionally, you cannot combine shorthand and normal text in the same part of the node.
For example, `luckperms.(user|group).(set|unset)permission` would not work.
### Regex
LuckPerms has support for regex when defining permission nodes and server/world names.
Whenever regex is used, it MUST be prefixed with "R=", so LuckPerms knows to treat it as regex, and not as a normal string.
For example, if you wanted to give all members of the default group, the `essentials.fly` permission on all of your hub servers, where the hub server names are hub1, hub2, hub3, etc.
You would use the command `/perms group default set essentials.fly true R=hub\d+`.
You can also use regex in permission nodes.
Once again using LuckPerms permissions as an example, if you wanted a user to be able to create both groups and tracks, you would normally just add the two permission nodes. However with regex, you can just add one. `luckperms\.create.*` Remember to escape any characters, specifically dots, as the entire node will be parsed.
## API
LuckPerms has an extensive API, allowing for easy integration with other projects. To use the Api, you need to obtain an instance of the `LuckPermsApi` interface. This can be done in a number of ways.

View File

@ -64,6 +64,16 @@ public interface LPConfiguration {
*/
boolean getApplyWildcards();
/**
* @return if LuckPerms is resolving and applying regex permissions
*/
boolean getApplyRegex();
/**
* @return if LuckPerms is expanding shorthand permissions
*/
boolean getApplyShorthand();
/**
* @return the database values set in the configuration
*/

View File

@ -27,6 +27,16 @@ online-mode: true
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the node, and resolve &
# apply all registered permissions matching the regex. This will only work for plugins that define all of their
# permissions to the server.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, flatfile
# Fill out connection info below if you're using MySQL

View File

@ -27,6 +27,16 @@ online-mode: true
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards: true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the node, and resolve &
# apply all registered permissions matching the regex. This will only work for plugins that define all of their
# permissions to the server.
apply-regex: true
# If the plugin should complete and apply shorthand permissions.
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand: true
# Which storage method the plugin should use.
# Currently supported: mysql & flatfile
# Fill out connection info below if you're using MySQL

View File

@ -24,6 +24,7 @@ package me.lucko.luckperms.api.implementation.internal;
import lombok.AllArgsConstructor;
import lombok.NonNull;
import me.lucko.luckperms.LuckPermsPlugin;
import me.lucko.luckperms.api.Datastore;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Track;
@ -40,11 +41,13 @@ import static me.lucko.luckperms.api.implementation.internal.Utils.*;
@SuppressWarnings({"unused", "WeakerAccess"})
public class DatastoreLink implements Datastore {
private final LuckPermsPlugin plugin;
private final me.lucko.luckperms.data.Datastore master;
private final Async async;
private final Sync sync;
public DatastoreLink(@NonNull me.lucko.luckperms.data.Datastore master) {
public DatastoreLink(@NonNull LuckPermsPlugin plugin, @NonNull me.lucko.luckperms.data.Datastore master) {
this.plugin = plugin;
this.master = master;
this.async = new Async(master);
this.sync = new Sync(master);
@ -122,6 +125,9 @@ public class DatastoreLink implements Datastore {
@Override
public void deleteGroup(@NonNull Group group, Callback<Boolean> callback) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
master.deleteGroup(((GroupLink) group).getMaster(), checkCallback(callback));
}
@ -207,6 +213,9 @@ public class DatastoreLink implements Datastore {
@Override
public boolean deleteGroup(@NonNull Group group) {
checkGroup(group);
if (group.getName().equalsIgnoreCase(plugin.getConfiguration().getDefaultGroupName())) {
throw new IllegalArgumentException("Cannot delete the default group.");
}
return master.deleteGroup(((GroupLink) group).getMaster());
}

View File

@ -27,7 +27,7 @@ import me.lucko.luckperms.api.LPConfiguration;
import me.lucko.luckperms.api.data.MySQLConfiguration;
/**
* Provides a link between {@link me.lucko.luckperms.api.LPConfiguration} and {@link me.lucko.luckperms.utils.LPConfiguration}
* Provides a link between {@link LPConfiguration} and {@link me.lucko.luckperms.utils.LPConfiguration}
*/
@AllArgsConstructor
public class LPConfigurationLink implements LPConfiguration {
@ -68,6 +68,16 @@ public class LPConfigurationLink implements LPConfiguration {
return master.getApplyWildcards();
}
@Override
public boolean getApplyRegex() {
return master.getApplyRegex();
}
@Override
public boolean getApplyShorthand() {
return master.getApplyShorthand();
}
@Override
public MySQLConfiguration getDatabaseValues() {
return master.getDatabaseValues();

View File

@ -26,8 +26,7 @@ import lombok.experimental.UtilityClass;
import me.lucko.luckperms.api.Group;
import me.lucko.luckperms.api.Track;
import me.lucko.luckperms.api.User;
import me.lucko.luckperms.utils.DateUtil;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
@UtilityClass
class Utils {
@ -51,7 +50,7 @@ class Utils {
}
static String checkUsername(String s) {
if (s.length() > 16 || Patterns.NON_USERNAME.matcher(s).find()) {
if (!ArgumentChecker.checkUsername(s)) {
throw new IllegalArgumentException("Invalid username entry '" + s + "'. Usernames must be less than 16 chars" +
" and only contain 'a-z A-Z 1-9 _'.");
}
@ -59,7 +58,7 @@ class Utils {
}
static String checkName(String s) {
if (s.length() > 36 || Patterns.NON_ALPHA_NUMERIC.matcher(s).find()) {
if (!ArgumentChecker.checkName(s)) {
throw new IllegalArgumentException("Invalid name entry '" + s + "'. Names must be less than 37 chars" +
" and only contain 'a-z A-Z 1-9'.");
}
@ -67,21 +66,21 @@ class Utils {
}
static String checkServer(String s) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(s).find()) {
if (!ArgumentChecker.checkServer(s)) {
throw new IllegalArgumentException("Invalid server entry '" + s + "'. Server names can only contain alphanumeric characters.");
}
return s;
}
static String checkNode(String s) {
if (s.contains("/") || s.contains("$")) {
if (!ArgumentChecker.checkNode(s)) {
throw new IllegalArgumentException("Invalid node entry '" + s + "'. Nodes cannot contain '/' or '$' characters.");
}
return s;
}
static long checkTime(long l) {
if (DateUtil.shouldExpire(l)) {
if (!ArgumentChecker.checkTime(l)) {
throw new IllegalArgumentException("Unix time '" + l + "' is invalid, as it has already passed.");
}
return l;

View File

@ -28,7 +28,7 @@ import me.lucko.luckperms.api.UuidCache;
import java.util.UUID;
/**
* Provides a link between {@link me.lucko.luckperms.api.UuidCache} and {@link me.lucko.luckperms.utils.UuidCache}
* Provides a link between {@link UuidCache} and {@link me.lucko.luckperms.utils.UuidCache}
*/
@AllArgsConstructor
public class UuidCacheLink implements UuidCache {

View File

@ -27,7 +27,7 @@ import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,13 +44,7 @@ public class CreateGroup extends SingleMainCommand {
}
String groupName = args.get(0).toLowerCase();
if (groupName.length() > 36) {
Message.GROUP_NAME_TOO_LONG.send(sender, groupName);
return;
}
if (Patterns.NON_ALPHA_NUMERIC.matcher(groupName).find()) {
if (!ArgumentChecker.checkName(groupName)) {
Message.GROUP_INVALID_ENTRY.send(sender);
return;
}

View File

@ -28,7 +28,7 @@ import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.Collections;
@ -54,7 +54,7 @@ public class DeleteGroup extends SingleMainCommand {
return;
}
if (Patterns.NON_ALPHA_NUMERIC.matcher(groupName).find()) {
if (!ArgumentChecker.checkName(groupName)) {
Message.GROUP_INVALID_ENTRY.send(sender);
return;
}

View File

@ -28,7 +28,7 @@ import me.lucko.luckperms.commands.MainCommand;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
@ -40,7 +40,7 @@ public class GroupMainCommand extends MainCommand<Group> {
@Override
protected void getTarget(String target, LuckPermsPlugin plugin, Sender sender, Callback<Group> onSuccess) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(target).find()) {
if (!ArgumentChecker.checkName(target)) {
Message.GROUP_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,7 +44,7 @@ public class GroupHasPerm extends SubCommand<Group> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
if (args.size() >= 2) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(args.get(1)).find()) {
if (!ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,7 +44,7 @@ public class GroupInheritsPerm extends SubCommand<Group> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
if (args.size() >= 2) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(args.get(1)).find()) {
if (!ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -45,7 +45,7 @@ public class GroupSetInherit extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -57,7 +57,7 @@ public class GroupSetInherit extends SubCommand<Group> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -45,7 +46,7 @@ public class GroupSetPermission extends SubCommand<Group> {
String node = args.get(0);
String bool = args.get(1).toLowerCase();
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -65,7 +66,7 @@ public class GroupSetPermission extends SubCommand<Group> {
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,8 +30,8 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -46,7 +46,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -71,7 +71,7 @@ public class GroupSetTempInherit extends SubCommand<Group> {
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import me.lucko.luckperms.utils.Patterns;
@ -47,7 +48,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
String node = args.get(0);
String bool = args.get(1).toLowerCase();
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -80,7 +81,7 @@ public class GroupSetTempPermission extends SubCommand<Group> {
try {
if (args.size() >= 4) {
final String server = args.get(3).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -44,7 +45,7 @@ public class GroupUnSetPermission extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0);
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -57,7 +58,7 @@ public class GroupUnSetPermission extends SubCommand<Group> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -45,7 +45,7 @@ public class GroupUnsetInherit extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -53,7 +53,7 @@ public class GroupUnsetInherit extends SubCommand<Group> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -45,7 +45,7 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -53,7 +53,7 @@ public class GroupUnsetTempInherit extends SubCommand<Group> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -45,7 +46,7 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
public void execute(LuckPermsPlugin plugin, Sender sender, Group group, List<String> args, String label) {
String node = args.get(0);
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -58,7 +59,7 @@ public class GroupUnsetTempPermission extends SubCommand<Group> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -27,7 +27,7 @@ import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,13 +44,7 @@ public class CreateTrack extends SingleMainCommand {
}
String trackName = args.get(0).toLowerCase();
if (trackName.length() > 36) {
Message.TRACK_NAME_TOO_LONG.send(sender, trackName);
return;
}
if (Patterns.NON_ALPHA_NUMERIC.matcher(trackName).find()) {
if (!ArgumentChecker.checkName(trackName)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}

View File

@ -28,7 +28,7 @@ import me.lucko.luckperms.commands.SingleMainCommand;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.Collections;
@ -48,8 +48,7 @@ public class DeleteTrack extends SingleMainCommand {
}
String trackName = args.get(0).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(trackName).find()) {
if (!ArgumentChecker.checkName(trackName)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}

View File

@ -28,6 +28,7 @@ import me.lucko.luckperms.commands.MainCommand;
import me.lucko.luckperms.commands.Sender;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.ArrayList;
import java.util.List;
@ -39,6 +40,10 @@ public class TrackMainCommand extends MainCommand<Track> {
@Override
protected void getTarget(String target, LuckPermsPlugin plugin, Sender sender, Callback<Track> onSuccess) {
if (!ArgumentChecker.checkName(target)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}
plugin.getDatastore().loadTrack(target, success -> {
if (!success) {
Message.TRACK_NOT_FOUND.send(sender);

View File

@ -31,7 +31,7 @@ import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -45,7 +45,7 @@ public class UserAddGroup extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -63,7 +63,7 @@ public class UserAddGroup extends SubCommand<User> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -31,8 +31,8 @@ import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -47,7 +47,7 @@ public class UserAddTempGroup extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -78,7 +78,7 @@ public class UserAddTempGroup extends SubCommand<User> {
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -46,6 +47,10 @@ public class UserDemote extends SubCommand<User> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
final String trackName = args.get(0).toLowerCase();
if (!ArgumentChecker.checkName(trackName)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}
plugin.getDatastore().loadTrack(trackName, success -> {
if (!success) {

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,7 +44,7 @@ public class UserHasPerm extends SubCommand<User> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
if (args.size() >= 2) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(args.get(1)).find()) {
if (!ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.commands.Util;
import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,7 +44,7 @@ public class UserInheritsPerm extends SubCommand<User> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
if (args.size() >= 2) {
if (Patterns.NON_ALPHA_NUMERIC.matcher(args.get(1)).find()) {
if (!ArgumentChecker.checkServer(args.get(1))) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -34,6 +34,7 @@ import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.groups.Group;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -46,6 +47,10 @@ public class UserPromote extends SubCommand<User> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
final String trackName = args.get(0).toLowerCase();
if (!ArgumentChecker.checkName(trackName)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}
plugin.getDatastore().loadTrack(trackName, success -> {
if (!success) {

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -44,7 +44,7 @@ public class UserRemoveGroup extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -58,7 +58,7 @@ public class UserRemoveGroup extends SubCommand<User> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,7 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.Patterns;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -45,7 +45,7 @@ public class UserRemoveTempGroup extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String groupName = args.get(0).toLowerCase();
if (groupName.contains("/") || groupName.contains("$")) {
if (!ArgumentChecker.checkNode(groupName)) {
sendUsage(sender, label);
return;
}
@ -53,7 +53,7 @@ public class UserRemoveTempGroup extends SubCommand<User> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -46,7 +47,7 @@ public class UserSetPermission extends SubCommand<User> {
String node = args.get(0);
String bool = args.get(1).toLowerCase();
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -66,7 +67,7 @@ public class UserSetPermission extends SubCommand<User> {
try {
if (args.size() >= 3) {
final String server = args.get(2).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectAlreadyHasException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.DateUtil;
import me.lucko.luckperms.utils.Patterns;
@ -47,7 +48,7 @@ public class UserSetTempPermission extends SubCommand<User> {
String node = args.get(0);
String bool = args.get(1).toLowerCase();
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -80,7 +81,7 @@ public class UserSetTempPermission extends SubCommand<User> {
try {
if (args.size() >= 4) {
final String server = args.get(3).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -31,6 +31,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.tracks.Track;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import java.util.List;
@ -43,6 +44,10 @@ public class UserShowPos extends SubCommand<User> {
@Override
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
final String trackName = args.get(0).toLowerCase();
if (!ArgumentChecker.checkName(trackName)) {
Message.TRACK_INVALID_ENTRY.send(sender);
return;
}
plugin.getDatastore().loadTrack(trackName, success -> {
if (!success) {

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -44,7 +45,7 @@ public class UserUnSetPermission extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String node = args.get(0);
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -57,7 +58,7 @@ public class UserUnSetPermission extends SubCommand<User> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -30,6 +30,7 @@ import me.lucko.luckperms.constants.Message;
import me.lucko.luckperms.constants.Permission;
import me.lucko.luckperms.exceptions.ObjectLacksException;
import me.lucko.luckperms.users.User;
import me.lucko.luckperms.utils.ArgumentChecker;
import me.lucko.luckperms.utils.Patterns;
import java.util.List;
@ -45,7 +46,7 @@ public class UserUnsetTempPermission extends SubCommand<User> {
public void execute(LuckPermsPlugin plugin, Sender sender, User user, List<String> args, String label) {
String node = args.get(0);
if (node.contains("/") || node.contains("$")) {
if (!ArgumentChecker.checkNode(node)) {
sendUsage(sender, label);
return;
}
@ -58,7 +59,7 @@ public class UserUnsetTempPermission extends SubCommand<User> {
try {
if (args.size() >= 2) {
final String server = args.get(1).toLowerCase();
if (Patterns.NON_ALPHA_NUMERIC.matcher(server).find()) {
if (!ArgumentChecker.checkServer(server)) {
Message.SERVER_INVALID_ENTRY.send(sender);
return;
}

View File

@ -105,13 +105,11 @@ public enum Message {
GROUP_ALREADY_EXISTS("That group already exists!", true),
GROUP_DOES_NOT_EXIST("That group does not exist!", true),
GROUP_NAME_TOO_LONG("Group name '%s' exceeds the maximum length of 36 characters.", true),
GROUP_LOAD_ERROR("An unexpected error occurred. Group not loaded.", true),
GROUPS_LOAD_ERROR("An unexpected error occurred. Unable to load all groups.", true),
TRACK_ALREADY_EXISTS("That track already exists!", true),
TRACK_DOES_NOT_EXIST("That track does not exist!", true),
TRACK_NAME_TOO_LONG("Track name '%s' exceeds the maximum length of 36 characters.", true),
TRACK_LOAD_ERROR("An unexpected error occurred. Track not loaded.", true),
TRACKS_LOAD_ERROR("An unexpected error occurred. Unable to load all tracks.", true),
TRACK_EMPTY("The track cannot be used as it is empty or contains only one group.", true),

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 2016 Lucko (Luck) <luck@lucko.me>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package me.lucko.luckperms.utils;
import lombok.experimental.UtilityClass;
@UtilityClass
public class ArgumentChecker {
public static boolean checkUsername(String s) {
return !(s.length() > 16 || Patterns.NON_USERNAME.matcher(s).find());
}
public static boolean checkName(String s) {
return !(s.length() > 36 || Patterns.NON_ALPHA_NUMERIC.matcher(s).find());
}
public static boolean checkServer(String s) {
return !s.toLowerCase().startsWith("r=") && !Patterns.NON_ALPHA_NUMERIC.matcher(s).find();
}
public static boolean checkNode(String s) {
return !(s.contains("/") || s.contains("$"));
}
public static boolean checkTime(long l) {
return !DateUtil.shouldExpire(l);
}
}

View File

@ -92,6 +92,14 @@ public abstract class LPConfiguration<T extends LuckPermsPlugin> {
return getBoolean("apply-wildcards", true);
}
public boolean getApplyRegex() {
return getBoolean("apply-regex", true);
}
public boolean getApplyShorthand() {
return getBoolean("apply-shorthand", true);
}
public MySQLConfiguration getDatabaseValues() {
return new MySQLConfiguration(
getString("sql.address", null),

View File

@ -24,17 +24,39 @@ package me.lucko.luckperms.utils;
import lombok.experimental.UtilityClass;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
@UtilityClass
public class Patterns {
private static final Map<String, Pattern> CACHE = new ConcurrentHashMap<>();
public static final Pattern SPACE = Pattern.compile(" ");
public static final Pattern SERVER_DELIMITER = Pattern.compile("\\/");
public static final Pattern WORLD_DELIMITER = Pattern.compile("\\-");
public static final Pattern TEMP_DELIMITER = Pattern.compile("\\$");
public static final Pattern DOT = Pattern.compile("\\.");
public static final Pattern VERTICAL_BAR = Pattern.compile("\\|");
public static final Pattern GROUP_MATCH = Pattern.compile("group\\..*");
public static final Pattern NON_ALPHA_NUMERIC = Pattern.compile("[^A-Za-z0-9]");
public static final Pattern NON_USERNAME = Pattern.compile("[^A-Za-z0-9_]");
public static final Pattern SHORTHAND_NODE = Pattern.compile("\\.\\([^.]+\\)");
public static Pattern compile(String regex) throws PatternSyntaxException {
if (!CACHE.containsKey(regex)) {
Pattern p;
try {
p = Pattern.compile(regex);
} catch (PatternSyntaxException e) {
return null;
}
CACHE.put(regex, p);
}
return CACHE.get(regex);
}
}

View File

@ -32,6 +32,7 @@ import me.lucko.luckperms.groups.Group;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
@ -537,12 +538,12 @@ public abstract class PermissionHolder {
String[] serverParts = Patterns.WORLD_DELIMITER.split(parts[0], 2);
// 0=server 1=world
if ((!serverParts[0].equalsIgnoreCase("global") || !includeGlobal) && (!serverParts[0].equalsIgnoreCase(server))) {
if ((!serverParts[0].equalsIgnoreCase("global") || !includeGlobal) && (!matches(server, serverParts[0]))) {
// GLOBAL AND UNWANTED OR SERVER SPECIFIC BUT DOES NOT APPLY :(((
continue;
}
if (world != null && !serverParts[1].equalsIgnoreCase(world)) {
if (world != null && !matches(world, serverParts[1])) {
// WORLD SPECIFIC BUT DOES NOT APPLY
continue;
}
@ -563,7 +564,7 @@ public abstract class PermissionHolder {
break serverSpecific;
}
if (!parts[0].equalsIgnoreCase(server)) {
if (!matches(server, parts[0])) {
// SERVER SPECIFIC BUT DOES NOT APPLY
continue;
}
@ -631,6 +632,8 @@ public abstract class PermissionHolder {
}
}
applyShorthandIfEnabled(perms);
// Apply next priorities: serverSpecificGroups and then serverWorldSpecificGroups
for (Map<String, Boolean> m : Arrays.asList(serverSpecificGroups, serverWorldSpecificGroups)) {
for (Map.Entry<String, Boolean> groupNode : m.entrySet()) {
@ -653,10 +656,12 @@ public abstract class PermissionHolder {
}
}
}
applyShorthandIfEnabled(perms);
}
// Apply next priority: userNodes
perms.putAll(userNodes);
applyShorthandIfEnabled(perms);
// Apply final priorities: serverSpecificNodes and then serverWorldSpecificNodes
for (Map<String, Boolean> m : Arrays.asList(serverSpecificNodes, serverWorldSpecificNodes)) {
@ -664,22 +669,60 @@ public abstract class PermissionHolder {
final String rawNode = Patterns.SERVER_DELIMITER.split(node.getKey())[1];
perms.put(rawNode, node.getValue());
}
applyShorthandIfEnabled(perms);
}
if (plugin.getConfiguration().getApplyRegex()) {
if (possibleNodes != null && !possibleNodes.isEmpty()) {
perms = applyRegex(perms, possibleNodes);
} else {
perms = applyRegex(perms, plugin.getPossiblePermissions());
}
}
applyShorthandIfEnabled(perms);
if (plugin.getConfiguration().getApplyWildcards()) {
if (possibleNodes != null && !possibleNodes.isEmpty()) {
return applyWildcards(perms, possibleNodes);
perms = applyWildcards(perms, possibleNodes);
} else {
perms = applyWildcards(perms, plugin.getPossiblePermissions());
}
return applyWildcards(perms, plugin.getPossiblePermissions());
}
return perms;
}
private Map<String, Boolean> applyWildcards(Map<String, Boolean> input, List<String> possibleNodes) {
// Add all group nodes, so wildcard group.* and '*' can apply.
plugin.getGroupManager().getGroups().keySet().forEach(s -> possibleNodes.add("group." + s));
private boolean matches(String entry, String possibleRegex) {
if (!possibleRegex.toLowerCase().startsWith("r=") || !plugin.getConfiguration().getApplyRegex()) {
return entry.equalsIgnoreCase(possibleRegex);
}
Pattern p = Patterns.compile(possibleRegex.substring(2));
if (p == null) {
return false;
}
return p.matcher(entry).matches();
}
private Map<String, Boolean> applyRegex(Map<String, Boolean> input, List<String> possibleNodes) {
for (Map.Entry<String, Boolean> e : input.entrySet()) {
if (!e.getKey().startsWith("r=") && !e.getKey().startsWith("R=")) {
continue;
}
final Pattern node = Patterns.compile(e.getKey().substring(2));
if (node == null) continue;
possibleNodes.stream()
.filter(n -> node.matcher(n).matches())
.filter(n -> !input.containsKey(n))
.forEach(n -> input.put(n, e.getValue()));
}
return input;
}
private static Map<String, Boolean> applyWildcards(Map<String, Boolean> input, List<String> possibleNodes) {
SortedMap<Integer, Map<String, Boolean>> wildcards = new TreeMap<>(Collections.reverseOrder());
for (Map.Entry<String, Boolean> e : input.entrySet()) {
if (e.getKey().equals("*") || e.getKey().equals("'*'")) {
@ -721,6 +764,57 @@ public abstract class PermissionHolder {
return input;
}
private void applyShorthandIfEnabled(Map<String, Boolean> map) {
if (plugin.getConfiguration().getApplyShorthand()) {
applyShorthand(map);
}
}
private static Map<String, Boolean> applyShorthand(Map<String, Boolean> input) {
for (Map.Entry<String, Boolean> e : input.entrySet()) {
if (!Patterns.SHORTHAND_NODE.matcher(e.getKey()).find()) {
continue;
}
if (!e.getKey().contains(".")) {
continue;
}
String[] parts = Patterns.DOT.split(e.getKey());
List<Set<String>> nodeParts = new ArrayList<>();
for (String s : parts) {
if ((!s.startsWith("(") || !s.endsWith(")")) || !s.contains("|")) {
nodeParts.add(Collections.singleton(s));
continue;
}
final String bits = s.substring(1, s.length() - 1);
nodeParts.add(new HashSet<>(Arrays.asList(Patterns.VERTICAL_BAR.split(bits))));
}
Set<String> nodes = new HashSet<>();
for (Set<String> set : nodeParts) {
final Set<String> newNodes = new HashSet<>();
if (nodes.isEmpty()) {
newNodes.addAll(set);
} else {
nodes.forEach(str -> newNodes.addAll(set.stream()
.map(add -> str + "." + add)
.collect(Collectors.toList()))
);
}
nodes = newNodes;
}
nodes.stream()
.filter(n -> !input.containsKey(n)) // Don't override existing nodes
.forEach(n -> input.put(n, e.getValue()));
}
return input;
}
private static String stripTime(String s) {
if (s.contains("$")) {
return Patterns.TEMP_DELIMITER.split(s)[0];

View File

@ -27,6 +27,16 @@ online-mode=true
# the wildcard. This will only work for plugins that define all of their permissions to the server.
apply-wildcards=true
# If the plugin should parse regex permissions.
# If set to true, LuckPerms will detect regex permissions, marked with "r=" at the start of the node, and resolve &
# apply all registered permissions matching the regex. This will only work for plugins that define all of their
# permissions to the server.
apply-regex=true
# If the plugin should complete and apply shorthand permissions.
# If set to true, LuckPerms will detect and expand shorthand node patterns.
apply-shorthand=true
# Which storage method the plugin should use.
# Currently supported: mysql, sqlite, flatfile
# Fill out connection info below if you're using MySQL