Merge branch 'master' of https://github.com/AuthMe/AuthMeReloaded into explicit-getters-from-db
This commit is contained in:
@@ -72,6 +72,7 @@ public class AuthMe extends JavaPlugin {
|
||||
private DataSource database;
|
||||
private BukkitService bukkitService;
|
||||
private Injector injector;
|
||||
private BackupService backupService;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
@@ -154,7 +155,7 @@ public class AuthMe extends JavaPlugin {
|
||||
}
|
||||
|
||||
// Do a backup on start
|
||||
new BackupService(this, settings).doBackup(BackupService.BackupCause.START);
|
||||
backupService.doBackup(BackupService.BackupCause.START);
|
||||
|
||||
// Set up Metrics
|
||||
OnStartupTasks.sendMetrics(this, settings);
|
||||
@@ -257,6 +258,7 @@ public class AuthMe extends JavaPlugin {
|
||||
permsMan = injector.getSingleton(PermissionsManager.class);
|
||||
bukkitService = injector.getSingleton(BukkitService.class);
|
||||
commandHandler = injector.getSingleton(CommandHandler.class);
|
||||
backupService = injector.getSingleton(BackupService.class);
|
||||
|
||||
// Trigger construction of API classes; they will keep track of the singleton
|
||||
injector.getSingleton(fr.xephi.authme.api.v3.AuthMeApi.class);
|
||||
@@ -352,8 +354,8 @@ public class AuthMe extends JavaPlugin {
|
||||
}
|
||||
|
||||
// Do backup on stop if enabled
|
||||
if (settings != null) {
|
||||
new BackupService(this, settings).doBackup(BackupService.BackupCause.STOP);
|
||||
if (backupService != null) {
|
||||
backupService.doBackup(BackupService.BackupCause.STOP);
|
||||
}
|
||||
|
||||
// Wait for tasks and close data source
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import fr.xephi.authme.command.executable.HelpCommand;
|
||||
import fr.xephi.authme.command.executable.authme.AccountsCommand;
|
||||
import fr.xephi.authme.command.executable.authme.AuthMeCommand;
|
||||
import fr.xephi.authme.command.executable.authme.BackupCommand;
|
||||
import fr.xephi.authme.command.executable.authme.ChangePasswordAdminCommand;
|
||||
import fr.xephi.authme.command.executable.authme.ConverterCommand;
|
||||
import fr.xephi.authme.command.executable.authme.FirstSpawnCommand;
|
||||
@@ -39,8 +40,8 @@ import fr.xephi.authme.command.executable.logout.LogoutCommand;
|
||||
import fr.xephi.authme.command.executable.register.RegisterCommand;
|
||||
import fr.xephi.authme.command.executable.unregister.UnregisterCommand;
|
||||
import fr.xephi.authme.permission.AdminPermission;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PlayerPermission;
|
||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
@@ -226,13 +227,23 @@ public class CommandInitializer {
|
||||
.parent(AUTHME_BASE)
|
||||
.labels("purge", "delete")
|
||||
.description("Purge old data")
|
||||
.detailedDescription("Purge old AuthMeReloaded data longer than the specified amount of days ago.")
|
||||
.detailedDescription("Purge old AuthMeReloaded data longer than the specified number of days ago.")
|
||||
.withArgument("days", "Number of days", false)
|
||||
.withArgument("all", "Add 'all' at the end to also purge players with lastlogin = 0", true)
|
||||
.permission(AdminPermission.PURGE)
|
||||
.executableCommand(PurgeCommand.class)
|
||||
.register();
|
||||
|
||||
// Backup command
|
||||
CommandDescription.builder()
|
||||
.parent(AUTHME_BASE)
|
||||
.labels("backup")
|
||||
.description("Perform a backup")
|
||||
.detailedDescription("Creates a backup of the registered users.")
|
||||
.permission(AdminPermission.BACKUP)
|
||||
.executableCommand(BackupCommand.class)
|
||||
.register();
|
||||
|
||||
// Register the purgelastposition command
|
||||
CommandDescription.builder()
|
||||
.parent(AUTHME_BASE)
|
||||
@@ -312,10 +323,9 @@ public class CommandInitializer {
|
||||
.description("Debug features")
|
||||
.detailedDescription("Allows various operations for debugging.")
|
||||
.withArgument("child", "The child to execute", true)
|
||||
.withArgument(".", "meaning varies", true)
|
||||
.withArgument(".", "meaning varies", true)
|
||||
.withArgument(".", "meaning varies", true)
|
||||
.permission(PlayerStatePermission.DEBUG_COMMAND)
|
||||
.withArgument("arg", "argument (depends on debug section)", true)
|
||||
.withArgument("arg", "argument (depends on debug section)", true)
|
||||
.permission(DebugSectionPermissions.DEBUG_COMMAND)
|
||||
.executableCommand(DebugCommand.class)
|
||||
.register();
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package fr.xephi.authme.command.executable.authme;
|
||||
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.service.BackupService;
|
||||
import fr.xephi.authme.service.BackupService.BackupCause;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Command to perform a backup.
|
||||
*/
|
||||
public class BackupCommand implements ExecutableCommand {
|
||||
|
||||
@Inject
|
||||
private BackupService backupService;
|
||||
|
||||
@Override
|
||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||
backupService.doBackup(BackupCause.COMMAND, sender);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.service.GeoIpService;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
import fr.xephi.authme.settings.properties.ProtectionSettings;
|
||||
@@ -54,6 +56,11 @@ class CountryLookup implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.COUNTRY_LOOKUP;
|
||||
}
|
||||
|
||||
private void outputInfoForIpAddr(CommandSender sender, String ipAddr) {
|
||||
sender.sendMessage("IP '" + ipAddr + "' maps to country '" + geoIpService.getCountryCode(ipAddr)
|
||||
+ "' (" + geoIpService.getCountryName(ipAddr) + ")");
|
||||
|
||||
@@ -8,6 +8,8 @@ import fr.xephi.authme.initialization.HasCleanup;
|
||||
import fr.xephi.authme.initialization.Reloadable;
|
||||
import fr.xephi.authme.initialization.SettingsDependent;
|
||||
import fr.xephi.authme.initialization.factory.SingletonStore;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -52,6 +54,11 @@ class DataStatistics implements DebugSection {
|
||||
outputInjectorStats(sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.DATA_STATISTICS;
|
||||
}
|
||||
|
||||
private void outputDatabaseStats(CommandSender sender) {
|
||||
sender.sendMessage("Total players in DB: " + dataSource.getAccountsRegistered());
|
||||
if (dataSource instanceof CacheDataSource) {
|
||||
|
||||
@@ -3,6 +3,8 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import fr.xephi.authme.command.ExecutableCommand;
|
||||
import fr.xephi.authme.initialization.factory.Factory;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -24,27 +26,48 @@ public class DebugCommand implements ExecutableCommand {
|
||||
@Inject
|
||||
private Factory<DebugSection> debugSectionFactory;
|
||||
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
|
||||
private Map<String, DebugSection> sections;
|
||||
|
||||
@Override
|
||||
public void executeCommand(CommandSender sender, List<String> arguments) {
|
||||
DebugSection debugSection = getDebugSection(arguments);
|
||||
DebugSection debugSection = findDebugSection(arguments);
|
||||
if (debugSection == null) {
|
||||
sender.sendMessage("Available sections:");
|
||||
getSections().values()
|
||||
.forEach(e -> sender.sendMessage("- " + e.getName() + ": " + e.getDescription()));
|
||||
sendAvailableSections(sender);
|
||||
} else {
|
||||
debugSection.execute(sender, arguments.subList(1, arguments.size()));
|
||||
executeSection(debugSection, sender, arguments);
|
||||
}
|
||||
}
|
||||
|
||||
private DebugSection getDebugSection(List<String> arguments) {
|
||||
private DebugSection findDebugSection(List<String> arguments) {
|
||||
if (arguments.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return getSections().get(arguments.get(0).toLowerCase());
|
||||
}
|
||||
|
||||
private void sendAvailableSections(CommandSender sender) {
|
||||
sender.sendMessage("Sections available to you:");
|
||||
long availableSections = getSections().values().stream()
|
||||
.filter(section -> permissionsManager.hasPermission(sender, section.getRequiredPermission()))
|
||||
.peek(e -> sender.sendMessage("- " + e.getName() + ": " + e.getDescription()))
|
||||
.count();
|
||||
|
||||
if (availableSections == 0) {
|
||||
sender.sendMessage(ChatColor.RED + "You don't have permission to view any debug section");
|
||||
}
|
||||
}
|
||||
|
||||
private void executeSection(DebugSection section, CommandSender sender, List<String> arguments) {
|
||||
if (permissionsManager.hasPermission(sender, section.getRequiredPermission())) {
|
||||
section.execute(sender, arguments.subList(1, arguments.size()));
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "You don't have permission for this section. See /authme debug");
|
||||
}
|
||||
}
|
||||
|
||||
// Lazy getter
|
||||
private Map<String, DebugSection> getSections() {
|
||||
if (sections == null) {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import java.util.List;
|
||||
@@ -27,4 +28,9 @@ interface DebugSection {
|
||||
*/
|
||||
void execute(CommandSender sender, List<String> arguments);
|
||||
|
||||
/**
|
||||
* @return permission required to run this section
|
||||
*/
|
||||
PermissionNode getRequiredPermission();
|
||||
|
||||
}
|
||||
|
||||
+8
-3
@@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import fr.xephi.authme.permission.AdminPermission;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.DefaultPermission;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
@@ -25,8 +26,8 @@ import java.util.function.BiFunction;
|
||||
*/
|
||||
class HasPermissionChecker implements DebugSection {
|
||||
|
||||
static final List<Class<? extends PermissionNode>> PERMISSION_NODE_CLASSES =
|
||||
ImmutableList.of(AdminPermission.class, PlayerPermission.class, PlayerStatePermission.class);
|
||||
static final List<Class<? extends PermissionNode>> PERMISSION_NODE_CLASSES = ImmutableList.of(
|
||||
AdminPermission.class, PlayerPermission.class, PlayerStatePermission.class, DebugSectionPermissions.class);
|
||||
|
||||
@Inject
|
||||
private PermissionsManager permissionsManager;
|
||||
@@ -69,6 +70,11 @@ class HasPermissionChecker implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.HAS_PERMISSION_CHECK;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a permission check and informs the given sender of the result. {@code permissionChecker} is the
|
||||
* permission check to perform with the given {@code node} and the {@code player}.
|
||||
@@ -90,7 +96,6 @@ class HasPermissionChecker implements DebugSection {
|
||||
sender.sendMessage(ChatColor.DARK_RED + "Check failed: player '" + player.getName()
|
||||
+ "' does NOT have permission '" + node + "'");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -3,6 +3,8 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
import fr.xephi.authme.listener.FailedVerificationException;
|
||||
import fr.xephi.authme.listener.OnJoinVerifier;
|
||||
import fr.xephi.authme.message.Messages;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.service.ValidationService;
|
||||
import fr.xephi.authme.service.ValidationService.ValidationResult;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -60,6 +62,11 @@ class InputValidator implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.INPUT_VALIDATOR;
|
||||
}
|
||||
|
||||
private void displayUsageHint(CommandSender sender) {
|
||||
sender.sendMessage("You can define forbidden emails and passwords in your config.yml");
|
||||
sender.sendMessage("This command allows you to test some of the values:");
|
||||
|
||||
@@ -3,6 +3,8 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
import fr.xephi.authme.data.limbo.LimboPlayer;
|
||||
import fr.xephi.authme.data.limbo.LimboService;
|
||||
import fr.xephi.authme.data.limbo.persistence.LimboPersistence;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -71,6 +73,11 @@ class LimboPlayerViewer implements DebugSection {
|
||||
.sendEntry("Group", LimboPlayer::getGroup, permissionsManager::getPrimaryGroup);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.LIMBO_PLAYER_VIEWER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the info for the given LimboPlayer and Player to the provided CommandSender.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.permission.PermissionsManager;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandSender;
|
||||
@@ -38,4 +40,9 @@ class PermissionGroups implements DebugSection {
|
||||
sender.sendMessage("Primary group is: " + permissionsManager.getGroups(player));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.PERM_GROUPS;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@ package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.data.auth.PlayerAuth;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import org.bukkit.ChatColor;
|
||||
@@ -50,6 +52,11 @@ class PlayerAuthViewer implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.PLAYER_AUTH_VIEWER;
|
||||
}
|
||||
|
||||
/**
|
||||
* Outputs the PlayerAuth information to the given sender.
|
||||
*
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package fr.xephi.authme.command.executable.authme.debug;
|
||||
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.service.BukkitService;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.SpawnLoader;
|
||||
@@ -49,6 +51,11 @@ class SpawnLocationViewer implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.SPAWN_LOCATION;
|
||||
}
|
||||
|
||||
private void showGeneralInfo(CommandSender sender) {
|
||||
sender.sendMessage("Spawn priority: "
|
||||
+ String.join(", ", settings.getProperty(RestrictionSettings.SPAWN_PRIORITY)));
|
||||
|
||||
@@ -4,6 +4,8 @@ import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.datasource.DataSource;
|
||||
import fr.xephi.authme.datasource.DataSourceResult;
|
||||
import fr.xephi.authme.mail.SendMailSsl;
|
||||
import fr.xephi.authme.permission.DebugSectionPermissions;
|
||||
import fr.xephi.authme.permission.PermissionNode;
|
||||
import fr.xephi.authme.util.StringUtils;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.apache.commons.mail.EmailException;
|
||||
@@ -61,6 +63,11 @@ class TestEmailSender implements DebugSection {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionNode getRequiredPermission() {
|
||||
return DebugSectionPermissions.TEST_EMAIL;
|
||||
}
|
||||
|
||||
private String getEmail(CommandSender sender, List<String> arguments) {
|
||||
if (arguments.isEmpty()) {
|
||||
DataSourceResult<String> emailResult = dataSource.getEmail(sender.getName());
|
||||
|
||||
+1
-4
@@ -41,10 +41,7 @@ class DistributedFilesPersistenceHandler implements LimboPersistenceHandler {
|
||||
@Inject
|
||||
DistributedFilesPersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService, Settings settings) {
|
||||
cacheFolder = new File(dataFolder, "playerdata");
|
||||
if (!cacheFolder.exists()) {
|
||||
// TODO ljacqu 20170313: Create FileUtils#mkdirs
|
||||
cacheFolder.mkdirs();
|
||||
}
|
||||
FileUtils.createDirectory(cacheFolder);
|
||||
|
||||
gson = new GsonBuilder()
|
||||
.registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer())
|
||||
|
||||
@@ -8,6 +8,7 @@ import fr.xephi.authme.security.PasswordSecurity;
|
||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.ConverterSettings;
|
||||
import fr.xephi.authme.util.Utils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -85,8 +86,7 @@ public class RakamakConverter implements Converter {
|
||||
.build();
|
||||
database.saveAuth(auth);
|
||||
}
|
||||
ConsoleLogger.info("Rakamak database has been imported correctly");
|
||||
sender.sendMessage("Rakamak database has been imported correctly");
|
||||
Utils.logAndSendMessage(sender, "Rakamak database has been imported correctly");
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.logException("Can't open the rakamak database file! Does it exist?", ex);
|
||||
}
|
||||
|
||||
@@ -113,7 +113,12 @@ public enum AdminPermission implements PermissionNode {
|
||||
/**
|
||||
* Permission to see the other accounts of the players that log in.
|
||||
*/
|
||||
SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts");
|
||||
SEE_OTHER_ACCOUNTS("authme.admin.seeotheraccounts"),
|
||||
|
||||
/**
|
||||
* Allows to use the backup command.
|
||||
*/
|
||||
BACKUP("authme.admin.backup");
|
||||
|
||||
/**
|
||||
* The permission node.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package fr.xephi.authme.permission;
|
||||
|
||||
/**
|
||||
* Permissions for the debug sections (/authme debug).
|
||||
*/
|
||||
public enum DebugSectionPermissions implements PermissionNode {
|
||||
|
||||
/** General permission to use the /authme debug command. */
|
||||
DEBUG_COMMAND("authme.debug.command"),
|
||||
|
||||
/** Permission to use the country lookup section. */
|
||||
COUNTRY_LOOKUP("authme.debug.country"),
|
||||
|
||||
/** Permission to use the stats section. */
|
||||
DATA_STATISTICS("authme.debug.stats"),
|
||||
|
||||
/** Permission to use the permission checker. */
|
||||
HAS_PERMISSION_CHECK("authme.debug.perm"),
|
||||
|
||||
/** Permission to use sample validation. */
|
||||
INPUT_VALIDATOR("authme.debug.valid"),
|
||||
|
||||
/** Permission to use the limbo data viewer. */
|
||||
LIMBO_PLAYER_VIEWER("authme.debug.limbo"),
|
||||
|
||||
/** Permission to view permission groups. */
|
||||
PERM_GROUPS("authme.debug.group"),
|
||||
|
||||
/** Permission to view data from the database. */
|
||||
PLAYER_AUTH_VIEWER("authme.debug.db"),
|
||||
|
||||
/** Permission to view spawn information. */
|
||||
SPAWN_LOCATION("authme.debug.spawn"),
|
||||
|
||||
/** Permission to use the test email sender. */
|
||||
TEST_EMAIL("authme.debug.mail");
|
||||
|
||||
private final String node;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param node the permission node
|
||||
*/
|
||||
DebugSectionPermissions(String node) {
|
||||
this.node = node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getNode() {
|
||||
return node;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DefaultPermission getDefaultPermission() {
|
||||
return DefaultPermission.OP_ONLY;
|
||||
}
|
||||
}
|
||||
@@ -29,12 +29,7 @@ public enum PlayerStatePermission implements PermissionNode {
|
||||
/**
|
||||
* Permission to bypass the purging process.
|
||||
*/
|
||||
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED),
|
||||
|
||||
/**
|
||||
* Permission to use the /authme debug command.
|
||||
*/
|
||||
DEBUG_COMMAND("authme.debug", DefaultPermission.OP_ONLY);
|
||||
BYPASS_PURGE("authme.bypasspurge", DefaultPermission.NOT_ALLOWED);
|
||||
|
||||
/**
|
||||
* The permission node.
|
||||
|
||||
@@ -85,12 +85,22 @@ public final class HashUtils {
|
||||
* @param algorithm The algorithm to hash the message with
|
||||
* @return The digest in its hexadecimal representation
|
||||
*/
|
||||
private static String hash(String message, MessageDigestAlgorithm algorithm) {
|
||||
MessageDigest md = getDigest(algorithm);
|
||||
md.reset();
|
||||
md.update(message.getBytes());
|
||||
byte[] digest = md.digest();
|
||||
public static String hash(String message, MessageDigest algorithm) {
|
||||
algorithm.reset();
|
||||
algorithm.update(message.getBytes());
|
||||
byte[] digest = algorithm.digest();
|
||||
return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest));
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash the message with the given algorithm and return the hash in its hexadecimal notation.
|
||||
*
|
||||
* @param message The message to hash
|
||||
* @param algorithm The algorithm to hash the message with
|
||||
* @return The digest in its hexadecimal representation
|
||||
*/
|
||||
private static String hash(String message, MessageDigestAlgorithm algorithm) {
|
||||
return hash(message, getDigest(algorithm));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
package fr.xephi.authme.security.crypts;
|
||||
|
||||
import fr.xephi.authme.security.HashUtils;
|
||||
import fr.xephi.authme.security.MessageDigestAlgorithm;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public class RoyalAuth extends UnsaltedMethod {
|
||||
|
||||
@Override
|
||||
public String computeHash(String password) {
|
||||
for (int i = 0; i < 25; i++) {
|
||||
// TODO ljacqu 20151228: HashUtils#sha512 gets a new message digest each time...
|
||||
password = HashUtils.sha512(password);
|
||||
MessageDigest algorithm = HashUtils.getDigest(MessageDigestAlgorithm.SHA512);
|
||||
for (int i = 0; i < 25; ++i) {
|
||||
password = HashUtils.hash(password, algorithm);
|
||||
}
|
||||
return password;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package fr.xephi.authme.service;
|
||||
|
||||
import fr.xephi.authme.AuthMe;
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import fr.xephi.authme.datasource.DataSourceType;
|
||||
import fr.xephi.authme.initialization.DataFolder;
|
||||
import fr.xephi.authme.settings.Settings;
|
||||
import fr.xephi.authme.settings.properties.BackupSettings;
|
||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||
import fr.xephi.authme.util.FileUtils;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -16,80 +19,80 @@ import java.io.OutputStream;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
import static fr.xephi.authme.util.Utils.logAndSendMessage;
|
||||
import static fr.xephi.authme.util.Utils.logAndSendWarning;
|
||||
|
||||
/**
|
||||
* The backup management class
|
||||
*
|
||||
* @author stefano
|
||||
* Performs a backup of the data source.
|
||||
*/
|
||||
public class BackupService {
|
||||
|
||||
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
|
||||
|
||||
private final String dbName;
|
||||
private final String dbUserName;
|
||||
private final String dbPassword;
|
||||
private final String tblname;
|
||||
private final String path;
|
||||
private final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
|
||||
private final File dataFolder;
|
||||
private final File backupFolder;
|
||||
private final Settings settings;
|
||||
|
||||
/**
|
||||
* Constructor for PerformBackup.
|
||||
* Constructor.
|
||||
*
|
||||
* @param instance AuthMe
|
||||
* @param settings The plugin settings
|
||||
* @param dataFolder the data folder
|
||||
* @param settings the plugin settings
|
||||
*/
|
||||
public BackupService(AuthMe instance, Settings settings) {
|
||||
this.dataFolder = instance.getDataFolder();
|
||||
this.settings = settings;
|
||||
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
this.dbUserName = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
|
||||
this.dbPassword = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
|
||||
this.tblname = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||
|
||||
String dateString = DATE_FORMAT.format(new Date());
|
||||
this.path = String.join(File.separator,
|
||||
instance.getDataFolder().getPath(), "backups", "backup" + dateString);
|
||||
@Inject
|
||||
public BackupService(@DataFolder File dataFolder, Settings settings) {
|
||||
this.dataFolder = dataFolder;
|
||||
this.backupFolder = new File(dataFolder, "backups");
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform a backup with the given reason.
|
||||
* Performs a backup for the given reason.
|
||||
*
|
||||
* @param cause The cause of the backup.
|
||||
* @param cause backup reason
|
||||
*/
|
||||
public void doBackup(BackupCause cause) {
|
||||
doBackup(cause, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a backup for the given reason.
|
||||
*
|
||||
* @param cause backup reason
|
||||
* @param sender the command sender (nullable)
|
||||
*/
|
||||
public void doBackup(BackupCause cause, CommandSender sender) {
|
||||
if (!settings.getProperty(BackupSettings.ENABLED)) {
|
||||
// Print a warning if the backup was requested via command or by another plugin
|
||||
if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) {
|
||||
ConsoleLogger.warning("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
|
||||
+ cause.name());
|
||||
logAndSendWarning(sender,
|
||||
"Can't perform a backup: disabled in configuration. Cause of the backup: " + cause.name());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Check whether a backup should be made at the specified point in time
|
||||
if (BackupCause.START.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_START)
|
||||
|| BackupCause.STOP.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) {
|
||||
} else if (BackupCause.START == cause && !settings.getProperty(BackupSettings.ON_SERVER_START)
|
||||
|| BackupCause.STOP == cause && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) {
|
||||
// Don't perform backup on start or stop if so configured
|
||||
return;
|
||||
}
|
||||
|
||||
// Do backup and check return value!
|
||||
if (doBackup()) {
|
||||
ConsoleLogger.info("A backup has been performed successfully. Cause of the Backup: " + cause.name());
|
||||
logAndSendMessage(sender,
|
||||
"A backup has been performed successfully. Cause of the backup: " + cause.name());
|
||||
} else {
|
||||
ConsoleLogger.warning("Error while performing a backup! Cause of the Backup: " + cause.name());
|
||||
logAndSendWarning(sender, "Error while performing a backup! Cause of the backup: " + cause.name());
|
||||
}
|
||||
}
|
||||
|
||||
public boolean doBackup() {
|
||||
private boolean doBackup() {
|
||||
DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
|
||||
switch (dataSourceType) {
|
||||
case FILE:
|
||||
return fileBackup("auths.db");
|
||||
return performFileBackup("auths.db");
|
||||
case MYSQL:
|
||||
return mySqlBackup();
|
||||
return performMySqlBackup();
|
||||
case SQLITE:
|
||||
return fileBackup(dbName + ".db");
|
||||
String dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
return performFileBackup(dbName + ".db");
|
||||
default:
|
||||
ConsoleLogger.warning("Unknown data source type '" + dataSourceType + "' for backup");
|
||||
}
|
||||
@@ -97,17 +100,15 @@ public class BackupService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean mySqlBackup() {
|
||||
File dirBackup = new File(dataFolder + File.separator + "backups");
|
||||
private boolean performMySqlBackup() {
|
||||
FileUtils.createDirectory(backupFolder);
|
||||
File sqlBackupFile = constructBackupFile("sql");
|
||||
|
||||
if (!dirBackup.exists()) {
|
||||
dirBackup.mkdir();
|
||||
}
|
||||
String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH);
|
||||
boolean isUsingWindows = checkWindows(backupWindowsPath);
|
||||
boolean isUsingWindows = useWindowsCommand(backupWindowsPath);
|
||||
String backupCommand = isUsingWindows
|
||||
? backupWindowsPath + "\\bin\\mysqldump.exe" + buildMysqlDumpArguments()
|
||||
: "mysqldump" + buildMysqlDumpArguments();
|
||||
? backupWindowsPath + "\\bin\\mysqldump.exe" + buildMysqlDumpArguments(sqlBackupFile)
|
||||
: "mysqldump" + buildMysqlDumpArguments(sqlBackupFile);
|
||||
|
||||
try {
|
||||
Process runtimeProcess = Runtime.getRuntime().exec(backupCommand);
|
||||
@@ -124,14 +125,12 @@ public class BackupService {
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean fileBackup(String backend) {
|
||||
File dirBackup = new File(dataFolder + File.separator + "backups");
|
||||
|
||||
if (!dirBackup.exists())
|
||||
dirBackup.mkdir();
|
||||
private boolean performFileBackup(String filename) {
|
||||
FileUtils.createDirectory(backupFolder);
|
||||
File backupFile = constructBackupFile("db");
|
||||
|
||||
try {
|
||||
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
|
||||
copy(new File(dataFolder, filename), backupFile);
|
||||
return true;
|
||||
} catch (IOException ex) {
|
||||
ConsoleLogger.logException("Encountered an error during file backup:", ex);
|
||||
@@ -146,7 +145,7 @@ public class BackupService {
|
||||
* @param windowsPath The path to check
|
||||
* @return True if the path is correct, false if it is incorrect or the OS is not Windows
|
||||
*/
|
||||
private static boolean checkWindows(String windowsPath) {
|
||||
private static boolean useWindowsCommand(String windowsPath) {
|
||||
String isWin = System.getProperty("os.name").toLowerCase();
|
||||
if (isWin.contains("win")) {
|
||||
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
|
||||
@@ -162,28 +161,42 @@ public class BackupService {
|
||||
/**
|
||||
* Builds the command line arguments to pass along when running the {@code mysqldump} command.
|
||||
*
|
||||
* @param sqlBackupFile the file to back up to
|
||||
* @return the mysqldump command line arguments
|
||||
*/
|
||||
private String buildMysqlDumpArguments() {
|
||||
return " -u " + dbUserName + " -p" + dbPassword + " " + dbName
|
||||
+ " --tables " + tblname + " -r " + path + ".sql";
|
||||
private String buildMysqlDumpArguments(File sqlBackupFile) {
|
||||
String dbUsername = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
|
||||
String dbPassword = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
|
||||
String dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
|
||||
String tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
|
||||
|
||||
return " -u " + dbUsername + " -p" + dbPassword + " " + dbName
|
||||
+ " --tables " + tableName + " -r " + sqlBackupFile.getPath() + ".sql";
|
||||
}
|
||||
|
||||
private static void copy(String src, String dst) throws IOException {
|
||||
InputStream in = new FileInputStream(src);
|
||||
OutputStream out = new FileOutputStream(dst);
|
||||
/**
|
||||
* Constructs the file name to back up the data source to.
|
||||
*
|
||||
* @param fileExtension the file extension to use (e.g. sql)
|
||||
* @return the file to back up the data to
|
||||
*/
|
||||
private File constructBackupFile(String fileExtension) {
|
||||
String dateString = dateFormat.format(new Date());
|
||||
return new File(backupFolder, "backup" + dateString + "." + fileExtension);
|
||||
}
|
||||
|
||||
// Transfer bytes from in to out
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
private static void copy(File src, File dst) throws IOException {
|
||||
try (InputStream in = new FileInputStream(src);
|
||||
OutputStream out = new FileOutputStream(dst)) {
|
||||
// Transfer bytes from in to out
|
||||
byte[] buf = new byte[1024];
|
||||
int len;
|
||||
while ((len = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, len);
|
||||
}
|
||||
}
|
||||
in.close();
|
||||
out.close();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Possible backup causes.
|
||||
*/
|
||||
|
||||
@@ -45,7 +45,6 @@ public class SpawnLoader implements Reloadable {
|
||||
*/
|
||||
@Inject
|
||||
SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService) {
|
||||
// TODO ljacqu 20160312: Check if resource could be copied and handle the case if not
|
||||
File spawnFile = new File(pluginFolder, "spawn.yml");
|
||||
FileUtils.copyFileFromResource(spawnFile, "spawn.yml");
|
||||
this.authMeConfigurationFile = spawnFile;
|
||||
|
||||
@@ -8,19 +8,19 @@ import static ch.jalu.configme.properties.PropertyInitializer.newProperty;
|
||||
|
||||
public final class BackupSettings implements SettingsHolder {
|
||||
|
||||
@Comment("Enable or disable automatic backup")
|
||||
@Comment("General configuration for backups: if false, no backups are possible")
|
||||
public static final Property<Boolean> ENABLED =
|
||||
newProperty("BackupSystem.ActivateBackup", false);
|
||||
|
||||
@Comment("Set backup at every start of server")
|
||||
@Comment("Create backup at every start of server")
|
||||
public static final Property<Boolean> ON_SERVER_START =
|
||||
newProperty("BackupSystem.OnServerStart", false);
|
||||
|
||||
@Comment("Set backup at every stop of server")
|
||||
@Comment("Create backup at every stop of server")
|
||||
public static final Property<Boolean> ON_SERVER_STOP =
|
||||
newProperty("BackupSystem.OnServerStop", true);
|
||||
|
||||
@Comment("Windows only mysql installation Path")
|
||||
@Comment("Windows only: MySQL installation path")
|
||||
public static final Property<String> MYSQL_WINDOWS_PATH =
|
||||
newProperty("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
|
||||
|
||||
|
||||
@@ -194,7 +194,6 @@ class PurgeExecutor {
|
||||
}
|
||||
|
||||
// TODO: What is this method for? Is it correct?
|
||||
// TODO: Make it work with OfflinePlayers group data.
|
||||
synchronized void purgePermissions(Collection<OfflinePlayer> cleared) {
|
||||
if (!settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS)) {
|
||||
return;
|
||||
|
||||
@@ -30,7 +30,7 @@ public final class FileUtils {
|
||||
public static boolean copyFileFromResource(File destinationFile, String resourcePath) {
|
||||
if (destinationFile.exists()) {
|
||||
return true;
|
||||
} else if (!destinationFile.getParentFile().exists() && !destinationFile.getParentFile().mkdirs()) {
|
||||
} else if (!createDirectory(destinationFile.getParentFile())) {
|
||||
ConsoleLogger.warning("Cannot create parent directories for '" + destinationFile + "'");
|
||||
return false;
|
||||
}
|
||||
@@ -50,6 +50,20 @@ public final class FileUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the given directory.
|
||||
*
|
||||
* @param dir the directory to create
|
||||
* @return true upon success, false otherwise
|
||||
*/
|
||||
public static boolean createDirectory(File dir) {
|
||||
if (!dir.exists() && !dir.mkdirs()) {
|
||||
ConsoleLogger.warning("Could not create directory '" + dir + "'");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a JAR file as stream. Returns null if it doesn't exist.
|
||||
*
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package fr.xephi.authme.util;
|
||||
|
||||
import fr.xephi.authme.ConsoleLogger;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
|
||||
@@ -69,6 +70,22 @@ public final class Utils {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a warning to the given sender (null safe), and logs the warning to the console.
|
||||
* This method is aware that the command sender might be the console sender and avoids
|
||||
* displaying the message twice in this case.
|
||||
*
|
||||
* @param sender the sender to inform
|
||||
* @param message the warning to log and send
|
||||
*/
|
||||
public static void logAndSendWarning(CommandSender sender, String message) {
|
||||
ConsoleLogger.warning(message);
|
||||
// Make sure sender is not console user, which will see the message from ConsoleLogger already
|
||||
if (sender != null && !(sender instanceof ConsoleCommandSender)) {
|
||||
sender.sendMessage(ChatColor.RED + message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Null-safe way to check whether a collection is empty or not.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user