Compare commits

...
5 Commits
71 changed files with 900 additions and 229 deletions

No files matched your search

+65 -11
View File
@@ -8,6 +8,7 @@ A permissions implementation for Bukkit/Spigot, BungeeCord and Sponge.
## Features
* **Group inheritance** - users can be members of multiple groups, groups can inherit other groups
* **Temporary permissions** - users/groups can be given permissions that expire after a given time
* **Wildcard permissions** - users/groups can be given wildcard permissions (e.g. "minecraft.command.*"), even when plugins haven't implemented their own wildcards.
* **Temporary groups** - users/groups can be added to/inherit other groups temporarily
* **Multi-server support** - data is synced across all servers/platforms
* **Full offline-mode/mixed-mode support** - player permissions are synced properly over offline-mode or mixed online/offline-mode networks.
@@ -18,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.
@@ -34,38 +37,89 @@ You can define the settings for per-server permissions, the storage method and c
## Info
### Permission Calculation
Permissions are calculated based on a priority system as follows.
#### Permissions are calculated based on a priority system as follows.
* Temporary permissions will override non-temporary 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.
* **More specific wildcards override less specific ones**
Example: if a user has "luckperms.\*" set to true, but "luckperms.user.\*" set to false, all of the user permissions will be set to false, despite the more generic wildcard for "luckperms.*".
* **Temporary permissions will override non-temporary permissions.**
Example: if a user has a false permission set for "test.node", and a temporary true permission set for "test.node", the temporary permission will override the permanent one, and the user will be granted the true node.
* World specific permissions will override generic permissions.
* **World specific permissions will override generic permissions.**
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission in the "world_nether" world, the world specific permission will override the globally defined one, and the user will be granted the negated node (provided they're in that world, of course.).
* Server specific permissions will override generic/global permissions.
* **Server specific permissions will override generic/global permissions.**
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission on the "factions" server, the server specific permission will override the globally defined one, and the user will be granted the negated node.
Example: if a user has a global "fly.use" permission, and then has a negated "fly.use" permission on the "factions" server, the server specific permission will override the globally defined one, and the user will be granted the negated node (provided they're on that server).
* Inherited permissions will be overridden by an objects own permissions.
* **Inherited permissions will be overridden by an objects own permissions.**
Example: A user is a member of the default group, which grants "some.thing.perm", but the users own permissions has "some.thing.perm" set to false. The inherited permission will be overridden by the users own permissions, and the user will be granted the negative node (provided they're on that server).
Example: A user is a member of the default group, which grants "some.thing.perm", but the users own permissions has "some.thing.perm" set to false. The inherited permission will be overridden by the users own permissions, and the user will be granted the negative node.
### Temporary Permissions
Temporary permissions are checked each time a user/group is loaded, and when the sync task runs. This means if you set a temporary permission to expire after 30 seconds, it won't actually be removed until the sync task runs.
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.
```java
// On all platforms
// On all platforms (throws IllegalStateException if the API is not loaded)
final LuckPermsApi api = LuckPerms.getApi();
// Or with Optional
Optional<LuckPermsApi> provider = LuckPerms.getApiSafe();
if (provider.isPresent()) {
final LuckPermsApi api = provider.get();
}
// On Bukkit/Spigot
final LuckPermsApi api = Bukkit.getServicesManager().getRegistration(LuckPermsApi.class).getProvider();
ServicesManager manager = Bukkit.getServicesManager();
if (manager.isProvidedFor(LuckPermsApi.class)) {
final LuckPermsApi api = manager.getRegistration(LuckPermsApi.class).getProvider();
}
// On Sponge
Optional<LuckPermsApi> provider = Sponge.getServiceManager().provide(LuckPermsApi.class);
@@ -93,7 +147,7 @@ You can add LuckPerms as a Maven dependency by adding the following to your proj
<dependency>
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms-api</artifactId>
<version>2.0</version>
<version>2.1</version>
</dependency>
</dependencies>
````
@@ -101,7 +155,7 @@ You can add LuckPerms as a Maven dependency by adding the following to your proj
## Versioning
As of version 2.0, LuckPerms roughly follows the standards set out in Semantic Versioning.
The only difference is that patch number is not included anywhere within the pom, and is calculated each build, based upon how may commits have been made since the last tag. (A new tag is made every minor version)
The only difference is that the patch number is not included anywhere within the pom, and is calculated each build, based upon how may commits have been made since the last tag. (A new tag is made every minor version)
This means that API versions do not have a patch number (as no API changes are made in patches). API versions will be x.y, and each individual build of LuckPerms will follow x.y.z.
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -28,7 +28,8 @@ import java.util.UUID;
/**
* Wrapper interface for the internal Datastore instance
* The implementations of this interface limit access to the datastore and add parameter checks to further prevent
*
* <p> The implementations of this interface limit access to the datastore and add parameter checks to further prevent
* errors and ensure all API interactions to not damage the state of the plugin.
*/
@SuppressWarnings("unused")
@@ -29,7 +29,8 @@ import java.util.List;
/**
* Wrapper interface for internal Group instances
* The implementations of this interface limit access to the Group and add parameter checks to further prevent
*
* <p> The implementations of this interface limit access to the Group and add parameter checks to further prevent
* errors and ensure all API interactions to not damage the state of the group.
*/
@SuppressWarnings("unused")
@@ -59,6 +59,21 @@ public interface LPConfiguration {
*/
boolean getOnlineMode();
/**
* @return if LuckPerms is applying wildcard permissions
*/
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
*/
@@ -24,7 +24,8 @@ package me.lucko.luckperms.api;
/**
* A wrapper class for platform logger instances.
* Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the commons
*
* <p> Bukkit/Bungee both use java.util.logging, and Sponge uses org.slf4j. This class wraps those classes so the commons
* module can access a logger.
*/
public interface Logger {
@@ -30,7 +30,8 @@ import java.util.Map;
/**
* Wrapper interface for internal PermissionHolder (user/group) instances
* The implementations of this interface limit access to the object and add parameter checks to further prevent
*
* <p> The implementations of this interface limit access to the object and add parameter checks to further prevent
* errors and ensure all API interactions to not damage the state of the object.
*/
@SuppressWarnings("unused")
@@ -262,6 +263,16 @@ public interface PermissionHolder {
*/
void unsetPermission(String node, String server, String world, boolean temporary) throws ObjectLacksException;
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
@@ -273,8 +284,17 @@ public interface PermissionHolder {
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for (can be null)
* @param excludedGroups Groups that shouldn't be inherited, can be null (to prevent circular inheritance issues)
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes);
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @return a {@link Map} of the permissions
*/
Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups);
@@ -29,7 +29,8 @@ import java.util.List;
/**
* Wrapper interface for internal Track instances
* The implementations of this interface limit access to the Track and add parameter checks to further prevent
*
* <p> The implementations of this interface limit access to the Track and add parameter checks to further prevent
* errors and ensure all API interactions to not damage the state of the track.
*/
@SuppressWarnings("unused")
@@ -30,7 +30,8 @@ import java.util.UUID;
/**
* Wrapper interface for internal User instances
* The implementations of this interface limit access to the User and add parameter checks to further prevent
*
* <p> The implementations of this interface limit access to the User and add parameter checks to further prevent
* errors and ensure all API interactions to not damage the state of the user.
*/
@SuppressWarnings("unused")
@@ -30,10 +30,10 @@ import java.util.UUID;
* they first join the server, but this UUID will then not be consistent across the network. LuckPerms will instead check
* the datastore cache, to get a UUID for a user that is consistent across an entire network.
*
* If you want to get a user object from the datastore using the api on a server in offline mode, you will need to use this cache,
* <p> If you want to get a user object from the datastore using the api on a server in offline mode, you will need to use this cache,
* OR use Datastore#getUUID, for users that are not online.
*
* WARNING: THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS.
* <p> WARNING: THIS IS ONLY EFFECTIVE FOR ONLINE PLAYERS. USE THE DATASTORE METHODS FOR OFFLINE PLAYERS.
*/
public interface UuidCache {
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -40,7 +40,6 @@ import me.lucko.luckperms.users.UserManager;
import me.lucko.luckperms.utils.LPConfiguration;
import me.lucko.luckperms.utils.LogUtil;
import me.lucko.luckperms.utils.UuidCache;
import org.bukkit.Bukkit;
import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
@@ -48,6 +47,7 @@ import org.bukkit.plugin.ServicePriority;
import org.bukkit.plugin.java.JavaPlugin;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
@@ -71,7 +71,7 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
configuration = new BukkitConfig(this);
// register events
PluginManager pm = Bukkit.getPluginManager();
PluginManager pm = getServer().getPluginManager();
pm.registerEvents(new BukkitListener(this), this);
// register commands
@@ -155,12 +155,12 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
@Override
public void doAsync(Runnable r) {
Bukkit.getScheduler().runTaskAsynchronously(this, r);
getServer().getScheduler().runTaskAsynchronously(this, r);
}
@Override
public void doSync(Runnable r) {
Bukkit.getScheduler().runTask(this, r);
getServer().getScheduler().runTask(this, r);
}
@Override
@@ -183,6 +183,18 @@ public class LPBukkitPlugin extends JavaPlugin implements LuckPermsPlugin {
return getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
final List<String> perms = new ArrayList<>();
getServer().getPluginManager().getPermissions().forEach(p -> {
perms.add(p.getName());
p.getChildren().keySet().forEach(perms::add);
});
return perms;
}
@Override
public void runUpdateTask() {
getServer().getScheduler().runTaskAsynchronously(this, new UpdateTask(this));
@@ -28,10 +28,24 @@ import me.lucko.luckperms.LPBukkitPlugin;
import org.bukkit.entity.Player;
import org.bukkit.permissions.PermissionAttachment;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.UUID;
public class BukkitUser extends User {
private static Field permissionsField = null;
private static Field getPermissionsField() {
if (permissionsField == null) {
try {
permissionsField = PermissionAttachment.class.getDeclaredField("permissions");
permissionsField.setAccessible(true);
} catch (SecurityException | NoSuchFieldException e) {
e.printStackTrace();
}
}
return permissionsField;
}
private final LPBukkitPlugin plugin;
@@ -49,6 +63,7 @@ public class BukkitUser extends User {
this.plugin = plugin;
}
@SuppressWarnings("unchecked")
@Override
public void refreshPermissions() {
plugin.doSync(() -> {
@@ -60,12 +75,35 @@ public class BukkitUser extends User {
setAttachment(player.addAttachment(plugin));
}
// Clear existing permissions
attachment.getPermissions().keySet().forEach(p -> attachment.setPermission(p, false));
// Calculate the permissions that should be applied
Map<String, Boolean> toApply = getLocalPermissions(getPlugin().getConfiguration().getServer(), player.getWorld().getName(), null);
// Re-add all defined permissions for the user
Map<String, Boolean> local = getLocalPermissions(getPlugin().getConfiguration().getServer(), player.getWorld().getName(), null);
local.entrySet().forEach(e -> attachment.setPermission(e.getKey(), e.getValue()));
try {
Map<String, Boolean> existing = (Map<String, Boolean>) getPermissionsField().get(attachment);
boolean different = false;
if (toApply.size() != existing.size()) {
different = true;
} else {
for (Map.Entry<String, Boolean> e : existing.entrySet()) {
if (toApply.containsKey(e.getKey()) && toApply.get(e.getKey()) == e.getValue()) {
continue;
}
different = true;
break;
}
}
if (!different) return;
// Faster than recalculating permissions after each PermissionAttachment#setPermission
existing.clear();
existing.putAll(toApply);
attachment.getPermissible().recalculatePermissions();
} catch (Exception e) {
e.printStackTrace();
}
});
}
}
+15
View File
@@ -22,6 +22,21 @@ include-global: true
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode: true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# 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
+99 -1
View File
@@ -7,4 +7,102 @@ description: A permissions plugin
commands:
luckperms:
description: Manage permissions
aliases: [perms, permissions, lp, p, perm]
aliases: [perms, permissions, lp, p, perm]
permissions:
luckperms.*:
description: Gives access to all LuckPerms commands
children:
luckperms.sync: true
luckperms.info: true
luckperms.debug: true
luckperms.creategroup: true
luckperms.deletegroup: true
luckperms.listgroups: true
luckperms.createtrack: true
luckperms.deletetrack: true
luckperms.listtracks: true
luckperms.user.info: true
luckperms.user.getuuid: true
luckperms.user.listnodes: true
luckperms.user.haspermission: true
luckperms.user.inheritspermission: true
luckperms.user.setpermission: true
luckperms.user.unsetpermission: true
luckperms.user.addgroup: true
luckperms.user.removegroup: true
luckperms.user.settemppermission: true
luckperms.user.unsettemppermission: true
luckperms.user.addtempgroup: true
luckperms.user.removetempgroup: true
luckperms.user.setprimarygroup: true
luckperms.user.showtracks: true
luckperms.user.promote: true
luckperms.user.demote: true
luckperms.user.showpos: true
luckperms.user.clear: true
luckperms.group.info: true
luckperms.group.listnodes: true
luckperms.group.haspermission: true
luckperms.group.inheritspermission: true
luckperms.group.setpermission: true
luckperms.group.unsetpermission: true
luckperms.group.setinherit: true
luckperms.group.unsetinherit: true
luckperms.group.settemppermission: true
luckperms.group.unsettemppermission: true
luckperms.group.settempinherit: true
luckperms.group.unsettempinherit: true
luckperms.group.showtracks: true
luckperms.group.clear: true
luckperms.track.info: true
luckperms.track.append: true
luckperms.track.insert: true
luckperms.track.remove: true
luckperms.track.clear: true
luckperms.user.*:
description: Gives access to all LuckPerms user commands
children:
luckperms.user.info: true
luckperms.user.getuuid: true
luckperms.user.listnodes: true
luckperms.user.haspermission: true
luckperms.user.inheritspermission: true
luckperms.user.setpermission: true
luckperms.user.unsetpermission: true
luckperms.user.addgroup: true
luckperms.user.removegroup: true
luckperms.user.settemppermission: true
luckperms.user.unsettemppermission: true
luckperms.user.addtempgroup: true
luckperms.user.removetempgroup: true
luckperms.user.setprimarygroup: true
luckperms.user.showtracks: true
luckperms.user.promote: true
luckperms.user.demote: true
luckperms.user.showpos: true
luckperms.user.clear: true
luckperms.group.*:
description: Gives access to all LuckPerms group commands
children:
luckperms.group.info: true
luckperms.group.listnodes: true
luckperms.group.haspermission: true
luckperms.group.inheritspermission: true
luckperms.group.setpermission: true
luckperms.group.unsetpermission: true
luckperms.group.setinherit: true
luckperms.group.unsetinherit: true
luckperms.group.settemppermission: true
luckperms.group.unsettemppermission: true
luckperms.group.settempinherit: true
luckperms.group.unsettempinherit: true
luckperms.group.showtracks: true
luckperms.group.clear: true
luckperms.track.*:
description: Gives access to all LuckPerms track commands
children:
luckperms.track.info: true
luckperms.track.append: true
luckperms.track.insert: true
luckperms.track.remove: true
luckperms.track.clear: true
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -29,14 +29,13 @@ import me.lucko.luckperms.utils.UuidCache;
import net.md_5.bungee.api.chat.TextComponent;
import net.md_5.bungee.api.connection.PendingConnection;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.event.LoginEvent;
import net.md_5.bungee.api.event.PlayerDisconnectEvent;
import net.md_5.bungee.api.event.PostLoginEvent;
import net.md_5.bungee.api.event.ServerSwitchEvent;
import net.md_5.bungee.api.event.*;
import net.md_5.bungee.api.plugin.Listener;
import net.md_5.bungee.event.EventHandler;
import java.lang.ref.WeakReference;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -49,6 +48,27 @@ class BungeeListener extends AbstractListener implements Listener {
this.plugin = plugin;
}
@EventHandler
public void onPlayerPermissionCheck(PermissionCheckEvent e) {
if (!(e.getSender() instanceof ProxiedPlayer)) {
return;
}
final ProxiedPlayer player = ((ProxiedPlayer) e.getSender());
final User user = plugin.getUserManager().getUser(plugin.getUuidCache().getUUID(player.getUniqueId()));
if (user == null) return;
final String server = player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
Map<String, Boolean> local = user.getLocalPermissions(plugin.getConfiguration().getServer(), server, null, Collections.singletonList(e.getPermission()));
for (Map.Entry<String, Boolean> en : local.entrySet()) {
if (en.getKey().equalsIgnoreCase(e.getPermission())) {
e.setHasPermission(en.getValue());
return;
}
}
}
@EventHandler
public void onPlayerLogin(LoginEvent e) {
/* Delay the login here, as we want to cache UUID data before the player is connected to a backend bukkit server.
@@ -41,6 +41,7 @@ import me.lucko.luckperms.utils.UuidCache;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.api.plugin.Plugin;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
@@ -143,6 +144,12 @@ public class LPBungeePlugin extends Plugin implements LuckPermsPlugin {
return getProxy().getPlayers().stream().map(ProxiedPlayer::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
// No such thing on Bungee. Wildcards are processed in the listener instead.
return Collections.emptyList();
}
@Override
public void runUpdateTask() {
doAsync(new UpdateTask(this));
@@ -23,38 +23,20 @@
package me.lucko.luckperms.users;
import me.lucko.luckperms.LPBungeePlugin;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.UUID;
public class BungeeUser extends User {
private final LPBungeePlugin plugin;
BungeeUser(UUID uuid, LPBungeePlugin plugin) {
super(uuid, plugin);
this.plugin = plugin;
}
BungeeUser(UUID uuid, String username, LPBungeePlugin plugin) {
super(uuid, username, plugin);
this.plugin = plugin;
}
@Override
public void refreshPermissions() {
ProxiedPlayer player = plugin.getProxy().getPlayer(plugin.getUuidCache().getExternalUUID(getUuid()));
if (player == null) return;
// Clear existing permissions
Collection<String> perms = new ArrayList<>(player.getPermissions());
perms.forEach(p -> player.setPermission(p, false));
// Re-add all defined permissions for the user
final String server = player.getServer() == null ? null : (player.getServer().getInfo() == null ? null : player.getServer().getInfo().getName());
Map<String, Boolean> local = getLocalPermissions(getPlugin().getConfiguration().getServer(), server, null);
local.entrySet().forEach(e -> player.setPermission(e.getKey(), e.getValue()));
// Do nothing. Permissions are applied when needed in a listener.
}
}
+15
View File
@@ -22,6 +22,21 @@ include-global: false
# In this case, set online-mode to true no matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode: true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# 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
+1 -1
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -106,6 +106,12 @@ public interface LuckPermsPlugin {
*/
List<String> getPlayerList();
/**
* Gets all possible permission nodes, used for resolving wildcards
* @return a {@link List} of permission nodes
*/
List<String> getPossiblePermissions();
/**
* Runs an update task
*/
@@ -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());
}
@@ -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 {
@@ -63,6 +63,21 @@ public class LPConfigurationLink implements LPConfiguration {
return master.getOnlineMode();
}
@Override
public boolean getApplyWildcards() {
return master.getApplyWildcards();
}
@Override
public boolean getApplyRegex() {
return master.getApplyRegex();
}
@Override
public boolean getApplyShorthand() {
return master.getApplyShorthand();
}
@Override
public MySQLConfiguration getDatabaseValues() {
return master.getDatabaseValues();
@@ -175,11 +175,21 @@ class PermissionHolderLink implements PermissionHolder {
master.unsetPermission(checkNode(node), checkServer(server), world, temporary);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, world, excludedGroups, possibleNodes);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return master.getLocalPermissions(server, world, excludedGroups);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return master.getLocalPermissions(server, excludedGroups, possibleNodes);
}
@Override
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return master.getLocalPermissions(server, excludedGroups);
@@ -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;
@@ -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 {
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -40,6 +40,6 @@ public class InfoCommand extends SingleMainCommand {
protected void execute(LuckPermsPlugin plugin, Sender sender, List<String> args, String label) {
final LPConfiguration c = plugin.getConfiguration();
Message.INFO.send(sender, plugin.getVersion(), plugin.getDatastore().getName(), c.getServer(),
c.getDefaultGroupName(), c.getSyncTime(), c.getIncludeGlobalPerms(), c.getOnlineMode());
c.getDefaultGroupName(), c.getSyncTime(), c.getIncludeGlobalPerms(), c.getOnlineMode(), c.getApplyWildcards());
}
}
@@ -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;
}
@@ -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;
}
@@ -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);
@@ -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;
}
@@ -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;
}
@@ -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) {
@@ -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;
}
@@ -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;
}
@@ -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) {
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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;
}
@@ -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) {
@@ -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;
}
@@ -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;
}
@@ -41,7 +41,7 @@ public enum Message {
COMMAND_NOT_RECOGNISED("Command not recognised.", true),
COMMAND_NO_PERMISSION("You do not have permission to use this command!", true),
INFO_BRIEF("&6Running &bLuckPerms %s&6.", true),
INFO_BRIEF("&6Running &bLuckPerms v%s&6.", true),
ALREADY_HASPERMISSION("%s already has this permission!", true),
DOES_NOT_HAVEPERMISSION("%s does not have this permission set.", true),
@@ -105,27 +105,26 @@ 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),
UPDATE_TASK_RUN("&bRunning update task for all online users.", true),
INFO(
PREFIX + "&6Running &bLuckPerms %s&6." + "\n" +
PREFIX + "&6Running &bLuckPerms v%s&6." + "\n" +
PREFIX + "&eAuthor: &6Luck" + "\n" +
PREFIX + "&eStorage Method: &6%s" + "\n" +
PREFIX + "&eServer Name: &6%s" + "\n" +
PREFIX + "&eDefault Group: &6%s" + "\n" +
PREFIX + "&eSync Interval: &6%s minutes" + "\n" +
PREFIX + "&eInclude Global Perms: &6%s" + "\n" +
PREFIX + "&eOnline Mode: &6%s",
PREFIX + "&eOnline Mode: &6%s" + "\n" +
PREFIX + "&eApply Wildcards: &6%s",
false
),
DEBUG(
@@ -240,7 +239,7 @@ public enum Message {
),
TRACK_CLEAR("&b%s&a's groups track was cleared.", true),
TRACK_APPEND_SUCCESS("&aGroup &b%s&a was successfully appended to track &b%s&a.", true),
TRACK_INSERT_SUCCESS("&aGroup &b%s&a was successfully inserted into to track &b%s&a at position &b%s&a.", true),
TRACK_INSERT_SUCCESS("&aGroup &b%s&a was successfully inserted into track &b%s&a at position &b%s&a.", true),
TRACK_INSERT_ERROR_NUMBER("Expected number but instead received: %s", true),
TRACK_INSERT_ERROR_INVALID_POS("Unable to insert at position %s. Index out of bounds.", true),
TRACK_REMOVE_SUCCESS("&aGroup &b%s&a was successfully removed from track &b%s&a.", true);
@@ -23,7 +23,6 @@
package me.lucko.luckperms.constants;
import lombok.AllArgsConstructor;
import lombok.Getter;
import me.lucko.luckperms.commands.Sender;
@SuppressWarnings("SpellCheckingInspection")
@@ -42,74 +41,56 @@ public enum Permission {
DELETE_TRACK("deletetrack", null),
LIST_TRACKS("listtracks", null),
USER_INFO("info", PermissionGroup.USER),
USER_GETUUID("getuuid", PermissionGroup.USER),
USER_LISTNODES("listnodes", PermissionGroup.USER),
USER_HASPERMISSION("haspermission", PermissionGroup.USER),
USER_INHERITSPERMISSION("inheritspermission", PermissionGroup.USER),
USER_SETPERMISSION("setpermission", PermissionGroup.USER),
USER_UNSETPERMISSION("unsetpermission", PermissionGroup.USER),
USER_ADDGROUP("addgroup", PermissionGroup.USER),
USER_REMOVEGROUP("removegroup", PermissionGroup.USER),
USER_SET_TEMP_PERMISSION("settemppermission", PermissionGroup.USER),
USER_UNSET_TEMP_PERMISSION("unsettemppermission", PermissionGroup.USER),
USER_ADDTEMPGROUP("addtempgroup", PermissionGroup.USER),
USER_REMOVETEMPGROUP("removetempgroup", PermissionGroup.USER),
USER_SETPRIMARYGROUP("setprimarygroup", PermissionGroup.USER),
USER_SHOWTRACKS("showtracks", PermissionGroup.USER),
USER_PROMOTE("promote", PermissionGroup.USER),
USER_DEMOTE("demote", PermissionGroup.USER),
USER_SHOWPOS("showpos", PermissionGroup.USER),
USER_CLEAR("clear", PermissionGroup.USER),
USER_INFO("info", "user"),
USER_GETUUID("getuuid", "user"),
USER_LISTNODES("listnodes", "user"),
USER_HASPERMISSION("haspermission", "user"),
USER_INHERITSPERMISSION("inheritspermission", "user"),
USER_SETPERMISSION("setpermission", "user"),
USER_UNSETPERMISSION("unsetpermission", "user"),
USER_ADDGROUP("addgroup", "user"),
USER_REMOVEGROUP("removegroup", "user"),
USER_SET_TEMP_PERMISSION("settemppermission", "user"),
USER_UNSET_TEMP_PERMISSION("unsettemppermission", "user"),
USER_ADDTEMPGROUP("addtempgroup", "user"),
USER_REMOVETEMPGROUP("removetempgroup", "user"),
USER_SETPRIMARYGROUP("setprimarygroup", "user"),
USER_SHOWTRACKS("showtracks", "user"),
USER_PROMOTE("promote", "user"),
USER_DEMOTE("demote", "user"),
USER_SHOWPOS("showpos", "user"),
USER_CLEAR("clear", "user"),
GROUP_INFO("info", PermissionGroup.GROUP),
GROUP_LISTNODES("listnodes", PermissionGroup.GROUP),
GROUP_HASPERMISSION("haspermission", PermissionGroup.GROUP),
GROUP_INHERITSPERMISSION("inheritspermission", PermissionGroup.GROUP),
GROUP_SETPERMISSION("setpermission", PermissionGroup.GROUP),
GROUP_UNSETPERMISSION("unsetpermission", PermissionGroup.GROUP),
GROUP_SETINHERIT("setinherit", PermissionGroup.GROUP),
GROUP_UNSETINHERIT("unsetinherit", PermissionGroup.GROUP),
GROUP_SET_TEMP_PERMISSION("settemppermission", PermissionGroup.GROUP),
GROUP_UNSET_TEMP_PERMISSION("unsettemppermission", PermissionGroup.GROUP),
GROUP_SET_TEMP_INHERIT("settempinherit", PermissionGroup.GROUP),
GROUP_UNSET_TEMP_INHERIT("unsettempinherit", PermissionGroup.GROUP),
GROUP_SHOWTRACKS("showtracks", PermissionGroup.GROUP),
GROUP_CLEAR("clear", PermissionGroup.GROUP),
GROUP_INFO("info", "group"),
GROUP_LISTNODES("listnodes", "group"),
GROUP_HASPERMISSION("haspermission", "group"),
GROUP_INHERITSPERMISSION("inheritspermission", "group"),
GROUP_SETPERMISSION("setpermission", "group"),
GROUP_UNSETPERMISSION("unsetpermission", "group"),
GROUP_SETINHERIT("setinherit", "group"),
GROUP_UNSETINHERIT("unsetinherit", "group"),
GROUP_SET_TEMP_PERMISSION("settemppermission", "group"),
GROUP_UNSET_TEMP_PERMISSION("unsettemppermission", "group"),
GROUP_SET_TEMP_INHERIT("settempinherit", "group"),
GROUP_UNSET_TEMP_INHERIT("unsettempinherit", "group"),
GROUP_SHOWTRACKS("showtracks", "group"),
GROUP_CLEAR("clear", "group"),
TRACK_INFO("info", PermissionGroup.TRACK),
TRACK_APPEND("append", PermissionGroup.TRACK),
TRACK_INSERT("insert", PermissionGroup.TRACK),
TRACK_REMOVE("remove", PermissionGroup.TRACK),
TRACK_CLEAR("clear", PermissionGroup.TRACK);
TRACK_INFO("info", "track"),
TRACK_APPEND("append", "track"),
TRACK_INSERT("insert", "track"),
TRACK_REMOVE("remove", "track"),
TRACK_CLEAR("clear", "track");
private String node;
private PermissionGroup group;
private String group;
public boolean isAuthorized(Sender sender) {
if (sender.hasPermission("luckperms.*")) {
return true;
}
if (group != null) {
return group.isAuthorized(sender) || sender.hasPermission("luckperms." + group.getNode() + "." + node);
return sender.hasPermission("luckperms." + group + "." + node);
}
return sender.hasPermission("luckperms." + node);
}
@Getter
@AllArgsConstructor
private enum PermissionGroup {
USER("user"),
GROUP("group"),
TRACK("track");
private String node;
private boolean isAuthorized(Sender sender) {
return sender.hasPermission("luckperms." + node + ".*");
}
}
}
@@ -282,7 +282,7 @@ public class Group extends PermissionHolder {
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal);
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])
@@ -313,7 +313,7 @@ public abstract class User extends PermissionHolder {
*/
private List<String> getGroups(String server, String world, boolean includeGlobal) {
// Call super #getPermissions method, and just sort through those
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal);
Map<String, Boolean> perms = getPermissions(server, world, null, includeGlobal, null);
return perms.keySet().stream()
.filter(s -> Patterns.GROUP_MATCH.matcher(s).matches())
.map(s -> Patterns.DOT.split(s, 2)[1])
@@ -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);
}
}
@@ -88,6 +88,18 @@ public abstract class LPConfiguration<T extends LuckPermsPlugin> {
return getBoolean("online-mode", true);
}
public boolean getApplyWildcards() {
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),
@@ -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);
}
}
@@ -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;
/**
@@ -396,6 +397,18 @@ public abstract class PermissionHolder {
unsetPermission(server + "-" + world + "/" + node, temporary);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param world The world to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups, List<String> possibleNodes) {
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms(), possibleNodes);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
@@ -404,7 +417,18 @@ public abstract class PermissionHolder {
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, String world, List<String> excludedGroups) {
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms());
return getPermissions(server, world, excludedGroups, plugin.getConfiguration().getIncludeGlobalPerms(), null);
}
/**
* Gets the permissions and inherited permissions that apply to a specific server
* @param server The server to get nodes for
* @param excludedGroups Groups that shouldn't be inherited (to prevent circular inheritance issues)
* @param possibleNodes A list of possible permission nodes for wildcard permission handling
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups, List<String> possibleNodes) {
return getLocalPermissions(server, null, excludedGroups, possibleNodes);
}
/**
@@ -414,7 +438,7 @@ public abstract class PermissionHolder {
* @return a {@link Map} of the permissions
*/
public Map<String, Boolean> getLocalPermissions(String server, List<String> excludedGroups) {
return getLocalPermissions(server, null, excludedGroups);
return getLocalPermissions(server, null, excludedGroups, null);
}
/**
@@ -468,7 +492,7 @@ public abstract class PermissionHolder {
return nodes;
}
protected Map<String, Boolean> getPermissions(String server, String world, List<String> excludedGroups, boolean includeGlobal) {
protected Map<String, Boolean> getPermissions(String server, String world, List<String> excludedGroups, boolean includeGlobal, List<String> possibleNodes) {
if (excludedGroups == null) {
excludedGroups = new ArrayList<>();
}
@@ -514,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;
}
@@ -540,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;
}
@@ -608,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()) {
@@ -630,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)) {
@@ -641,11 +669,152 @@ 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()) {
perms = applyWildcards(perms, possibleNodes);
} else {
perms = applyWildcards(perms, plugin.getPossiblePermissions());
}
}
return perms;
}
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("'*'")) {
wildcards.put(0, Collections.singletonMap("*", e.getValue()));
continue;
}
if (!e.getKey().endsWith(".*")) {
continue;
}
final String node = e.getKey().substring(0, e.getKey().length() - 2);
final String[] parts = Patterns.DOT.split(node);
if (!wildcards.containsKey(parts.length)) {
wildcards.put(parts.length, new HashMap<>());
}
wildcards.get(parts.length).put(node, e.getValue());
}
for (Map.Entry<Integer, Map<String, Boolean>> e : wildcards.entrySet()) {
if (e.getKey() == 0) {
// Apply all permissions
possibleNodes.stream()
.filter(n -> !input.containsKey(n)) // Don't override existing nodes
.forEach(n -> input.put(n, e.getValue().get("*")));
break;
}
for (Map.Entry<String, Boolean> wc : e.getValue().entrySet()) {
possibleNodes.stream()
.filter(n -> n.startsWith(wc.getKey() + ".")) // Only nodes that match the wildcard are applied
.filter(n -> !input.containsKey(n)) // Don't override existing nodes
.forEach(n -> input.put(n, wc.getValue()));
}
}
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];
+1 -1
View File
@@ -6,7 +6,7 @@
<groupId>me.lucko.luckperms</groupId>
<artifactId>luckperms</artifactId>
<version>2.0</version>
<version>2.2</version>
<modules>
<module>common</module>
<module>api</module>
+1 -12
View File
@@ -5,7 +5,7 @@
<parent>
<artifactId>luckperms</artifactId>
<groupId>me.lucko.luckperms</groupId>
<version>2.0</version>
<version>2.2</version>
</parent>
<modelVersion>4.0.0</modelVersion>
@@ -45,10 +45,6 @@
<configuration>
<minimizeJar>true</minimizeJar>
<relocations>
<relocation>
<pattern>org.slf4j</pattern>
<shadedPattern>me.lucko.luckperms.lib.slf4j</shadedPattern>
</relocation>
<relocation>
<pattern>com.zaxxer.hikari</pattern>
<shadedPattern>me.lucko.luckperms.lib.hikari</shadedPattern>
@@ -139,13 +135,6 @@
<version>2.4.7</version>
<scope>compile</scope>
</dependency>
<!-- slf4j library -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.7.9</version>
<scope>compile</scope>
</dependency>
<!-- javassist maven -->
<dependency>
<groupId>de.icongmbh.oss.maven.plugins</groupId>
@@ -46,20 +46,26 @@ import org.spongepowered.api.command.CommandManager;
import org.spongepowered.api.config.ConfigDir;
import org.spongepowered.api.entity.living.player.Player;
import org.spongepowered.api.event.Listener;
import org.spongepowered.api.event.game.state.GamePostInitializationEvent;
import org.spongepowered.api.event.game.state.GamePreInitializationEvent;
import org.spongepowered.api.event.game.state.GameStoppingServerEvent;
import org.spongepowered.api.plugin.Plugin;
import org.spongepowered.api.scheduler.Scheduler;
import org.spongepowered.api.service.permission.PermissionDescription;
import org.spongepowered.api.service.permission.PermissionService;
import org.spongepowered.api.text.Text;
import java.io.File;
import java.nio.file.Path;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Getter
@Plugin(id = "luckperms", name = "LuckPerms", version = "MAGIC", authors = {"Luck"}, description = "A permissions plugin")
@Plugin(id = "luckperms", name = "LuckPerms", version = "null", authors = {"Luck"}, description = "A permissions plugin")
public class LPSpongePlugin implements LuckPermsPlugin {
@Inject
@@ -96,6 +102,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
getLog().info("Registering commands...");
CommandManager cmdService = Sponge.getCommandManager();
cmdService.register(this, new SpongeCommand(this), "luckperms", "perms", "lp", "permissions", "p", "perm");
registerPermissions();
getLog().info("Detecting storage method...");
final String storageMethod = configuration.getStorageMethod();
@@ -153,6 +160,11 @@ public class LPSpongePlugin implements LuckPermsPlugin {
LuckPerms.unregisterProvider();
}
@Listener
public void onPostInit(GamePostInitializationEvent event) {
registerPermissions();
}
@SuppressWarnings("ResultOfMethodCallIgnored")
private File getStorageDir() {
File base = configDir.toFile().getParentFile().getParentFile();
@@ -163,7 +175,7 @@ public class LPSpongePlugin implements LuckPermsPlugin {
@Override
public String getVersion() {
return "MAGIC";
return "null";
}
@Override
@@ -181,6 +193,15 @@ public class LPSpongePlugin implements LuckPermsPlugin {
return game.getServer().getOnlinePlayers().stream().map(Player::getName).collect(Collectors.toList());
}
@Override
public List<String> getPossiblePermissions() {
Optional<PermissionService> p = game.getServiceManager().provide(PermissionService.class);
if (!p.isPresent()) {
return Collections.emptyList();
}
return p.get().getDescriptions().stream().map(PermissionDescription::getId).collect(Collectors.toList());
}
@Override
public void runUpdateTask() {
scheduler.createTaskBuilder().async().execute(new UpdateTask(this)).submit(LPSpongePlugin.this);
@@ -195,4 +216,79 @@ public class LPSpongePlugin implements LuckPermsPlugin {
public void doSync(Runnable r) {
scheduler.createTaskBuilder().execute(r).submit(LPSpongePlugin.this);
}
private void registerPermissions() {
Optional<PermissionService> ps = game.getServiceManager().provide(PermissionService.class);
if (!ps.isPresent()) {
getLog().warn("Unable to register all LuckPerms permissions. PermissionService not available.");
return;
}
final PermissionService p = ps.get();
Optional<PermissionDescription.Builder> builder = p.newDescriptionBuilder(this);
if (!builder.isPresent()) {
getLog().warn("Unable to register all LuckPerms permissions. Description Builder not available.");
return;
}
registerPermission(p, "luckperms.sync");
registerPermission(p, "luckperms.info");
registerPermission(p, "luckperms.debug");
registerPermission(p, "luckperms.creategroup");
registerPermission(p, "luckperms.deletegroup");
registerPermission(p, "luckperms.listgroups");
registerPermission(p, "luckperms.createtrack");
registerPermission(p, "luckperms.deletetrack");
registerPermission(p, "luckperms.listtracks");
registerPermission(p, "luckperms.user.info");
registerPermission(p, "luckperms.user.getuuid");
registerPermission(p, "luckperms.user.listnodes");
registerPermission(p, "luckperms.user.haspermission");
registerPermission(p, "luckperms.user.inheritspermission");
registerPermission(p, "luckperms.user.setpermission");
registerPermission(p, "luckperms.user.unsetpermission");
registerPermission(p, "luckperms.user.addgroup");
registerPermission(p, "luckperms.user.removegroup");
registerPermission(p, "luckperms.user.settemppermission");
registerPermission(p, "luckperms.user.unsettemppermission");
registerPermission(p, "luckperms.user.addtempgroup");
registerPermission(p, "luckperms.user.removetempgroup");
registerPermission(p, "luckperms.user.setprimarygroup");
registerPermission(p, "luckperms.user.showtracks");
registerPermission(p, "luckperms.user.promote");
registerPermission(p, "luckperms.user.demote");
registerPermission(p, "luckperms.user.showpos");
registerPermission(p, "luckperms.user.clear");
registerPermission(p, "luckperms.group.info");
registerPermission(p, "luckperms.group.listnodes");
registerPermission(p, "luckperms.group.haspermission");
registerPermission(p, "luckperms.group.inheritspermission");
registerPermission(p, "luckperms.group.setpermission");
registerPermission(p, "luckperms.group.unsetpermission");
registerPermission(p, "luckperms.group.setinherit");
registerPermission(p, "luckperms.group.unsetinherit");
registerPermission(p, "luckperms.group.settemppermission");
registerPermission(p, "luckperms.group.unsettemppermission");
registerPermission(p, "luckperms.group.settempinherit");
registerPermission(p, "luckperms.group.unsettempinherit");
registerPermission(p, "luckperms.group.showtracks");
registerPermission(p, "luckperms.group.clear");
registerPermission(p, "luckperms.track.info");
registerPermission(p, "luckperms.track.append");
registerPermission(p, "luckperms.track.insert");
registerPermission(p, "luckperms.track.remove");
registerPermission(p, "luckperms.track.clear");
}
private void registerPermission(PermissionService p, String node) {
Optional<PermissionDescription.Builder> builder = p.newDescriptionBuilder(this);
if (!builder.isPresent()) return;
try {
builder.get().assign(PermissionDescription.ROLE_ADMIN, true).description(Text.of(node)).id(node).register();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
@@ -51,6 +51,7 @@ class SpongeCommand extends CommandManager implements CommandCallable {
@Override
public List<String> getSuggestions(CommandSource source, String s) throws CommandException {
// TODO: fix this so it actually works
return onTabComplete(FACTORY.wrap(source), Arrays.asList(Patterns.SPACE.split(s)));
}
@@ -33,7 +33,8 @@ import org.spongepowered.api.event.network.ClientConnectionEvent;
import org.spongepowered.api.profile.GameProfile;
import org.spongepowered.api.text.serializer.TextSerializers;
class SpongeListener extends AbstractListener {
@SuppressWarnings("WeakerAccess")
public class SpongeListener extends AbstractListener {
private final LPSpongePlugin plugin;
SpongeListener(LPSpongePlugin plugin) {
+15
View File
@@ -22,6 +22,21 @@ include-global=true
# matter what is set in server.properties. (we can just fallback to the servers uuid cache)
online-mode=true
# If the plugin should apply wildcard permissions.
# If set to true, LuckPerms will detect wildcard permissions, and resolve & apply all registered permissions matching
# 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