Merge branch 'master' of https://github.com/AuthMe/AuthMeReloaded into 1141-optional-additional-2fa-auth
# Conflicts: # src/main/java/fr/xephi/authme/permission/PlayerPermission.java # src/main/java/fr/xephi/authme/service/BukkitService.java
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
package fr.xephi.authme.data;
|
||||
|
||||
import fr.xephi.authme.initialization.HasCleanup;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.permission.PlayerPermission;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||
import fr.xephi.authme.util.expiring.ExpiringSet;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class QuickCommandsProtectionManager implements SettingsDependent, HasCleanup {
|
||||
|
||||
private final PermissionsManager permissionsManager;
|
||||
|
||||
private final ExpiringSet<String> latestJoin;
|
||||
|
||||
@Inject
|
||||
public QuickCommandsProtectionManager(Settings settings, PermissionsManager permissionsManager) {
|
||||
this.permissionsManager = permissionsManager;
|
||||
long countTimeout = settings.getProperty(ProtectionSettings.QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS);
|
||||
latestJoin = new ExpiringSet<>(countTimeout, TimeUnit.MILLISECONDS);
|
||||
reload(settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the player in the set
|
||||
* @param name the player's name
|
||||
*/
|
||||
private void setJoin(String name) {
|
||||
latestJoin.add(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given player has the permission and should be saved in the set
|
||||
* @param player the player to check
|
||||
* @return true if the player has the permission, false otherwise
|
||||
*/
|
||||
private boolean shouldSavePlayer(Player player) {
|
||||
return permissionsManager.hasPermission(player, PlayerPermission.QUICK_COMMANDS_PROTECTION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the player join
|
||||
* @param player the player to process
|
||||
*/
|
||||
public void processJoin(Player player) {
|
||||
if(shouldSavePlayer(player)) {
|
||||
setJoin(player.getName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given player is able to perform the command
|
||||
* @param name the name of the player to check
|
||||
* @return true if the player is not in the set (so it's allowed to perform the command), false otherwise
|
||||
*/
|
||||
public boolean isAllowed(String name) {
|
||||
return !latestJoin.contains(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(Settings settings) {
|
||||
long countTimeout = settings.getProperty(ProtectionSettings.QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS);
|
||||
latestJoin.setExpiration(countTimeout, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performCleanup() {
|
||||
latestJoin.removeExpiredEntries();
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.listener;
|
||||
|
||||
import fr.xephi.authme.data.QuickCommandsProtectionManager;
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.message.MessageKey;
|
||||
@@ -86,6 +87,8 @@ public class PlayerListener implements Listener {
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
@Inject
|
||||
private QuickCommandsProtectionManager quickCommandsProtectionManager;
|
||||
@Inject
|
||||
private BungeeSender bungeeSender;
|
||||
|
||||
private boolean isAsyncPlayerPreLoginEventCalled = false;
|
||||
@@ -100,6 +103,11 @@ public class PlayerListener implements Listener {
|
||||
return;
|
||||
}
|
||||
final Player player = event.getPlayer();
|
||||
if (!quickCommandsProtectionManager.isAllowed(player.getName())) {
|
||||
event.setCancelled(true);
|
||||
player.kickPlayer(m.retrieveSingle(player, MessageKey.QUICK_COMMAND_PROTECTION_KICK));
|
||||
return;
|
||||
}
|
||||
if (listenerService.shouldCancelEvent(player)) {
|
||||
event.setCancelled(true);
|
||||
m.send(player, MessageKey.DENIED_COMMAND);
|
||||
@@ -207,6 +215,9 @@ public class PlayerListener implements Listener {
|
||||
if (!PlayerListener19Spigot.isPlayerSpawnLocationEventCalled()) {
|
||||
teleportationService.teleportOnJoin(player);
|
||||
}
|
||||
|
||||
quickCommandsProtectionManager.processJoin(player);
|
||||
|
||||
management.performJoin(player);
|
||||
|
||||
teleportationService.teleportNewPlayerToFirstSpawn(player);
|
||||
|
||||
@@ -278,6 +278,9 @@ public enum MessageKey {
|
||||
/** To verify your identity you need to link an email address with your account! */
|
||||
VERIFICATION_CODE_EMAIL_NEEDED("verification.email_needed"),
|
||||
|
||||
/** You used a command too fast! Please, join the server again and wait more before using any command. */
|
||||
QUICK_COMMAND_PROTECTION_KICK("on_join_validation.quick_command"),
|
||||
|
||||
/** second */
|
||||
SECOND("time.second"),
|
||||
|
||||
|
||||
@@ -70,6 +70,11 @@ public enum PlayerPermission implements PermissionNode {
|
||||
*/
|
||||
VERIFICATION_CODE("authme.player.security.verificationcode"),
|
||||
|
||||
/**
|
||||
* Permission that enables on join quick commands checks for the player.
|
||||
*/
|
||||
QUICK_COMMANDS_PROTECTION("authme.player.protection.quickcommandsprotection"),
|
||||
|
||||
/**
|
||||
* Permission to enable two-factor authentication.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.permission.handlers;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.permission.PermissionsSystemType;
|
||||
import me.lucko.luckperms.LuckPerms;
|
||||
@@ -41,13 +42,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
}
|
||||
|
||||
private void saveUser(User user) {
|
||||
luckPermsApi.getStorage().saveUser(user)
|
||||
.thenAcceptAsync(wasSuccessful -> {
|
||||
if (!wasSuccessful) {
|
||||
return;
|
||||
}
|
||||
user.refreshPermissions();
|
||||
}, luckPermsApi.getStorage().getAsyncExecutor());
|
||||
luckPermsApi.getUserManager().saveUser(user)
|
||||
.thenAcceptAsync(wasSuccessful -> user.refreshCachedData());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,7 +58,7 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
DataMutateResult result = user.setPermissionUnchecked(
|
||||
DataMutateResult result = user.setPermission(
|
||||
luckPermsApi.getNodeFactory().makeGroupNode(newGroup).build());
|
||||
if (result == DataMutateResult.FAIL) {
|
||||
return false;
|
||||
@@ -83,6 +79,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
public boolean hasPermissionOffline(String name, PermissionNode node) {
|
||||
User user = luckPermsApi.getUser(name);
|
||||
if (user == null) {
|
||||
ConsoleLogger.warning("LuckPermsHandler: tried to check permission for offline user "
|
||||
+ name + " but it isn't loaded!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -98,6 +96,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
public boolean isInGroup(OfflinePlayer player, String group) {
|
||||
User user = luckPermsApi.getUser(player.getName());
|
||||
if (user == null) {
|
||||
ConsoleLogger.warning("LuckPermsHandler: tried to check group for offline user "
|
||||
+ player.getName() + " but it isn't loaded!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -112,6 +112,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
public boolean removeFromGroup(OfflinePlayer player, String group) {
|
||||
User user = luckPermsApi.getUser(player.getName());
|
||||
if (user == null) {
|
||||
ConsoleLogger.warning("LuckPermsHandler: tried to remove group for offline user "
|
||||
+ player.getName() + " but it isn't loaded!");
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -121,7 +123,7 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
}
|
||||
|
||||
Node groupNode = luckPermsApi.getNodeFactory().makeGroupNode(permissionGroup).build();
|
||||
boolean result = user.unsetPermissionUnchecked(groupNode) != DataMutateResult.FAIL;
|
||||
boolean result = user.unsetPermission(groupNode) != DataMutateResult.FAIL;
|
||||
|
||||
luckPermsApi.cleanupUser(user);
|
||||
return result;
|
||||
@@ -131,6 +133,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
public boolean setGroup(OfflinePlayer player, String group) {
|
||||
User user = luckPermsApi.getUser(player.getName());
|
||||
if (user == null) {
|
||||
ConsoleLogger.warning("LuckPermsHandler: tried to set group for offline user "
|
||||
+ player.getName() + " but it isn't loaded!");
|
||||
return false;
|
||||
}
|
||||
Group permissionGroup = luckPermsApi.getGroup(group);
|
||||
@@ -138,7 +142,7 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
return false;
|
||||
}
|
||||
Node groupNode = luckPermsApi.getNodeFactory().makeGroupNode(permissionGroup).build();
|
||||
DataMutateResult result = user.setPermissionUnchecked(groupNode);
|
||||
DataMutateResult result = user.setPermission(groupNode);
|
||||
if (result == DataMutateResult.FAIL) {
|
||||
return false;
|
||||
}
|
||||
@@ -153,6 +157,8 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
public List<String> getGroups(OfflinePlayer player) {
|
||||
User user = luckPermsApi.getUser(player.getName());
|
||||
if (user == null) {
|
||||
ConsoleLogger.warning("LuckPermsHandler: tried to get groups for offline user "
|
||||
+ player.getName() + " but it isn't loaded!");
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -185,7 +191,7 @@ public class LuckPermsHandler implements PermissionHandler {
|
||||
@Override
|
||||
public void loadUserData(UUID uuid) {
|
||||
try {
|
||||
luckPermsApi.getStorage().loadUser(uuid).get(5, TimeUnit.SECONDS);
|
||||
luckPermsApi.getUserManager().loadUser(uuid).get(5, TimeUnit.SECONDS);
|
||||
} catch (InterruptedException | ExecutionException | TimeoutException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import org.bukkit.Bukkit;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Event;
|
||||
import org.bukkit.scheduler.BukkitRunnable;
|
||||
@@ -25,6 +26,7 @@ import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Function;
|
||||
|
||||
@@ -377,6 +379,21 @@ public class BukkitService implements SettingsDependent {
|
||||
return Bukkit.getServer().getBanList(BanList.Type.IP).addBan(ip, reason, expires, source);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an optional with a boolean indicating whether bungeecord is enabled or not if the
|
||||
* server implementation is Spigot. Otherwise returns an empty optional.
|
||||
*
|
||||
* @return Optional with configuration value for Spigot, empty optional otherwise
|
||||
*/
|
||||
public Optional<Boolean> isBungeeCordConfiguredForSpigot() {
|
||||
try {
|
||||
YamlConfiguration spigotConfig = Bukkit.spigot().getConfig();
|
||||
return Optional.of(spigotConfig.getBoolean("settings.bungeecord"));
|
||||
} catch (NoSuchMethodError e) {
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the IP string that this server is bound to, otherwise empty string
|
||||
*/
|
||||
|
||||
@@ -4,15 +4,15 @@ import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.security.HashAlgorithm;
|
||||
import fr.xephi.authme.security.crypts.Argon2;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.properties.EmailSettings;
|
||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||
import fr.xephi.authme.settings.properties.PluginSettings;
|
||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.bukkit.Bukkit;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Logs warning messages in cases where the configured values suggest a misconfiguration.
|
||||
@@ -29,6 +29,9 @@ public class SettingsWarner {
|
||||
@Inject
|
||||
private AuthMe authMe;
|
||||
|
||||
@Inject
|
||||
private BukkitService bukkitService;
|
||||
|
||||
SettingsWarner() {
|
||||
}
|
||||
|
||||
@@ -54,7 +57,7 @@ public class SettingsWarner {
|
||||
}
|
||||
|
||||
// Warn if spigot.yml has settings.bungeecord set to true but config.yml has Hooks.bungeecord set to false
|
||||
if (Utils.isSpigot() && Bukkit.spigot().getConfig().getBoolean("settings.bungeecord")
|
||||
if (isTrue(bukkitService.isBungeeCordConfiguredForSpigot())
|
||||
&& !settings.getProperty(HooksSettings.BUNGEECORD)) {
|
||||
ConsoleLogger.warning("Note: Hooks.bungeecord is set to false but your server appears to be running in"
|
||||
+ " bungeecord mode (see your spigot.yml). In order to allow the datasource caching and the"
|
||||
@@ -69,4 +72,8 @@ public class SettingsWarner {
|
||||
authMe.stopOrUnload();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isTrue(Optional<Boolean> value) {
|
||||
return value.isPresent() && value.get();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,6 +55,10 @@ public final class ProtectionSettings implements SettingsHolder {
|
||||
public static final Property<Integer> ANTIBOT_DELAY =
|
||||
newProperty("Protection.antiBotDelay", 60);
|
||||
|
||||
@Comment("Kicks the player that issued a command before the defined time after the join process")
|
||||
public static final Property<Integer> QUICK_COMMANDS_DENIED_BEFORE_MILLISECONDS =
|
||||
newProperty("Protection.quickCommands.denyCommandsBeforeMilliseconds", 1000);
|
||||
|
||||
private ProtectionSettings() {
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
package fr.xephi.authme.util;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
@@ -23,20 +22,6 @@ public final class Utils {
|
||||
private Utils() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if the running server instance is craftbukkit or spigot based.
|
||||
*
|
||||
* @return true if the running server instance is spigot-based.
|
||||
*/
|
||||
public static boolean isSpigot() {
|
||||
try {
|
||||
Bukkit.spigot();
|
||||
return true;
|
||||
} catch (NoSuchMethodError e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compile Pattern sneaky without throwing Exception.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user