From 200af9c4c400755f2aabda9c309c8e8b04a073b1 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 19 Jan 2016 09:20:55 +0100 Subject: [PATCH 01/14] Move new configs outside of 'custom' package - Create properties package for storing the config properties - Move NewSetting class to main settings pkg --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../fr/xephi/authme/command/CommandService.java | 2 +- .../authme/ChangePasswordAdminCommand.java | 4 ++-- .../executable/authme/RegisterAdminCommand.java | 2 +- .../executable/captcha/CaptchaCommand.java | 2 +- .../changepassword/ChangePasswordCommand.java | 4 ++-- .../settings/{custom => }/NewSetting.java | 3 ++- .../{custom => properties}/BackupSettings.java | 2 +- .../ConverterSettings.java | 2 +- .../DatabaseSettings.java | 2 +- .../{custom => properties}/EmailSettings.java | 2 +- .../{custom => properties}/HooksSettings.java | 2 +- .../{custom => properties}/PluginSettings.java | 2 +- .../ProtectionSettings.java | 2 +- .../{custom => properties}/PurgeSettings.java | 2 +- .../RegistrationSettings.java | 2 +- .../RestrictionSettings.java | 2 +- .../SecuritySettings.java | 2 +- .../SettingsFieldRetriever.java | 17 ++++++++++++----- .../authme/command/CommandServiceTest.java | 4 ++-- .../executable/captcha/CaptchaCommandTest.java | 2 +- .../ChangePasswordCommandTest.java | 4 ++-- .../{custom => }/ConfigFileConsistencyTest.java | 4 +++- .../{custom => }/NewSettingIntegrationTest.java | 4 +++- .../settings/{custom => }/NewSettingTest.java | 4 +++- .../SettingsClassConsistencyTest.java | 4 ++-- .../TestConfiguration.java | 8 ++++++-- 27 files changed, 55 insertions(+), 37 deletions(-) rename src/main/java/fr/xephi/authme/settings/{custom => }/NewSetting.java (98%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/BackupSettings.java (95%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/ConverterSettings.java (96%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/DatabaseSettings.java (99%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/EmailSettings.java (98%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/HooksSettings.java (98%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/PluginSettings.java (98%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/ProtectionSettings.java (97%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/PurgeSettings.java (98%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/RegistrationSettings.java (99%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/RestrictionSettings.java (99%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/SecuritySettings.java (99%) rename src/main/java/fr/xephi/authme/settings/{custom => properties}/SettingsFieldRetriever.java (80%) rename src/test/java/fr/xephi/authme/settings/{custom => }/ConfigFileConsistencyTest.java (95%) rename src/test/java/fr/xephi/authme/settings/{custom => }/NewSettingIntegrationTest.java (97%) rename src/test/java/fr/xephi/authme/settings/{custom => }/NewSettingTest.java (96%) rename src/test/java/fr/xephi/authme/settings/{custom => properties}/SettingsClassConsistencyTest.java (98%) rename src/test/java/fr/xephi/authme/settings/{custom => properties}/TestConfiguration.java (91%) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 1b39b3440..936e95429 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -48,7 +48,7 @@ import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; -import fr.xephi.authme.settings.custom.NewSetting; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 8dd1da599..99d6bdb26 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -8,7 +8,7 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.settings.custom.NewSetting; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import org.bukkit.command.CommandSender; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java index a1b27f16f..cb6bddcf2 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ChangePasswordAdminCommand.java @@ -8,8 +8,8 @@ import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.custom.RestrictionSettings; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.CommandSender; import java.util.List; diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java index 107f8c7ae..7b9299526 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/RegisterAdminCommand.java @@ -7,7 +7,7 @@ import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.Bukkit; import org.bukkit.command.CommandSender; diff --git a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java index 79f963f0b..8c5a0764a 100644 --- a/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/captcha/CaptchaCommand.java @@ -6,7 +6,7 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.security.RandomString; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.Wrapper; import org.bukkit.entity.Player; diff --git a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java index a3b7f4451..d27ff2987 100644 --- a/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommand.java @@ -5,8 +5,8 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.PlayerCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.custom.RestrictionSettings; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.ChangePasswordTask; import fr.xephi.authme.util.Wrapper; import org.bukkit.entity.Player; diff --git a/src/main/java/fr/xephi/authme/settings/custom/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java similarity index 98% rename from src/main/java/fr/xephi/authme/settings/custom/NewSetting.java rename to src/main/java/fr/xephi/authme/settings/NewSetting.java index 6f9abdc44..34d16f348 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -1,8 +1,9 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings; import com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; diff --git a/src/main/java/fr/xephi/authme/settings/custom/BackupSettings.java b/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java similarity index 95% rename from src/main/java/fr/xephi/authme/settings/custom/BackupSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java index f2e78931b..32c439db2 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/BackupSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/BackupSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/ConverterSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java similarity index 96% rename from src/main/java/fr/xephi/authme/settings/custom/ConverterSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java index f32cf7483..9dc4ad60a 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/ConverterSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/ConverterSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/DatabaseSettings.java b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java similarity index 99% rename from src/main/java/fr/xephi/authme/settings/custom/DatabaseSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java index 84f0b7085..49ddc597b 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/DatabaseSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/DatabaseSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.settings.domain.Comment; diff --git a/src/main/java/fr/xephi/authme/settings/custom/EmailSettings.java b/src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java similarity index 98% rename from src/main/java/fr/xephi/authme/settings/custom/EmailSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java index 683143652..7b7ee3cef 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/EmailSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/EmailSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/HooksSettings.java b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java similarity index 98% rename from src/main/java/fr/xephi/authme/settings/custom/HooksSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java index af0458ac4..b20d28686 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/HooksSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/HooksSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/PluginSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java similarity index 98% rename from src/main/java/fr/xephi/authme/settings/custom/PluginSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java index e35076db2..6fea29fb0 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/PluginSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PluginSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/ProtectionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java similarity index 97% rename from src/main/java/fr/xephi/authme/settings/custom/ProtectionSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java index 2582c277f..f5a51215e 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/ProtectionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/ProtectionSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/PurgeSettings.java b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java similarity index 98% rename from src/main/java/fr/xephi/authme/settings/custom/PurgeSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java index 5fcc139d7..b4de9abfc 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/PurgeSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/PurgeSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/RegistrationSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java similarity index 99% rename from src/main/java/fr/xephi/authme/settings/custom/RegistrationSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java index 7e8301456..129e4ab97 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/RegistrationSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RegistrationSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/RestrictionSettings.java b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java similarity index 99% rename from src/main/java/fr/xephi/authme/settings/custom/RestrictionSettings.java rename to src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java index 32b68586d..a14285fdd 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/RestrictionSettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/RestrictionSettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; diff --git a/src/main/java/fr/xephi/authme/settings/custom/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java similarity index 99% rename from src/main/java/fr/xephi/authme/settings/custom/SecuritySettings.java rename to src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java index 94e33258c..955e35c11 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/SecuritySettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.settings.domain.Comment; diff --git a/src/main/java/fr/xephi/authme/settings/custom/SettingsFieldRetriever.java b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java similarity index 80% rename from src/main/java/fr/xephi/authme/settings/custom/SettingsFieldRetriever.java rename to src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java index 74b722e8f..cedd358ee 100644 --- a/src/main/java/fr/xephi/authme/settings/custom/SettingsFieldRetriever.java +++ b/src/main/java/fr/xephi/authme/settings/properties/SettingsFieldRetriever.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Comment; import fr.xephi.authme.settings.domain.Property; @@ -12,9 +12,10 @@ import java.util.Arrays; import java.util.List; /** - * Utility class responsible for the retrieval of all {@link Property} fields via reflections. + * Utility class responsible for retrieving all {@link Property} fields + * from {@link SettingsClass} implementations via reflection. */ -final class SettingsFieldRetriever { +public final class SettingsFieldRetriever { /** The classes to scan for properties. */ private static final List> CONFIGURATION_CLASSES = Arrays.asList( @@ -37,7 +38,7 @@ final class SettingsFieldRetriever { for (Class clazz : CONFIGURATION_CLASSES) { Field[] declaredFields = clazz.getDeclaredFields(); for (Field field : declaredFields) { - Property property = getFieldIfRelevant(field); + Property property = getPropertyField(field); if (property != null) { properties.put(property, getCommentsForField(field)); } @@ -53,7 +54,13 @@ final class SettingsFieldRetriever { return new String[0]; } - private static Property getFieldIfRelevant(Field field) { + /** + * Return the given field's value if it is a static {@link Property}. + * + * @param field The field's value to return + * @return The property the field defines, or null if not applicable + */ + private static Property getPropertyField(Field field) { field.setAccessible(true); if (field.isAccessible() && Property.class.equals(field.getType()) && Modifier.isStatic(field.getModifiers())) { try { diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index e3e67e3ed..034196986 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -8,8 +8,8 @@ import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.PasswordSecurity; -import fr.xephi.authme.settings.custom.NewSetting; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.settings.domain.Property; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; diff --git a/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java index c33b13ef3..b3b54a1c4 100644 --- a/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/captcha/CaptchaCommandTest.java @@ -5,7 +5,7 @@ import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; diff --git a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java index d00a4e37d..3936e5069 100644 --- a/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/changepassword/ChangePasswordCommandTest.java @@ -4,8 +4,8 @@ import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.custom.RestrictionSettings; -import fr.xephi.authme.settings.custom.SecuritySettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.task.ChangePasswordTask; import fr.xephi.authme.util.WrapperMock; import org.bukkit.Server; diff --git a/src/test/java/fr/xephi/authme/settings/custom/ConfigFileConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java similarity index 95% rename from src/test/java/fr/xephi/authme/settings/custom/ConfigFileConsistencyTest.java rename to src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java index d012a50a4..affb95ad8 100644 --- a/src/test/java/fr/xephi/authme/settings/custom/ConfigFileConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java @@ -1,7 +1,9 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings; import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.MemorySection; diff --git a/src/test/java/fr/xephi/authme/settings/custom/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java similarity index 97% rename from src/test/java/fr/xephi/authme/settings/custom/NewSettingIntegrationTest.java rename to src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 73b80b020..92a31cc12 100644 --- a/src/test/java/fr/xephi/authme/settings/custom/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -1,8 +1,10 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings; import com.google.common.collect.ImmutableMap; import fr.xephi.authme.ReflectionTestUtils; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.properties.TestConfiguration; import fr.xephi.authme.settings.propertymap.PropertyMap; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.BeforeClass; diff --git a/src/test/java/fr/xephi/authme/settings/custom/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java similarity index 96% rename from src/test/java/fr/xephi/authme/settings/custom/NewSettingTest.java rename to src/test/java/fr/xephi/authme/settings/NewSettingTest.java index 64e213aed..549be6f3d 100644 --- a/src/test/java/fr/xephi/authme/settings/custom/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -1,6 +1,8 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.properties.TestConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; diff --git a/src/test/java/fr/xephi/authme/settings/custom/SettingsClassConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java similarity index 98% rename from src/test/java/fr/xephi/authme/settings/custom/SettingsClassConsistencyTest.java rename to src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java index a6b67763a..075103345 100644 --- a/src/test/java/fr/xephi/authme/settings/custom/SettingsClassConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/settings/properties/SettingsClassConsistencyTest.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.settings.domain.Property; @@ -25,7 +25,7 @@ import static org.junit.Assert.fail; */ public class SettingsClassConsistencyTest { - private static final String SETTINGS_FOLDER = "src/main/java/fr/xephi/authme/settings/custom"; + private static final String SETTINGS_FOLDER = "src/main/java/fr/xephi/authme/settings/properties"; private static List> classes; @BeforeClass diff --git a/src/test/java/fr/xephi/authme/settings/custom/TestConfiguration.java b/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java similarity index 91% rename from src/test/java/fr/xephi/authme/settings/custom/TestConfiguration.java rename to src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java index 5f43262c7..449627f2e 100644 --- a/src/test/java/fr/xephi/authme/settings/custom/TestConfiguration.java +++ b/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java @@ -1,4 +1,4 @@ -package fr.xephi.authme.settings.custom; +package fr.xephi.authme.settings.properties; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.domain.PropertyType; @@ -11,7 +11,7 @@ import static fr.xephi.authme.settings.domain.Property.newProperty; /** * Sample properties for testing purposes. */ -class TestConfiguration implements SettingsClass { +public final class TestConfiguration implements SettingsClass { public static final Property DURATION_IN_SECONDS = newProperty("test.duration", 4); @@ -43,4 +43,8 @@ class TestConfiguration implements SettingsClass { public static final Property> COOL_OPTIONS = newProperty(PropertyType.STRING_LIST, "features.cool.options", "Sparks", "Sprinkles"); + + private TestConfiguration() { + } + } From 4012421d809e6e0fd643d42bbad1231d726cab18 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 19 Jan 2016 16:50:54 +0100 Subject: [PATCH 02/14] #450 Create migration service for new settings - Create service to check if new settings is up-to-date - Remove up-to-date checks from old Settings - Update tests --- .../fr/xephi/authme/settings/NewSetting.java | 16 +- .../fr/xephi/authme/settings/Settings.java | 232 ------------------ .../settings/SettingsMigrationService.java | 102 ++++++++ .../settings/ConfigFileConsistencyTest.java | 10 +- .../settings/NewSettingIntegrationTest.java | 3 +- .../xephi/authme/settings/NewSettingTest.java | 1 - 6 files changed, 111 insertions(+), 253 deletions(-) create mode 100644 src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 34d16f348..3679c9278 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -41,7 +41,9 @@ public class NewSetting { // be removed as we should check to rewrite the config.yml file only at one place // -------- // PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); - // if (!containsAllSettings(propertyMap)) { + // if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { + // ConsoleLogger.info("Merged new config options"); + // ConsoleLogger.info("Please check your config.yml file for new settings!"); // save(propertyMap); // } } @@ -58,7 +60,7 @@ public class NewSetting { this.configuration = configuration; this.file = file; - if (propertyMap != null && !containsAllSettings(propertyMap)) { + if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { save(propertyMap); } } @@ -135,16 +137,6 @@ public class NewSetting { } } - @VisibleForTesting - boolean containsAllSettings(PropertyMap propertyMap) { - for (Property property : propertyMap.keySet()) { - if (!property.isPresent(configuration)) { - return false; - } - } - return true; - } - private static String indent(int level) { // YAML uses indentation of 4 spaces StringBuilder sb = new StringBuilder(level * 4); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 9f4285b64..f6ed7e2e8 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -127,9 +127,6 @@ public final class Settings { plugin.saveDefaultConfig(); } configFile.load(SETTINGS_FILE); - if (exist) { - instance.mergeConfig(); - } loadVariables(); if (exist) { instance.saveDefaults(); @@ -510,235 +507,6 @@ public final class Settings { return correct; } - public void mergeConfig() { - boolean changes = false; - if (contains("Xenoforo.predefinedSalt")) { - set("Xenoforo.predefinedSalt", null); - changes = true; - } - if (!contains("Protection.enableProtection")) { - set("Protection.enableProtection", false); - changes = true; - } - if (!contains("settings.restrictions.removeSpeed")) { - set("settings.restrictions.removeSpeed", true); - changes = true; - } - if (!contains("Protection.countries")) { - countries = new ArrayList<>(); - countries.add("US"); - countries.add("GB"); - set("Protection.countries", countries); - changes = true; - } - if (!contains("Protection.enableAntiBot")) { - set("Protection.enableAntiBot", false); - changes = true; - } - if (!contains("Protection.antiBotSensibility")) { - set("Protection.antiBotSensibility", 5); - changes = true; - } - if (!contains("Protection.antiBotDuration")) { - set("Protection.antiBotDuration", 10); - changes = true; - } - if (!contains("settings.forceCommands")) { - set("settings.forceCommands", new ArrayList()); - changes = true; - } - if (!contains("settings.forceCommandsAsConsole")) { - set("settings.forceCommandsAsConsole", new ArrayList()); - changes = true; - } - if (!contains("Email.recallPlayers")) { - set("Email.recallPlayers", false); - changes = true; - } - if (!contains("Email.delayRecall")) { - set("Email.delayRecall", 5); - changes = true; - } - if (!contains("settings.useWelcomeMessage")) { - set("settings.useWelcomeMessage", true); - changes = true; - } - if (!contains("settings.restrictions.enablePasswordConfirmation")) { - set("settings.restrictions.enablePasswordConfirmation", true); - changes = true; - } - if (contains("settings.restrictions.enablePasswordVerifier")) { - set("settings.restrictions.enablePasswordVerifier", null); - changes = true; - } - if (!contains("settings.security.unsafePasswords")) { - List str = new ArrayList<>(); - str.add("123456"); - str.add("password"); - set("settings.security.unsafePasswords", str); - changes = true; - } - if (!contains("Protection.countriesBlacklist")) { - countriesBlacklist = new ArrayList<>(); - countriesBlacklist.add("A1"); - set("Protection.countriesBlacklist", countriesBlacklist); - changes = true; - } - if (!contains("settings.helpHeader")) { - set("settings.helpHeader", "AuthMeReloaded"); - changes = true; - } - if (!contains("settings.broadcastWelcomeMessage")) { - set("settings.broadcastWelcomeMessage", false); - changes = true; - } - if (!contains("settings.registration.forceKickAfterRegister")) { - set("settings.registration.forceKickAfterRegister", false); - changes = true; - } - if (!contains("settings.registration.forceLoginAfterRegister")) { - set("settings.registration.forceLoginAfterRegister", false); - changes = true; - } - if (!contains("DataSource.mySQLColumnLogged")) { - set("DataSource.mySQLColumnLogged", "isLogged"); - changes = true; - } - if (!contains("settings.restrictions.spawnPriority")) { - set("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default"); - changes = true; - } - if (!contains("settings.restrictions.maxLoginPerIp")) { - set("settings.restrictions.maxLoginPerIp", 0); - changes = true; - } - if (!contains("settings.restrictions.maxJoinPerIp")) { - set("settings.restrictions.maxJoinPerIp", 0); - changes = true; - } - if (!contains("VeryGames.enableIpCheck")) { - set("VeryGames.enableIpCheck", false); - changes = true; - } - if (configFile.getString("settings.restrictions.allowedNicknameCharacters").equals("[a-zA-Z0-9_?]*")) { - set("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*"); - changes = true; - } - if (contains("settings.delayJoinMessage")) { - set("settings.delayJoinMessage", null); - changes = true; - } - if (!contains("settings.delayJoinLeaveMessages")) { - set("settings.delayJoinLeaveMessages", true); - changes = true; - } - if (!contains("settings.restrictions.noTeleport")) { - set("settings.restrictions.noTeleport", false); - changes = true; - } - if (contains("Converter.Rakamak.newPasswordHash")) { - set("Converter.Rakamak.newPasswordHash", null); - changes = true; - } - if (!contains("Converter.CrazyLogin.fileName")) { - set("Converter.CrazyLogin.fileName", "accounts.db"); - changes = true; - } - if (!contains("settings.restrictions.allowedPasswordCharacters")) { - set("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*"); - changes = true; - } - if (!contains("settings.applyBlindEffect")) { - set("settings.applyBlindEffect", false); - changes = true; - } - if (!contains("Email.emailBlacklisted")) { - set("Email.emailBlacklisted", new ArrayList()); - changes = true; - } - if (contains("Performances")) { - set("Performances", null); - changes = true; - } - if (contains("Passpartu.enablePasspartu")) { - set("Passpartu.enablePasspartu", null); - changes = true; - } - if (contains("Passpartu")) { - set("Passpartu", null); - changes = true; - } - if (!contains("Email.emailWhitelisted")) { - set("Email.emailWhitelisted", new ArrayList()); - changes = true; - } - if (!contains("settings.forceRegisterCommands")) { - set("settings.forceRegisterCommands", new ArrayList()); - changes = true; - } - if (!contains("settings.forceRegisterCommandsAsConsole")) { - set("settings.forceRegisterCommandsAsConsole", new ArrayList()); - changes = true; - } - if (!contains("Hooks.customAttributes")) { - set("Hooks.customAttributes", false); - changes = true; - } - if (!contains("Purge.removePermissions")) { - set("Purge.removePermissions", false); - changes = true; - } - if (contains("Hooks.notifications")) { - set("Hooks.notifications", null); - changes = true; - } - if (contains("Hooks.chestshop")) { - set("Hooks.chestshop", null); - changes = true; - } - if (contains("Hooks.legacyChestshop")) { - set("Hooks.legacyChestshop", null); - changes = true; - } - if (!contains("Email.generateImage")) { - set("Email.generateImage", false); - changes = true; - } - if (!contains("DataSource.mySQLRealName")) { - set("DataSource.mySQLRealName", "realname"); - changes = true; - } - - if (!contains("settings.preventOtherCase")) { - set("settings.preventOtherCase", false); - changes = true; - } - - if (contains("Email.mailText")) { - set("Email.mailText", null); - ConsoleLogger.showError("Remove Email.mailText from config, we now use the email.html file"); - } - - if (!contains("Security.stop.kickPlayersBeforeStopping")) { - set("Security.stop.kickPlayersBeforeStopping", true); - changes = true; - } - - if (!contains("Email.emailOauth2Token")) - set("Email.emailOauth2Token", ""); - - if (!contains("Hooks.sendPlayerTo")) { - set("Hooks.sendPlayerTo", ""); - changes = true; - } - - if (changes) { - save(); - plugin.getLogger().warning("Merged new Config Options - I'm not an error, please don't report me"); - plugin.getLogger().warning("Please check your config.yml file for new configs!"); - } - } - /** * @param path * diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java new file mode 100644 index 000000000..0691609be --- /dev/null +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -0,0 +1,102 @@ +package fr.xephi.authme.settings; + +import com.google.common.annotations.VisibleForTesting; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.propertymap.PropertyMap; +import fr.xephi.authme.util.StringUtils; +import fr.xephi.authme.util.Wrapper; +import org.bukkit.configuration.file.FileConfiguration; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS; + +/** + * Service for verifying that the configuration is up-to-date. + */ +public final class SettingsMigrationService { + + private SettingsMigrationService() { + } + + /** + * Checks the config file and does any necessary migrations. + * + * @param configuration The file configuration to check and migrate + * @param propertyMap The property map of all existing properties + * @return True if there is a change and the config must be saved, false if the config is up-to-date + */ + public static boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap) { + return performMigrations(configuration) || hasDeprecatedProperties(configuration) + || !containsAllSettings(configuration, propertyMap); + } + + private static boolean performMigrations(FileConfiguration configuration) { + boolean changes = false; + if ("[a-zA-Z0-9_?]*".equals(configuration.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) { + configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*"); + changes = true; + } + // TODO #450: Don't get the data folder statically + Wrapper w = Wrapper.getInstance(); + changes = changes || performMailTextToFileMigration(configuration, w.getDataFolder()); + + return changes; + } + + @VisibleForTesting + static boolean containsAllSettings(FileConfiguration configuration, PropertyMap propertyMap) { + for (Property property : propertyMap.keySet()) { + if (!property.isPresent(configuration)) { + return false; + } + } + return true; + } + + private static boolean hasDeprecatedProperties(FileConfiguration configuration) { + String[] deprecatedProperties = { + "Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications", + "Passpartu", "Performances", "settings.delayJoinMessage", "settings.restrictions.enablePasswordVerifier", + "Xenoforo.predefinedSalt"}; + for (String deprecatedPath : deprecatedProperties) { + if (configuration.contains(deprecatedPath)) { + return true; + } + } + return false; + } + + // -------- + // Specific migrations + // -------- + + /** + * Check if {@code Email.mailText} is present and move it to the Email.html file if it doesn't exist yet. + * + * @param configuration The file configuration to verify + * @param dataFolder The plugin data folder + * @return True if a migration has been completed, false otherwise + */ + private static boolean performMailTextToFileMigration(FileConfiguration configuration, File dataFolder) { + final String oldSettingPath = "Email.mailText"; + if (!configuration.contains(oldSettingPath)) { + return false; + } + + final File emailFile = new File(dataFolder, "email.html"); + if (!emailFile.exists()) { + try (FileWriter fw = new FileWriter(emailFile)) { + fw.write(configuration.getString("Email.mailText")); + } catch (IOException e) { + ConsoleLogger.showError("Could not create email.html configuration file: " + + StringUtils.formatException(e)); + } + } + return true; + } + +} diff --git a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java index affb95ad8..755dcc461 100644 --- a/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java +++ b/src/test/java/fr/xephi/authme/settings/ConfigFileConsistencyTest.java @@ -1,7 +1,5 @@ package fr.xephi.authme.settings; -import fr.xephi.authme.ReflectionTestUtils; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; @@ -36,16 +34,14 @@ public class ConfigFileConsistencyTest { // given URL url = this.getClass().getResource(CONFIG_FILE); File configFile = new File(url.getFile()); - NewSetting settings = new NewSetting(YamlConfiguration.loadConfiguration(configFile), new File("bogus"), null); + FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile); // when - boolean result = settings.containsAllSettings(SettingsFieldRetriever.getAllPropertyFields()); + boolean result = SettingsMigrationService.containsAllSettings( + configuration, SettingsFieldRetriever.getAllPropertyFields()); // then if (!result) { - FileConfiguration configuration = - (FileConfiguration) ReflectionTestUtils.getFieldValue(NewSetting.class, settings, "configuration"); - Set knownProperties = getAllKnownPropertyPaths(); List missingProperties = new ArrayList<>(); for (String path : knownProperties) { diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 92a31cc12..491d11f68 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -2,10 +2,10 @@ package fr.xephi.authme.settings; import com.google.common.collect.ImmutableMap; import fr.xephi.authme.ReflectionTestUtils; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; import fr.xephi.authme.settings.propertymap.PropertyMap; +import fr.xephi.authme.util.WrapperMock; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.BeforeClass; import org.junit.Test; @@ -35,6 +35,7 @@ public class NewSettingIntegrationTest { @BeforeClass public static void generatePropertyMap() { + WrapperMock.createInstance(); propertyMap = new PropertyMap(); for (Field field : TestConfiguration.class.getDeclaredFields()) { Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName()); diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java index 549be6f3d..84941496e 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.settings; -import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; import org.bukkit.configuration.file.YamlConfiguration; From ec87c662e13d4be231e7e832c6941886da33c53f Mon Sep 17 00:00:00 2001 From: ljacqu Date: Tue, 26 Jan 2016 13:41:00 +0100 Subject: [PATCH 03/14] #450 Use SnakeYAML for writing properties --- .../fr/xephi/authme/settings/NewSetting.java | 67 +++++++++++------ .../settings/domain/EnumPropertyType.java | 15 ++-- .../authme/settings/domain/Property.java | 65 ++++++++++++---- .../authme/settings/domain/PropertyType.java | 75 +++++-------------- 4 files changed, 122 insertions(+), 100 deletions(-) diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 3679c9278..c48f1c469 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -8,6 +8,8 @@ import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.file.FileConfiguration; +import org.yaml.snakeyaml.DumperOptions; +import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.FileWriter; @@ -36,16 +38,12 @@ public class NewSetting { this.configuration = configuration; this.file = file; - // TODO ljacqu 20160109: Ensure that save() works as desired (i.e. that it always produces valid YAML) - // and then uncomment the lines below. Once this is uncommented, the checks in the old Settings.java should - // be removed as we should check to rewrite the config.yml file only at one place - // -------- - // PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); - // if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { - // ConsoleLogger.info("Merged new config options"); - // ConsoleLogger.info("Please check your config.yml file for new settings!"); - // save(propertyMap); - // } + PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); + if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { + ConsoleLogger.info("Merged new config options"); + ConsoleLogger.info("Please check your config.yml file for new settings!"); + save(propertyMap); + } } /** @@ -76,14 +74,18 @@ public class NewSetting { return property.getFromFile(configuration); } - public void save() { - save(SettingsFieldRetriever.getAllPropertyFields()); - } - public void save(PropertyMap propertyMap) { try (FileWriter writer = new FileWriter(file)) { writer.write(""); + DumperOptions simpleOptions = new DumperOptions(); + simpleOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml simpleYaml = new Yaml(simpleOptions); + DumperOptions singleQuoteOptions = new DumperOptions(); + singleQuoteOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); + singleQuoteOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + Yaml singleQuoteYaml = new Yaml(singleQuoteOptions); + // Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username" List currentPath = new ArrayList<>(); for (Map.Entry, String[]> entry : propertyMap.entrySet()) { @@ -118,14 +120,8 @@ public class NewSetting { writer.append("\n") .append(indent(indentationLevel)) .append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0)) - .append(": "); - - List yamlLines = property.formatValueAsYaml(configuration); - String delim = ""; - for (String yamlLine : yamlLines) { - writer.append(delim).append(yamlLine); - delim = "\n" + indent(indentationLevel); - } + .append(": ") + .append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml)); currentPath = propertyPath.subList(0, propertyPath.size() - 1); } @@ -137,6 +133,33 @@ public class NewSetting { } } + private String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) { + T value = property.getFromFile(configuration); + String representation = property.hasSingleQuotes() + ? singleQuoteYaml.dump(value) + : simpleYaml.dump(value); + + // If the property is a non-empty list we need to append a new line because it will be + // something like the following, which requires a new line: + // - 'item 1' + // - 'second item in list' + if (property.isList() && !((List) value).isEmpty()) { + representation = "\n" + representation; + } + + return join("\n" + indent(indent), representation.split("\\n")); + } + + private static String join(String delimiter, String[] items) { + StringBuilder sb = new StringBuilder(); + String delim = ""; + for (String item : items) { + sb.append(delim).append(item); + delim = delimiter; + } + return sb.toString(); + } + private static String indent(int level) { // YAML uses indentation of 4 spaces StringBuilder sb = new StringBuilder(level * 4); diff --git a/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java b/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java index ed184bb7d..c71739a5f 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java +++ b/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java @@ -2,12 +2,9 @@ package fr.xephi.authme.settings.domain; import org.bukkit.configuration.file.FileConfiguration; -import java.util.List; - -import static java.util.Arrays.asList; - /** * Enum property type. + * * @param The enum class */ class EnumPropertyType> extends PropertyType { @@ -28,17 +25,17 @@ class EnumPropertyType> extends PropertyType { return mappedValue != null ? mappedValue : property.getDefaultValue(); } - @Override - protected List asYaml(E value) { - return asList("'" + value + "'"); - } - @Override public boolean contains(Property property, FileConfiguration configuration) { return super.contains(property, configuration) && mapToEnum(configuration.getString(property.getPath())) != null; } + @Override + public boolean hasSingleQuotes() { + return true; + } + private E mapToEnum(String value) { for (E entry : clazz.getEnumConstants()) { if (entry.name().equalsIgnoreCase(value)) { diff --git a/src/main/java/fr/xephi/authme/settings/domain/Property.java b/src/main/java/fr/xephi/authme/settings/domain/Property.java index 6b15b5d3b..a67c6a492 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/Property.java +++ b/src/main/java/fr/xephi/authme/settings/domain/Property.java @@ -7,7 +7,7 @@ import java.util.List; import java.util.Objects; /** - * Properties (i.e. a setting that is read from the config.yml file). + * Property class, representing a setting that is read from the config.yml file. */ public class Property { @@ -22,15 +22,43 @@ public class Property { this.defaultValue = defaultValue; } + /** + * Create a new property. See also {@link #newProperty(PropertyType, String, Object[])} for lists and + * {@link #newProperty(Class, String, Enum)}. + * + * @param type The property type + * @param path The property's path + * @param defaultValue The default value + * @param The type of the property + * @return The created property + */ public static Property newProperty(PropertyType type, String path, T defaultValue) { return new Property<>(type, path, defaultValue); } + /** + * Create a new list property. + * + * @param type The list type of the property + * @param path The property's path + * @param defaultValues The default value's items + * @param The list type + * @return The created list property + */ @SafeVarargs public static Property> newProperty(PropertyType> type, String path, U... defaultValues) { return new Property<>(type, path, Arrays.asList(defaultValues)); } + /** + * Create a new enum property. + * + * @param clazz The enum class + * @param path The property's path + * @param defaultValue The default value + * @param The enum type + * @return The created enum property + */ public static > Property newProperty(Class clazz, String path, E defaultValue) { return new Property<>(new EnumPropertyType<>(clazz), path, defaultValue); } @@ -53,9 +81,8 @@ public class Property { // ----- // Hooks to the PropertyType methods // ----- - /** - * Get the property value from the given configuration. + * Get the property value from the given configuration – guaranteed to never return null. * * @param configuration The configuration to read the value from * @return The value, or default if not present @@ -64,16 +91,6 @@ public class Property { return type.getFromFile(this, configuration); } - /** - * Format the property value as YAML. - * - * @param configuration The configuration to read the value from - * @return The property value as YAML - */ - public List formatValueAsYaml(FileConfiguration configuration) { - return type.asYaml(this, configuration); - } - /** * Return whether or not the given configuration file contains the property. * @@ -84,10 +101,30 @@ public class Property { return type.contains(this, configuration); } + /** + * Return whether the property should be represented wrapped in single quotes in YAML. + * The YAML format allows both using single quotes and not for all types but for certain + * types one representation makes more sense. Typically we wrap string-like types in + * single quotes and all other ones not. + * + * @return True if single quotes should be used, false otherwise + */ + public boolean hasSingleQuotes() { + return type.hasSingleQuotes(); + } + + /** + * Return whether the property has a list type. + * + * @return True if the property type is a list, false otherwise + */ + public boolean isList() { + return type.isList(); + } + // ----- // Trivial getters // ----- - /** * Return the default value of the property. * diff --git a/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java b/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java index dc1975bba..4be934150 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java +++ b/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java @@ -2,11 +2,8 @@ package fr.xephi.authme.settings.domain; import org.bukkit.configuration.file.FileConfiguration; -import java.util.ArrayList; import java.util.List; -import static java.util.Arrays.asList; - /** * Handles a certain property type and provides type-specific functionality. * @@ -30,17 +27,6 @@ public abstract class PropertyType { */ public abstract T getFromFile(Property property, FileConfiguration configuration); - /** - * Return the property's value (or its default) as YAML. - * - * @param property The property to transform - * @param configuration The YAML configuration to read from - * @return The read value or its default in YAML format - */ - public List asYaml(Property property, FileConfiguration configuration) { - return asYaml(getFromFile(property, configuration)); - } - /** * Return whether the property is present in the given configuration. * @@ -53,12 +39,17 @@ public abstract class PropertyType { } /** - * Transform the given value to YAML. + * Return whether the property type should be wrapped in single quotes in YAML. * - * @param value The value to transform - * @return The value as YAML + * @return True if single quotes should be used, false if not */ - protected abstract List asYaml(T value); + public boolean hasSingleQuotes() { + return false; + } + + public boolean isList() { + return false; + } /** @@ -69,11 +60,6 @@ public abstract class PropertyType { public Boolean getFromFile(Property property, FileConfiguration configuration) { return configuration.getBoolean(property.getPath(), property.getDefaultValue()); } - - @Override - protected List asYaml(Boolean value) { - return asList(value ? "true" : "false"); - } } /** @@ -84,11 +70,6 @@ public abstract class PropertyType { public Double getFromFile(Property property, FileConfiguration configuration) { return configuration.getDouble(property.getPath(), property.getDefaultValue()); } - - @Override - protected List asYaml(Double value) { - return asList(String.valueOf(value)); - } } /** @@ -99,11 +80,6 @@ public abstract class PropertyType { public Integer getFromFile(Property property, FileConfiguration configuration) { return configuration.getInt(property.getPath(), property.getDefaultValue()); } - - @Override - protected List asYaml(Integer value) { - return asList(String.valueOf(value)); - } } /** @@ -114,15 +90,9 @@ public abstract class PropertyType { public String getFromFile(Property property, FileConfiguration configuration) { return configuration.getString(property.getPath(), property.getDefaultValue()); } - @Override - protected List asYaml(String value) { - return asList(toYamlLiteral(value)); - } - - public static String toYamlLiteral(String str) { - // TODO: Need to handle new lines properly - return "'" + str.replace("'", "''") + "'"; + public boolean hasSingleQuotes() { + return true; } } @@ -139,23 +109,18 @@ public abstract class PropertyType { } @Override - protected List asYaml(List value) { - if (value.isEmpty()) { - return asList("[]"); - } - - List resultLines = new ArrayList<>(); - resultLines.add(""); // add - for (String entry : value) { - // TODO: StringProperty#toYamlLiteral will return List... - resultLines.add(" - " + StringProperty.toYamlLiteral(entry)); - } - return resultLines; + public boolean contains(Property> property, FileConfiguration configuration) { + return configuration.contains(property.getPath()) && configuration.isList(property.getPath()); } @Override - public boolean contains(Property> property, FileConfiguration configuration) { - return configuration.contains(property.getPath()) && configuration.isList(property.getPath()); + public boolean hasSingleQuotes() { + return true; + } + + @Override + public boolean isList() { + return true; } } From c626521dc8c004dbcdd95ec519f5375b3afd7e69 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 27 Jan 2016 21:32:29 +0100 Subject: [PATCH 04/14] #473 Add logConsole setting - Add missing logConsole setting - Set true as default value, as suggested by games647 --- .../fr/xephi/authme/settings/properties/SecuritySettings.java | 4 ++++ src/main/resources/config.yml | 2 ++ 2 files changed, 6 insertions(+) diff --git a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java index 955e35c11..6a2ace715 100644 --- a/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java +++ b/src/main/java/fr/xephi/authme/settings/properties/SecuritySettings.java @@ -30,6 +30,10 @@ public class SecuritySettings implements SettingsClass { public static final Property REMOVE_PASSWORD_FROM_CONSOLE = newProperty("Security.console.removePassword", true); + @Comment("Copy AuthMe log output in a separate file as well?") + public static final Property USE_LOGGING = + newProperty("Security.console.logConsole", true); + @Comment("Player need to put a captcha when he fails too lot the password") public static final Property USE_CAPTCHA = newProperty("Security.captcha.useCaptcha", false); diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index d2e0a9e74..0bc812029 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -305,6 +305,8 @@ Security: noConsoleSpam: false # Replace passwords in the console when player type a command like /login removePassword: true + # Copy AuthMe log output in a separate file as well? + logConsole: true captcha: # Player need to put a captcha when he fails too lot the password useCaptcha: false From dedb3fce26e561a0c51602a0087adb26b91888cc Mon Sep 17 00:00:00 2001 From: ljacqu Date: Thu, 28 Jan 2016 10:38:44 +0100 Subject: [PATCH 05/14] #450 Add integration test for potentially difficult values - Ensure that edge cases such as backslashes, apostrophes and new lines are handled properly by the YAML writer & reader --- .../fr/xephi/authme/settings/NewSetting.java | 22 +++-- .../settings/NewSettingIntegrationTest.java | 96 +++++++++++++++---- .../resources/config-difficult-values.yml | 29 ++++++ 3 files changed, 122 insertions(+), 25 deletions(-) create mode 100644 src/test/resources/config-difficult-values.yml diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index c48f1c469..8aa46b84f 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -76,16 +76,10 @@ public class NewSetting { public void save(PropertyMap propertyMap) { try (FileWriter writer = new FileWriter(file)) { + Yaml simpleYaml = newYaml(false); + Yaml singleQuoteYaml = newYaml(true); + writer.write(""); - - DumperOptions simpleOptions = new DumperOptions(); - simpleOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - Yaml simpleYaml = new Yaml(simpleOptions); - DumperOptions singleQuoteOptions = new DumperOptions(); - singleQuoteOptions.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); - singleQuoteOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); - Yaml singleQuoteYaml = new Yaml(singleQuoteOptions); - // Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username" List currentPath = new ArrayList<>(); for (Map.Entry, String[]> entry : propertyMap.entrySet()) { @@ -150,6 +144,16 @@ public class NewSetting { return join("\n" + indent(indent), representation.split("\\n")); } + private static Yaml newYaml(boolean useSingleQuotes) { + DumperOptions options = new DumperOptions(); + options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); + options.setAllowUnicode(true); + if (useSingleQuotes) { + options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED); + } + return new Yaml(options); + } + private static String join(String delimiter, String[] items) { StringBuilder sb = new StringBuilder(); String delim = ""; diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 491d11f68..41b2cf2bd 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -7,7 +7,6 @@ import fr.xephi.authme.settings.properties.TestConfiguration; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.WrapperMock; import org.bukkit.configuration.file.YamlConfiguration; -import org.junit.BeforeClass; import org.junit.Test; import java.io.File; @@ -15,8 +14,10 @@ import java.lang.reflect.Field; import java.net.URL; import java.util.Arrays; import java.util.Collections; +import java.util.List; import java.util.Map; +import static fr.xephi.authme.settings.domain.Property.newProperty; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertThat; import static org.junit.Assume.assumeThat; @@ -30,22 +31,10 @@ public class NewSettingIntegrationTest { private static final String COMPLETE_FILE = "config-sample-values.yml"; /** File name of the sample config missing certain {@link TestConfiguration} values. */ private static final String INCOMPLETE_FILE = "config-incomplete-sample.yml"; + /** File name for testing difficult values. */ + private static final String DIFFICULT_FILE = "config-difficult-values.yml"; - private static PropertyMap propertyMap; - - @BeforeClass - public static void generatePropertyMap() { - WrapperMock.createInstance(); - propertyMap = new PropertyMap(); - for (Field field : TestConfiguration.class.getDeclaredFields()) { - Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName()); - if (fieldValue instanceof Property) { - Property property = (Property) fieldValue; - String[] comments = new String[]{"Comment for '" + property.getPath() + "'"}; - propertyMap.put(property, comments); - } - } - } + private static PropertyMap propertyMap = generatePropertyMap(); @Test public void shouldLoadAndReadAllProperties() { @@ -107,6 +96,62 @@ public class NewSettingIntegrationTest { } } + /** Verify that "difficult cases" such as apostrophes in strings etc. are handled properly. */ + @Test + public void shouldProperlyExportAnyValues() { + // given + File file = getConfigFile(DIFFICULT_FILE); + YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file); + assumeThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(false)); + + // Additional string properties + List> additionalProperties = Arrays.asList( + newProperty("more.string1", "it's a text with some \\'apostrophes'"), + newProperty("more.string2", "\tthis one\nhas some\nnew '' lines-test") + ); + PropertyMap propertyMap = generatePropertyMap(); + for (Property property : additionalProperties) { + propertyMap.put(property, new String[0]); + } + + // when + new NewSetting(configuration, file, propertyMap); + // reload the file as settings should hav been rewritten + configuration = YamlConfiguration.loadConfiguration(file); + + // then + // assert that we won't rewrite the settings again! One rewrite should produce a valid, complete configuration + File unusedFile = new File("config-difficult-values.unused.yml"); + NewSetting settings = new NewSetting(configuration, unusedFile, propertyMap); + assertThat(unusedFile.exists(), equalTo(false)); + assertThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(true)); + + Map, Object> expectedValues = ImmutableMap., Object>builder() + .put(TestConfiguration.DURATION_IN_SECONDS, 20) + .put(TestConfiguration.SYSTEM_NAME, "A 'test' name") + .put(TestConfiguration.RATIO_LIMIT, -41.8) + .put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia\\", "\tBurundi'", "Colombia?\n''")) + .put(TestConfiguration.VERSION_NUMBER, -1337) + .put(TestConfiguration.SKIP_BORING_FEATURES, false) + .put(TestConfiguration.BORING_COLORS, Arrays.asList("it's a difficult string!", "gray\nwith new lines\n")) + .put(TestConfiguration.DUST_LEVEL, 0.2) + .put(TestConfiguration.USE_COOL_FEATURES, true) + .put(TestConfiguration.COOL_OPTIONS, Collections.EMPTY_LIST) + .put(additionalProperties.get(0), additionalProperties.get(0).getDefaultValue()) + .put(additionalProperties.get(1), additionalProperties.get(1).getDefaultValue()) + .build(); + for (Map.Entry, Object> entry : expectedValues.entrySet()) { + assertThat("Property '" + entry.getKey().getPath() + "' has expected value" + + entry.getValue() + " but found " + settings.getProperty(entry.getKey()), + settings.getProperty(entry.getKey()), equalTo(entry.getValue())); + } + } + + /** + * Return a {@link File} instance to an existing file in the target/test-classes folder. + * + * @return The generated File + */ private File getConfigFile(String file) { URL url = getClass().getClassLoader().getResource(file); if (url == null) { @@ -115,4 +160,23 @@ public class NewSettingIntegrationTest { return new File(url.getFile()); } + /** + * Generate a property map with all properties in {@link TestConfiguration}. + * + * @return The generated property map + */ + private static PropertyMap generatePropertyMap() { + WrapperMock.createInstance(); + PropertyMap propertyMap = new PropertyMap(); + for (Field field : TestConfiguration.class.getDeclaredFields()) { + Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName()); + if (fieldValue instanceof Property) { + Property property = (Property) fieldValue; + String[] comments = new String[]{"Comment for '" + property.getPath() + "'"}; + propertyMap.put(property, comments); + } + } + return propertyMap; + } + } diff --git a/src/test/resources/config-difficult-values.yml b/src/test/resources/config-difficult-values.yml new file mode 100644 index 000000000..157971bc5 --- /dev/null +++ b/src/test/resources/config-difficult-values.yml @@ -0,0 +1,29 @@ +# Test config file with some "difficult" values + +test: + duration: 20.102 + systemName: 'A ''test'' name' +sample: + ratio: + limit: -41.8 + fields: + - Australia\ + - ' Burundi''' + - 'Colombia? + + ''''' + # The last element above represents "Colombia?\n''" +version: -1337 +features: + boring: + # YAML allows both "yes"/"no" and "true"/"false" for expressing booleans + skip: no + colors: + - 'it''s a difficult string!' + - | + gray + with new lines + # dustLevel: 0.81 <-- missing property triggering rewrite + cool: + enabled: yes + options: [] From 724296e02bb88e73a840fc4e5e7c888bea1cfc86 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 30 Jan 2016 13:19:05 +0100 Subject: [PATCH 06/14] #449 Migrate some properties to new settings - Use new settings class for retrieving help header & backup configs - Delete migrated configs from old settings --- src/main/java/fr/xephi/authme/AuthMe.java | 31 ++- .../java/fr/xephi/authme/PerformBackup.java | 188 ++++++++---------- .../executable/authme/VersionCommand.java | 6 +- .../authme/command/help/HelpProvider.java | 7 +- .../fr/xephi/authme/settings/Settings.java | 10 +- .../fr/xephi/authme/util/CollectionUtils.java | 9 +- .../authme/command/help/HelpProviderTest.java | 13 +- 7 files changed, 118 insertions(+), 146 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 936e95429..e38ece18f 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -45,10 +45,12 @@ import fr.xephi.authme.process.Management; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; -import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; @@ -81,6 +83,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; + /** * The AuthMe main class. */ @@ -279,7 +283,7 @@ public class AuthMe extends JavaPlugin { // End of Hooks // Do a backup on start - new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.START); + new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.START); // Setup the inventory backup @@ -422,7 +426,7 @@ public class AuthMe extends JavaPlugin { private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages, PasswordSecurity passwordSecurity, NewSetting settings) { - HelpProvider helpProvider = new HelpProvider(permissionsManager); + HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER)); Set baseCommands = CommandInitializer.buildCommands(); CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager); CommandService commandService = new CommandService( @@ -530,7 +534,7 @@ public class AuthMe extends JavaPlugin { } // Do backup on stop if enabled - new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.STOP); + new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); // Unload modules if (moduleManager != null) { @@ -595,7 +599,7 @@ public class AuthMe extends JavaPlugin { database.close(); // Backend MYSQL - FILE - SQLITE - SQLITEHIKARI boolean isSQLite = false; - switch (Settings.getDataSource) { + switch (newSettings.getProperty(DatabaseSettings.BACKEND)) { case FILE: database = new FlatFile(); break; @@ -788,16 +792,14 @@ public class AuthMe extends JavaPlugin { PlayerCache.getInstance().removePlayer(name); } - // Select the player to kick when a vip player join the server when full + // Select the player to kick when a vip player joins the server when full public Player generateKickPlayer(Collection collection) { - Player player = null; - for (Player p : collection) { - if (!getPermissionsManager().hasPermission(p, PlayerPermission.IS_VIP)) { - player = p; - break; + for (Player player : collection) { + if (!getPermissionsManager().hasPermission(player, PlayerPermission.IS_VIP)) { + return player; } } - return player; + return null; } // Purge inactive players from the database, as defined in the configuration @@ -809,10 +811,7 @@ public class AuthMe extends JavaPlugin { calendar.add(Calendar.DATE, -(Settings.purgeDelay)); long until = calendar.getTimeInMillis(); List cleared = database.autoPurgeDatabase(until); - if (cleared == null) { - return; - } - if (cleared.isEmpty()) { + if (CollectionUtils.isEmpty(cleared)) { return; } ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!"); diff --git a/src/main/java/fr/xephi/authme/PerformBackup.java b/src/main/java/fr/xephi/authme/PerformBackup.java index 6dbb7e4f9..250ac7f70 100644 --- a/src/main/java/fr/xephi/authme/PerformBackup.java +++ b/src/main/java/fr/xephi/authme/PerformBackup.java @@ -1,8 +1,17 @@ package fr.xephi.authme; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.datasource.DataSource; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.BackupSettings; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.util.StringUtils; -import java.io.*; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; import java.text.SimpleDateFormat; import java.util.Date; @@ -10,47 +19,51 @@ import java.util.Date; * The backup management class * * @author stefano - * @version $Revision: 1.0 $ */ public class PerformBackup { - final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm"); - final String dateString = format.format(new Date()); - private final String dbName = Settings.getMySQLDatabase; - private final String dbUserName = Settings.getMySQLUsername; - private final String dbPassword = Settings.getMySQLPassword; - private final String tblname = Settings.getMySQLTablename; - private final String path = AuthMe.getInstance().getDataFolder() + File.separator + "backups" + File.separator + "backup" + dateString; - private AuthMe instance; + 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 File dataFolder; + private final NewSetting settings; /** * Constructor for PerformBackup. * * @param instance AuthMe */ - public PerformBackup(AuthMe instance) { - this.setInstance(instance); + public PerformBackup(AuthMe instance, NewSetting 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 = StringUtils.join(File.separator, + instance.getDataFolder().getPath(), "backups", "backup" + dateString); } /** * Perform a backup with the given reason. * - * @param cause BackupCause The cause of the backup. + * @param cause The cause of the backup. */ public void doBackup(BackupCause cause) { - if (!Settings.isBackupActivated) { - ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: " + cause.name()); + if (!settings.getProperty(BackupSettings.ENABLED)) { + ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: " + + cause.name()); } // Check whether a backup should be made at the specified point in time - switch (cause) { - case START: - if (!Settings.isBackupOnStart) - return; - case STOP: - if (!Settings.isBackupOnStop) - return; - case COMMAND: - case OTHER: + if (BackupCause.START.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_START) + || BackupCause.STOP.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) { + return; } // Do backup and check return value! @@ -61,37 +74,31 @@ public class PerformBackup { } } - /** - * Method doBackup. - * - * @return boolean - */ public boolean doBackup() { - - switch (Settings.getDataSource) { + DataSource.DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND); + switch (dataSourceType) { case FILE: - return FileBackup("auths.db"); + return fileBackup("auths.db"); case MYSQL: - return MySqlBackup(); + return mySqlBackup(); case SQLITE: - return FileBackup(Settings.getMySQLDatabase + ".db"); + return fileBackup(dbName + ".db"); + default: + ConsoleLogger.showError("Unknown data source type '" + dataSourceType + "' for backup"); } return false; } - /** - * Method MySqlBackup. - * - * @return boolean - */ - private boolean MySqlBackup() { - File dirBackup = new File(AuthMe.getInstance().getDataFolder() + "/backups"); + private boolean mySqlBackup() { + File dirBackup = new File(dataFolder + File.separator + "backups"); - if (!dirBackup.exists()) + if (!dirBackup.exists()) { dirBackup.mkdir(); - if (checkWindows(Settings.backupWindowsPath)) { - String executeCmd = Settings.backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql"; + } + String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH); + if (checkWindows(backupWindowsPath)) { + String executeCmd = backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql"; Process runtimeProcess; try { runtimeProcess = Runtime.getRuntime().exec(executeCmd); @@ -102,8 +109,12 @@ public class PerformBackup { } else { ConsoleLogger.showError("Could not create the backup!"); } - } catch (Exception ex) { - ex.printStackTrace(); + } catch (IOException e) { + ConsoleLogger.showError("Error during backup: " + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } catch (InterruptedException e) { + ConsoleLogger.showError("Backup was interrupted: " + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); } } else { String executeCmd = "mysqldump -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql"; @@ -117,69 +128,54 @@ public class PerformBackup { } else { ConsoleLogger.showError("Could not create the backup!"); } - } catch (Exception ex) { - ex.printStackTrace(); + } catch (IOException e) { + ConsoleLogger.showError("Error during backup: " + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } catch (InterruptedException e) { + ConsoleLogger.showError("Backup was interrupted: " + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); } } return false; } - /** - * Method FileBackup. - * - * @param backend String - * - * @return boolean - */ - private boolean FileBackup(String backend) { - File dirBackup = new File(AuthMe.getInstance().getDataFolder() + "/backups"); + private boolean fileBackup(String backend) { + File dirBackup = new File(dataFolder + File.separator + "backups"); if (!dirBackup.exists()) dirBackup.mkdir(); try { - copy(new File("plugins" + File.separator + "AuthMe" + File.separator + backend), new File(path + ".db")); + copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db"); return true; - - } catch (Exception ex) { - ex.printStackTrace(); + } catch (IOException ex) { + ConsoleLogger.showError("Encountered an error during file backup: " + StringUtils.formatException(ex)); + ConsoleLogger.writeStackTrace(ex); } return false; } /** - * Method checkWindows. + * Check if we are under Windows and correct location of mysqldump.exe + * otherwise return error. * - * @param windowsPath String - * - * @return boolean + * @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 boolean checkWindows(String windowsPath) { + private static boolean checkWindows(String windowsPath) { String isWin = System.getProperty("os.name").toLowerCase(); if (isWin.contains("win")) { if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) { return true; } else { - ConsoleLogger.showError("Mysql Windows Path is incorrect please check it"); - return true; + ConsoleLogger.showError("Mysql Windows Path is incorrect. Please check it"); + return false; } - } else return false; + } + return false; } - /* - * Check if we are under Windows and correct location of mysqldump.exe - * otherwise return error. - */ - - /** - * Method copy. - * - * @param src File - * @param dst File - * - * @throws IOException - */ - void copy(File src, File dst) throws IOException { + private static void copy(String src, String dst) throws IOException { InputStream in = new FileInputStream(src); OutputStream out = new FileOutputStream(dst); @@ -193,27 +189,6 @@ public class PerformBackup { out.close(); } - /* - * Copyr src bytefile into dst file - */ - - /** - * Method getInstance. - * - * @return AuthMe - */ - public AuthMe getInstance() { - return instance; - } - - /** - * Method setInstance. - * - * @param instance AuthMe - */ - public void setInstance(AuthMe instance) { - this.instance = instance; - } /** * Possible backup causes. @@ -221,8 +196,7 @@ public class PerformBackup { public enum BackupCause { START, STOP, - COMMAND, - OTHER, + COMMAND } } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java index 64a35dd32..bfbb2ebf6 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/VersionCommand.java @@ -3,7 +3,6 @@ package fr.xephi.authme.command.executable.authme; import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; -import fr.xephi.authme.settings.Settings; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -11,12 +10,15 @@ import org.bukkit.entity.Player; import java.util.List; +import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; + public class VersionCommand implements ExecutableCommand { @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { // Show some version info - sender.sendMessage(ChatColor.GOLD + "==========[ " + Settings.helpHeader + " ABOUT ]=========="); + sender.sendMessage(ChatColor.GOLD + "==========[ " + commandService.getProperty(HELP_HEADER) + + " ABOUT ]=========="); sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName() + " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")"); sender.sendMessage(ChatColor.GOLD + "Developers:"); diff --git a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java index f05d21171..7bc06f03d 100644 --- a/src/main/java/fr/xephi/authme/command/help/HelpProvider.java +++ b/src/main/java/fr/xephi/authme/command/help/HelpProvider.java @@ -10,7 +10,6 @@ import fr.xephi.authme.command.FoundCommandResult; import fr.xephi.authme.permission.DefaultPermission; import fr.xephi.authme.permission.PermissionNode; import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.CollectionUtils; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -44,9 +43,11 @@ public class HelpProvider { public static final int ALL_OPTIONS = ~HIDE_COMMAND; private final PermissionsManager permissionsManager; + private final String helpHeader; - public HelpProvider(PermissionsManager permissionsManager) { + public HelpProvider(PermissionsManager permissionsManager, String helpHeader) { this.permissionsManager = permissionsManager; + this.helpHeader = helpHeader; } public List printHelp(CommandSender sender, FoundCommandResult result, int options) { @@ -55,7 +56,7 @@ public class HelpProvider { } List lines = new ArrayList<>(); - lines.add(ChatColor.GOLD + "==========[ " + Settings.helpHeader + " HELP ]=========="); + lines.add(ChatColor.GOLD + "==========[ " + helpHeader + " HELP ]=========="); CommandDescription command = result.getCommandDescription(); List labels = ImmutableList.copyOf(result.getLabels()); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index f6ed7e2e8..5cd3f592e 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.regex.Pattern; /** + * Old settings manager. See {@link NewSetting} for the new manager. */ public final class Settings { @@ -66,8 +67,7 @@ public final class Settings { isSaveQuitLocationEnabled, isForceSurvivalModeEnabled, isCachingEnabled, isKickOnWrongPasswordEnabled, enablePasswordConfirmation, - protectInventoryBeforeLogInEnabled, isBackupActivated, - isBackupOnStart, isBackupOnStop, isStopEnabled, reloadSupport, + protectInventoryBeforeLogInEnabled, isStopEnabled, reloadSupport, rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts, useCaptcha, emailRegistration, multiverse, bungee, banUnsafeIp, doubleEmailCheck, sessionExpireOnIpChange, @@ -79,7 +79,7 @@ public final class Settings { checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect, kickPlayersBeforeStopping, customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase; - public static String helpHeader, getNickRegex, getUnloggedinGroup, getMySQLHost, + public static String getNickRegex, getUnloggedinGroup, getMySQLHost, getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase, getMySQLTablename, getMySQLColumnName, getMySQLColumnPassword, getMySQLColumnIp, getMySQLColumnLastLogin, getMySQLColumnSalt, @@ -135,7 +135,6 @@ public final class Settings { } public static void loadVariables() { - helpHeader = configFile.getString("settings.helpHeader", "AuthMeReloaded"); messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage", "en").toLowerCase()); isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false); isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true); @@ -201,9 +200,6 @@ public final class Settings { plugin.checkProtocolLib(); passwordMaxLength = configFile.getInt("settings.security.passwordMaxLength", 20); - isBackupActivated = configFile.getBoolean("BackupSystem.ActivateBackup", false); - isBackupOnStart = configFile.getBoolean("BackupSystem.OnServerStart", false); - isBackupOnStop = configFile.getBoolean("BackupSystem.OnServeStop", false); backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\"); isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true); reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true); diff --git a/src/main/java/fr/xephi/authme/util/CollectionUtils.java b/src/main/java/fr/xephi/authme/util/CollectionUtils.java index 13077547c..6ec617a2c 100644 --- a/src/main/java/fr/xephi/authme/util/CollectionUtils.java +++ b/src/main/java/fr/xephi/authme/util/CollectionUtils.java @@ -52,11 +52,12 @@ public final class CollectionUtils { } /** - * @param element - * @param coll Collection - * @return boolean Boolean + * Null-safe way to check whether a collection is empty or not. + * + * @param coll The collection to verify + * @return True if the collection is null or empty, false otherwise */ - public static boolean isEmpty(Collection coll) { + public static boolean isEmpty(Collection coll) { return coll == null || coll.isEmpty(); } diff --git a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java index cb9c85012..45e4d4240 100644 --- a/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java +++ b/src/test/java/fr/xephi/authme/command/help/HelpProviderTest.java @@ -6,7 +6,6 @@ import fr.xephi.authme.command.FoundResultStatus; import fr.xephi.authme.command.TestCommandsUtil; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.permission.PlayerPermission; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; import org.bukkit.ChatColor; import org.bukkit.command.CommandSender; @@ -40,22 +39,22 @@ import static org.mockito.Mockito.mock; */ public class HelpProviderTest { + private static final String HELP_HEADER = "Help"; + private static Set commands; private HelpProvider helpProvider; private PermissionsManager permissionsManager; private CommandSender sender; - private static Set commands; @BeforeClass public static void setUpCommands() { WrapperMock.createInstance(); - Settings.helpHeader = "Help"; commands = TestCommandsUtil.generateCommands(); } @Before public void setUpHelpProvider() { permissionsManager = mock(PermissionsManager.class); - helpProvider = new HelpProvider(permissionsManager); + helpProvider = new HelpProvider(permissionsManager, HELP_HEADER); sender = mock(CommandSender.class); } @@ -70,7 +69,7 @@ public class HelpProviderTest { // then assertThat(lines, hasSize(5)); - assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP")); + assertThat(lines.get(0), containsString(HELP_HEADER + " HELP")); assertThat(removeColors(lines.get(1)), containsString("Command: /authme login ")); assertThat(removeColors(lines.get(2)), containsString("Short description: login cmd")); assertThat(removeColors(lines.get(3)), equalTo("Detailed description:")); @@ -88,7 +87,7 @@ public class HelpProviderTest { // then assertThat(lines, hasSize(4)); - assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP")); + assertThat(lines.get(0), containsString(HELP_HEADER + " HELP")); assertThat(removeColors(lines.get(1)), equalTo("Arguments:")); assertThat(removeColors(lines.get(2)), containsString("password: 'password' argument description")); assertThat(removeColors(lines.get(3)), containsString("confirmation: 'confirmation' argument description")); @@ -279,7 +278,7 @@ public class HelpProviderTest { // then assertThat(lines, hasSize(2)); - assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP")); + assertThat(lines.get(0), containsString(HELP_HEADER + " HELP")); assertThat(removeColors(lines.get(1)), containsString("Command: /authme register ")); } From 059175f14e95066be57c7149efb0d42495529203 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 30 Jan 2016 15:12:26 +0100 Subject: [PATCH 07/14] #450 Port usages of Settings#set(), #setValue() to NewSettings --- src/main/java/fr/xephi/authme/AuthMe.java | 44 +++++++++---------- .../authme/converter/ForceFlatToSqlite.java | 35 +++++++++------ .../fr/xephi/authme/datasource/FlatFile.java | 8 ++-- .../fr/xephi/authme/settings/NewSetting.java | 25 +++++++++-- .../fr/xephi/authme/settings/Settings.java | 37 ++-------------- 5 files changed, 73 insertions(+), 76 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index e38ece18f..e89df701e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -50,6 +50,8 @@ import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.settings.properties.RestrictionSettings; +import fr.xephi.authme.settings.properties.SecuritySettings; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.GeoLiteAPI; import fr.xephi.authme.util.StringUtils; @@ -628,7 +630,7 @@ public class AuthMe extends JavaPlugin { if (Settings.getDataSource == DataSource.DataSourceType.FILE) { ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, it will be changed " + "to SQLite... Connection will be impossible until conversion is done!"); - ForceFlatToSqlite converter = new ForceFlatToSqlite(database); + ForceFlatToSqlite converter = new ForceFlatToSqlite(database, newSettings); DataSource source = converter.run(); if (source != null) { database = source; @@ -636,7 +638,7 @@ public class AuthMe extends JavaPlugin { } // TODO: Move this to another place maybe ? - if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) { + if (HashAlgorithm.PLAINTEXT == newSettings.getProperty(SecuritySettings.PASSWORD_HASH)) { ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " + "it will be changed and hashed now to the AuthMe default hashing method"); for (PlayerAuth auth : database.getAllAuths()) { @@ -645,11 +647,11 @@ public class AuthMe extends JavaPlugin { auth.setPassword(hashedPassword); database.updatePassword(auth); } - Settings.setValue("settings.security.passwordHash", "SHA256"); - Settings.reload(); + newSettings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256); + newSettings.save(); } - if (Settings.isCachingEnabled) { + if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) { database = new CacheDataSource(database); } } @@ -740,24 +742,20 @@ public class AuthMe extends JavaPlugin { // Check the presence of the ProtocolLib plugin public void checkProtocolLib() { if (!server.getPluginManager().isPluginEnabled("ProtocolLib")) { - if (Settings.protectInventoryBeforeLogInEnabled) { - ConsoleLogger.showError("WARNING!!! The protectInventory feature requires ProtocolLib! Disabling it..."); + if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) { + ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it..."); Settings.protectInventoryBeforeLogInEnabled = false; - getSettings().set("settings.restrictions.ProtectInventoryBeforeLogIn", false); + newSettings.setProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN, false); } return; } - if (Settings.protectInventoryBeforeLogInEnabled) { - if (inventoryProtector == null) { - inventoryProtector = new AuthMeInventoryPacketAdapter(this); - inventoryProtector.register(); - } - } else { - if (inventoryProtector != null) { - inventoryProtector.unregister(); - inventoryProtector = null; - } + if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN) && inventoryProtector == null) { + inventoryProtector = new AuthMeInventoryPacketAdapter(this); + inventoryProtector.register(); + } else if (inventoryProtector != null) { + inventoryProtector.unregister(); + inventoryProtector = null; } if (tabComplete == null) { tabComplete = new AuthMeTabCompletePacketAdapter(this); @@ -895,12 +893,12 @@ public class AuthMe extends JavaPlugin { for (Player player : Utils.getOnlinePlayers()) { if (player.isOnline()) { String name = player.getName().toLowerCase(); - if (database.isAuthAvailable(name)) - if (PlayerCache.getInstance().isAuthenticated(name)) { - String email = database.getAuth(name).getEmail(); - if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) - messages.send(player, MessageKey.ADD_EMAIL_MESSAGE); + if (database.isAuthAvailable(name) && PlayerCache.getInstance().isAuthenticated(name)) { + String email = database.getAuth(name).getEmail(); + if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) { + messages.send(player, MessageKey.ADD_EMAIL_MESSAGE); } + } } } } diff --git a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java index b0ea61c0b..d873aa506 100644 --- a/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java +++ b/src/main/java/fr/xephi/authme/converter/ForceFlatToSqlite.java @@ -4,32 +4,41 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.SQLite; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.DatabaseSettings; +import fr.xephi.authme.util.StringUtils; + +import java.sql.SQLException; /** + * Mandatory migration from the deprecated flat file datasource to SQLite. */ public class ForceFlatToSqlite { - private final DataSource data; + private final DataSource database; + private final NewSetting settings; - public ForceFlatToSqlite(DataSource data) { - this.data = data; + public ForceFlatToSqlite(DataSource database, NewSetting settings) { + this.database = database; + this.settings = settings; } public DataSource run() { - DataSource sqlite = null; try { - sqlite = new SQLite(); - for (PlayerAuth auth : data.getAllAuths()) { + DataSource sqlite = new SQLite(); + for (PlayerAuth auth : database.getAllAuths()) { auth.setRealName("Player"); sqlite.saveAuth(auth); } - Settings.setValue("DataSource.backend", "sqlite"); - ConsoleLogger.info("Database successfully converted to sqlite !"); - } catch (Exception e) { - ConsoleLogger.showError("An error occurred while trying to convert flatfile to sqlite ..."); - return null; + settings.setProperty(DatabaseSettings.BACKEND, DataSource.DataSourceType.SQLITE); + settings.save(); + ConsoleLogger.info("Database successfully converted to sqlite!"); + return sqlite; + } catch (SQLException | ClassNotFoundException e) { + ConsoleLogger.showError("An error occurred while trying to convert flatfile to sqlite: " + + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); } - return sqlite; + return null; } } diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index 4d7b4b38e..88bad0774 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -36,17 +36,19 @@ public class FlatFile implements DataSource { private final File source; public FlatFile() { - source = Settings.AUTH_FILE; + AuthMe instance = AuthMe.getInstance(); + + source = new File(instance.getDataFolder(), "auths.db"); try { source.createNewFile(); } catch (IOException e) { ConsoleLogger.showError(e.getMessage()); if (Settings.isStopEnabled) { ConsoleLogger.showError("Can't use FLAT FILE... SHUTDOWN..."); - AuthMe.getInstance().getServer().shutdown(); + instance.getServer().shutdown(); } if (!Settings.isStopEnabled) { - AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance()); + instance.getServer().getPluginManager().disablePlugin(instance); } e.printStackTrace(); } diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 8aa46b84f..232b37b44 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -28,8 +28,7 @@ public class NewSetting { private FileConfiguration configuration; /** - * Constructor. - * Loads the file as YAML and checks its integrity. + * Constructor. Checks the given {@link FileConfiguration} object for completeness. * * @param configuration The configuration to interact with * @param file The configuration file @@ -74,7 +73,25 @@ public class NewSetting { return property.getFromFile(configuration); } - public void save(PropertyMap propertyMap) { + /** + * Set a new value for the given property. + * + * @param property The property to modify + * @param value The new value to assign to the property + * @param The property's type + */ + public void setProperty(Property property, T value) { + configuration.set(property.getPath(), value); + } + + /** + * Save the config file. Use after migrating one or more settings. + */ + public void save() { + save(SettingsFieldRetriever.getAllPropertyFields()); + } + + private void save(PropertyMap propertyMap) { try (FileWriter writer = new FileWriter(file)) { Yaml simpleYaml = newYaml(false); Yaml singleQuoteYaml = newYaml(true); @@ -165,7 +182,7 @@ public class NewSetting { } private static String indent(int level) { - // YAML uses indentation of 4 spaces + // We use an indentation of 4 spaces StringBuilder sb = new StringBuilder(level * 4); for (int i = 0; i < level; ++i) { sb.append(" "); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 5cd3f592e..14794965d 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -31,9 +31,8 @@ public final class Settings { public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); - public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db"); - public static final File EMAIL_FILE = new File(PLUGIN_FOLDER, "email.html"); - public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); + private static final File EMAIL_FILE = new File(PLUGIN_FOLDER, "email.html"); + private static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); public static final File LOG_FILE = new File(PLUGIN_FOLDER, "authme.log"); // This is not an option! public static boolean antiBotInAction = false; @@ -311,15 +310,6 @@ public final class Settings { } } - /** - * @param key the key to set - * @param value the value to set - */ - public static void setValue(String key, Object value) { - instance.set(key, value); - save(); - } - /** * Method getPasswordHash. * @@ -392,7 +382,7 @@ public final class Settings { * * @return True if saved successfully */ - public static boolean save() { + private static boolean save() { try { configFile.save(SETTINGS_FILE); return true; @@ -503,25 +493,6 @@ public final class Settings { return correct; } - /** - * @param path - * - * @return - */ - private static boolean contains(String path) { - return configFile.contains(path); - } - - // public because it's used in AuthMe at one place - - /** - * @param path String - * @param value String - */ - public void set(String path, Object value) { - configFile.set(path, value); - } - /** * Saves current configuration (plus defaults) to disk. *

@@ -529,7 +500,7 @@ public final class Settings { * * @return True if saved successfully */ - public final boolean saveDefaults() { + private boolean saveDefaults() { configFile.options() .copyDefaults(true) .copyHeader(true); From e747dfeb7fc2d639f2b4319223a76bf0f9687879 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 31 Jan 2016 09:55:02 +0100 Subject: [PATCH 08/14] #450 Make reload & messages functionality use NewSetting - Change ReloadCommand to use the new setting functionality - Check and construct the messages file in NewSetting - Unrelated: change MessagesManager not to extend CustomConfiguration anymore --- src/main/java/fr/xephi/authme/AuthMe.java | 40 ++----------- .../xephi/authme/command/CommandService.java | 29 ++++++++++ .../executable/authme/ReloadCommand.java | 24 ++++---- .../java/fr/xephi/authme/output/Messages.java | 33 ++++------- .../xephi/authme/output/MessagesManager.java | 21 +++---- .../fr/xephi/authme/settings/NewSetting.java | 56 ++++++++++++++++--- .../fr/xephi/authme/util/StringUtils.java | 40 ++++++++----- .../authme/command/CommandServiceTest.java | 46 ++++++++++----- .../output/MessagesIntegrationTest.java | 6 +- .../xephi/authme/settings/NewSettingTest.java | 3 +- .../fr/xephi/authme/util/StringUtilsTest.java | 10 ++++ 11 files changed, 185 insertions(+), 123 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index e89df701e..4d7c9461e 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -34,7 +34,6 @@ import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMeServerListener; import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; import fr.xephi.authme.mail.SendMailSSL; -import fr.xephi.authme.modules.ModuleManager; import fr.xephi.authme.output.ConsoleFilter; import fr.xephi.authme.output.Log4JFilter; import fr.xephi.authme.output.MessageKey; @@ -110,7 +109,6 @@ public class AuthMe extends JavaPlugin { private NewSetting newSettings; private Messages messages; private JsonCache playerBackup; - private ModuleManager moduleManager; private PasswordSecurity passwordSecurity; private DataSource database; @@ -219,15 +217,14 @@ public class AuthMe extends JavaPlugin { setPluginInfos(); // Load settings and custom configurations, if it fails, stop the server due to security reasons. + newSettings = createNewSetting(); if (loadSettings()) { server.shutdown(); setEnabled(false); return; } - newSettings = createNewSetting(); - // Set up messages & password security - messages = Messages.getInstance(); + messages = new Messages(Settings.messageFile); // Connect to the database and setup tables try { @@ -247,9 +244,6 @@ public class AuthMe extends JavaPlugin { permsMan = initializePermissionsManager(); commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings); - // Set up the module manager - setupModuleManager(); - // Setup otherAccounts file this.otherAccounts = OtherAccounts.getInstance(); @@ -327,21 +321,6 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!"); } - /** - * Set up the module manager. - */ - private void setupModuleManager() { - // TODO: Clean this up! - // TODO: split the plugin in more modules - // TODO: log number of loaded modules - - // Define the module manager instance - moduleManager = new ModuleManager(this); - - // Load the modules - // int loaded = moduleManager.loadModules(); - } - /** * Set up the mail API, if enabled. */ @@ -469,7 +448,7 @@ public class AuthMe extends JavaPlugin { private NewSetting createNewSetting() { File configFile = new File(getDataFolder() + "config.yml"); - return new NewSetting(getConfig(), configFile); + return new NewSetting(getConfig(), configFile, getDataFolder()); } /** @@ -536,18 +515,15 @@ public class AuthMe extends JavaPlugin { } // Do backup on stop if enabled - new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); - - // Unload modules - if (moduleManager != null) { - moduleManager.unloadModules(); + if (newSettings != null) { + new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP); } List pendingTasks = getServer().getScheduler().getPendingTasks(); for (Iterator iterator = pendingTasks.iterator(); iterator.hasNext();) { BukkitTask pendingTask = iterator.next(); if (!pendingTask.getOwner().equals(this) || pendingTask.isSync()) { - //remove all unrelevant tasks + //remove all irrelevant tasks iterator.remove(); } } @@ -973,10 +949,6 @@ public class AuthMe extends JavaPlugin { return count >= Settings.getMaxJoinPerIp; } - public ModuleManager getModuleManager() { - return moduleManager; - } - /** * Handle Bukkit commands. * diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index 99d6bdb26..5b8b5e490 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -12,6 +12,7 @@ import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.domain.Property; import org.bukkit.command.CommandSender; +import java.io.File; import java.util.List; /** @@ -101,6 +102,16 @@ public class CommandService { return authMe.getDataSource(); } + /** + * Return the AuthMe instance for further manipulation. Use only if other methods from + * the command service cannot be used. + * + * @return The AuthMe instance + */ + public AuthMe getAuthMe() { + return authMe; + } + /** * Return the PasswordSecurity instance. * @@ -152,6 +163,15 @@ public class CommandService { return messages.retrieve(key); } + /** + * Change the messages instance to retrieve messages from the given file. + * + * @param file The new file to read messages from + */ + public void reloadMessages(File file) { + messages.reload(file); + } + /** * Retrieve the given property's value. * @@ -163,4 +183,13 @@ public class CommandService { return settings.getProperty(property); } + /** + * Return the settings manager. + * + * @return The settings manager + */ + public NewSetting getSettings() { + return settings; + } + } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java index 7e4ad2b19..db21c8593 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java @@ -1,36 +1,32 @@ package fr.xephi.authme.command.executable.authme; -import java.util.List; - -import org.bukkit.command.CommandSender; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.output.Messages; -import fr.xephi.authme.settings.Settings; +import org.bukkit.command.CommandSender; +import java.util.List; + +/** + * The reload command. + */ public class ReloadCommand implements ExecutableCommand { @Override public void executeCommand(CommandSender sender, List arguments, CommandService commandService) { - // AuthMe plugin instance - AuthMe plugin = AuthMe.getInstance(); - + AuthMe plugin = commandService.getAuthMe(); try { - Settings.reload(); - Messages.getInstance().reloadManager(); - plugin.getModuleManager().reloadModules(); + commandService.getSettings().reload(); + commandService.reloadMessages(commandService.getSettings().getMessagesFile()); plugin.setupDatabase(); + commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); } catch (Exception e) { sender.sendMessage("Error occurred during reload of AuthMe: aborting"); ConsoleLogger.showError("Fatal error occurred! AuthMe instance ABORTED!"); ConsoleLogger.writeStackTrace(e); plugin.stopOrUnload(); } - - commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS); } } diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java index e27e90618..731844d07 100644 --- a/src/main/java/fr/xephi/authme/output/Messages.java +++ b/src/main/java/fr/xephi/authme/output/Messages.java @@ -1,9 +1,10 @@ package fr.xephi.authme.output; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.StringUtils; import org.bukkit.command.CommandSender; +import java.io.File; + /** * Class for retrieving and sending translatable messages to players. * This class detects when the language settings have changed and will @@ -11,27 +12,15 @@ import org.bukkit.command.CommandSender; */ public class Messages { - private static Messages singleton; - private final String language; private MessagesManager manager; - - private Messages(String language, MessagesManager manager) { - this.language = language; - this.manager = manager; - } - /** - * Get the instance of Messages. + * Constructor. * - * @return The Messages instance + * @param messageFile The messages file to use */ - public static Messages getInstance() { - if (singleton == null) { - MessagesManager manager = new MessagesManager(Settings.messageFile); - singleton = new Messages(Settings.messagesLanguage, manager); - } - return singleton; + public Messages(File messageFile) { + manager = new MessagesManager(messageFile); } /** @@ -60,7 +49,8 @@ public class Messages { String message = retrieveSingle(key); String[] tags = key.getTags(); if (replacements.length != tags.length) { - throw new RuntimeException("Given replacement size does not match the tags in message key '" + key + "'"); + throw new IllegalStateException( + "Given replacement size does not match the tags in message key '" + key + "'"); } for (int i = 0; i < tags.length; ++i) { @@ -80,9 +70,6 @@ public class Messages { * @return The message split by new lines */ public String[] retrieve(MessageKey key) { - if (!Settings.messagesLanguage.equalsIgnoreCase(language)) { - reloadManager(); - } return manager.retrieve(key.getKey()); } @@ -100,8 +87,8 @@ public class Messages { /** * Reload the messages manager. */ - public void reloadManager() { - manager = new MessagesManager(Settings.messageFile); + public void reload(File messagesFile) { + manager = new MessagesManager(messagesFile); } } diff --git a/src/main/java/fr/xephi/authme/output/MessagesManager.java b/src/main/java/fr/xephi/authme/output/MessagesManager.java index 1308712a0..a280ea3ae 100644 --- a/src/main/java/fr/xephi/authme/output/MessagesManager.java +++ b/src/main/java/fr/xephi/authme/output/MessagesManager.java @@ -1,8 +1,8 @@ package fr.xephi.authme.output; import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.settings.CustomConfiguration; import org.bukkit.ChatColor; +import org.bukkit.configuration.file.YamlConfiguration; import java.io.File; @@ -12,7 +12,10 @@ import java.io.File; * This class is used within {@link Messages}, which offers a high-level interface for accessing * or sending messages from a properties file. */ -class MessagesManager extends CustomConfiguration { +class MessagesManager { + + private final YamlConfiguration configuration; + private final String fileName; /** * Constructor for Messages. @@ -20,8 +23,8 @@ class MessagesManager extends CustomConfiguration { * @param file the configuration file */ MessagesManager(File file) { - super(file); - load(); + this.fileName = file.getName(); + this.configuration = YamlConfiguration.loadConfiguration(file); } /** @@ -31,24 +34,22 @@ class MessagesManager extends CustomConfiguration { * * @return The message */ - String[] retrieve(String key) { - String message = (String) get(key); + public String[] retrieve(String key) { + String message = configuration.getString(key); if (message != null) { return formatMessage(message); } // Message is null: log key not being found and send error back as message String retrievalError = "Error getting message with key '" + key + "'. "; - ConsoleLogger.showError(retrievalError + "Please verify your config file at '" - + getConfigFile().getName() + "'"); + ConsoleLogger.showError(retrievalError + "Please verify your config file at '" + fileName + "'"); return new String[]{ retrievalError + "Please contact the admin to verify or update the AuthMe messages file."}; } - static String[] formatMessage(String message) { + private static String[] formatMessage(String message) { String[] lines = message.split("&n"); for (int i = 0; i < lines.length; ++i) { - // We don't initialize a StringBuilder here because mostly we will only have one entry lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]); } return lines; diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 232b37b44..25a5c6406 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -3,11 +3,13 @@ package fr.xephi.authme.settings; import com.google.common.annotations.VisibleForTesting; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.domain.Property; +import fr.xephi.authme.settings.properties.PluginSettings; import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.CollectionUtils; import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; @@ -19,23 +21,30 @@ import java.util.Arrays; import java.util.List; import java.util.Map; +import static fr.xephi.authme.util.StringUtils.makePath; + /** * The new settings manager. */ public class NewSetting { - private File file; + private final File pluginFolder; + private final File configFile; private FileConfiguration configuration; + private File messagesFile; /** * Constructor. Checks the given {@link FileConfiguration} object for completeness. * * @param configuration The configuration to interact with - * @param file The configuration file + * @param configFile The configuration file + * @param pluginFolder The AuthMe plugin folder */ - public NewSetting(FileConfiguration configuration, File file) { + public NewSetting(FileConfiguration configuration, File configFile, File pluginFolder) { this.configuration = configuration; - this.file = file; + this.configFile = configFile; + this.pluginFolder = pluginFolder; + messagesFile = buildMessagesFile(); PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { @@ -49,13 +58,14 @@ public class NewSetting { * Constructor for testing purposes, allowing more options. * * @param configuration The FileConfiguration object to use - * @param file The file to write to + * @param configFile The file to write to * @param propertyMap The property map whose properties should be verified for presence, or null to skip this */ @VisibleForTesting - NewSetting(FileConfiguration configuration, File file, PropertyMap propertyMap) { + NewSetting(FileConfiguration configuration, File configFile, PropertyMap propertyMap) { this.configuration = configuration; - this.file = file; + this.configFile = configFile; + this.pluginFolder = new File(""); if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { save(propertyMap); @@ -91,8 +101,24 @@ public class NewSetting { save(SettingsFieldRetriever.getAllPropertyFields()); } + /** + * Return the messages file based on the messages language config. + * + * @return The messages file to read messages from + */ + public File getMessagesFile() { + return messagesFile; + } + + /** + * Reload the configuration. + */ + public void reload() { + configuration = YamlConfiguration.loadConfiguration(configFile); + } + private void save(PropertyMap propertyMap) { - try (FileWriter writer = new FileWriter(file)) { + try (FileWriter writer = new FileWriter(configFile)) { Yaml simpleYaml = newYaml(false); Yaml singleQuoteYaml = newYaml(true); @@ -161,6 +187,20 @@ public class NewSetting { return join("\n" + indent(indent), representation.split("\\n")); } + private File buildMessagesFile() { + String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE); + File messagesFile = buildMessagesFileFromCode(languageCode); + if (messagesFile.exists()) { + return messagesFile; + } + return buildMessagesFileFromCode("en"); + } + + private File buildMessagesFileFromCode(String language) { + return new File(pluginFolder.getName(), + makePath("messages", "messages_" + language + ".yml")); + } + private static Yaml newYaml(boolean useSingleQuotes) { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); diff --git a/src/main/java/fr/xephi/authme/util/StringUtils.java b/src/main/java/fr/xephi/authme/util/StringUtils.java index 9ae0ec0fd..377dd9f75 100644 --- a/src/main/java/fr/xephi/authme/util/StringUtils.java +++ b/src/main/java/fr/xephi/authme/util/StringUtils.java @@ -4,6 +4,7 @@ import net.ricecode.similarity.LevenshteinDistanceStrategy; import net.ricecode.similarity.StringSimilarityService; import net.ricecode.similarity.StringSimilarityServiceImpl; +import java.io.File; import java.util.Arrays; /** @@ -37,12 +38,12 @@ public final class StringUtils { } /** - * Returns whether the given string contains any of the provided elements. + * Return whether the given string contains any of the provided elements. * - * @param str the string to analyze - * @param pieces the items to check the string for + * @param str The string to analyze + * @param pieces The items to check the string for * - * @return true if the string contains at least one of the items + * @return True if the string contains at least one of the items */ public static boolean containsAny(String str, String... pieces) { if (str == null) { @@ -60,21 +61,21 @@ public final class StringUtils { * Null-safe method for checking whether a string is empty. Note that the string * is trimmed, so this method also considers a string with whitespace as empty. * - * @param str the string to verify + * @param str The string to verify * - * @return true if the string is empty, false otherwise + * @return True if the string is empty, false otherwise */ public static boolean isEmpty(String str) { return str == null || str.trim().isEmpty(); } /** - * Joins a list of elements into a single string with the specified delimiter. + * Join a list of elements into a single string with the specified delimiter. * - * @param delimiter the delimiter to use - * @param elements the elements to join + * @param delimiter The delimiter to use + * @param elements The elements to join * - * @return a new String that is composed of the elements separated by the delimiter + * @return A new String that is composed of the elements separated by the delimiter */ public static String join(String delimiter, Iterable elements) { if (delimiter == null) { @@ -95,12 +96,12 @@ public final class StringUtils { } /** - * Joins a list of elements into a single string with the specified delimiter. + * Join a list of elements into a single string with the specified delimiter. * - * @param delimiter the delimiter to use - * @param elements the elements to join + * @param delimiter The delimiter to use + * @param elements The elements to join * - * @return a new String that is composed of the elements separated by the delimiter + * @return A new String that is composed of the elements separated by the delimiter */ public static String join(String delimiter, String... elements) { return join(delimiter, Arrays.asList(elements)); @@ -117,4 +118,15 @@ public final class StringUtils { return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage(); } + /** + * Construct a file path from the given elements, i.e. separate the given elements by the file separator. + * + * @param elements The elements to create a path with + * + * @return The created path + */ + public static String makePath(String... elements) { + return join(File.separator, elements); + } + } diff --git a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java index 034196986..4ebd4c8a9 100644 --- a/src/test/java/fr/xephi/authme/command/CommandServiceTest.java +++ b/src/test/java/fr/xephi/authme/command/CommandServiceTest.java @@ -18,6 +18,7 @@ import org.junit.Ignore; import org.junit.Test; import org.mockito.ArgumentCaptor; +import java.io.File; import java.util.Arrays; import java.util.List; @@ -95,19 +96,6 @@ public class CommandServiceTest { verify(commandMapper).mapPartsToCommand(sender, commandParts); } - @Test - @Ignore - public void shouldRunTaskInAsync() { - // given - Runnable runnable = mock(Runnable.class); - - // when - commandService.runTaskAsynchronously(runnable); - - // then - // TODO ljacqu 20151226: AuthMe#getServer() is final, i.e. not mockable - } - @Test public void shouldGetDataSource() { // given @@ -193,10 +181,40 @@ public class CommandServiceTest { given(settings.getProperty(property)).willReturn(7); // when - int result = settings.getProperty(property); + int result = commandService.getProperty(property); // then assertThat(result, equalTo(7)); verify(settings).getProperty(property); } + + @Test + public void shouldReloadMessages() { + // given + File file = new File("some/bogus-file.test"); + + // when + commandService.reloadMessages(file); + + // then + verify(messages).reload(file); + } + + @Test + public void shouldReturnSettings() { + // given/when + NewSetting result = commandService.getSettings(); + + // then + assertThat(result, equalTo(settings)); + } + + @Test + public void shouldReturnAuthMe() { + // given/when + AuthMe result = commandService.getAuthMe(); + + // then + assertThat(result, equalTo(authMe)); + } } diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 343a56871..6e63a934d 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.output; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; @@ -37,15 +36,12 @@ public class MessagesIntegrationTest { public void setUpMessages() { WrapperMock.createInstance(); - Settings.messagesLanguage = "en"; URL url = getClass().getClassLoader().getResource(YML_TEST_FILE); if (url == null) { throw new RuntimeException("File '" + YML_TEST_FILE + "' could not be loaded"); } - Settings.messageFile = new File(url.getFile()); - Settings.messagesLanguage = "en"; - messages = Messages.getInstance(); + messages = new Messages(new File(url.getFile())); } @Test diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java index 84941496e..232401bf6 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -2,6 +2,7 @@ package fr.xephi.authme.settings; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; +import fr.xephi.authme.settings.propertymap.PropertyMap; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; @@ -40,7 +41,7 @@ public class NewSettingTest { setReturnValue(file, TestConfiguration.SYSTEM_NAME, "myTestSys"); // when / then - NewSetting settings = new NewSetting(file, new File("conf.txt"), null); + NewSetting settings = new NewSetting(file, new File("conf.txt"), (PropertyMap) null); assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20)); assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true)); diff --git a/src/test/java/fr/xephi/authme/util/StringUtilsTest.java b/src/test/java/fr/xephi/authme/util/StringUtilsTest.java index 238c8bcef..6cc7799aa 100644 --- a/src/test/java/fr/xephi/authme/util/StringUtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/StringUtilsTest.java @@ -2,6 +2,7 @@ package fr.xephi.authme.util; import org.junit.Test; +import java.io.File; import java.net.MalformedURLException; import java.util.Arrays; import java.util.List; @@ -135,4 +136,13 @@ public class StringUtilsTest { assertThat(StringUtils.getDifference("test", "bear"), equalTo(0.75)); assertThat(StringUtils.getDifference("test", "something"), greaterThan(0.88)); } + + @Test + public void shouldConstructPath() { + // given/when + String result = StringUtils.makePath("path", "to", "test-file.txt"); + + // then + assertThat(result, equalTo("path" + File.separator + "to" + File.separator + "test-file.txt")); + } } From fbd5265a0ba4a60cb57fd0ea2386f71ddc56cacd Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 31 Jan 2016 10:49:30 +0100 Subject: [PATCH 09/14] #450 Fix YAML export of enum values - Move writing logic to PropertyType - Remove unused double property type - Add sample enum property type to tests --- src/main/java/fr/xephi/authme/AuthMe.java | 2 +- .../fr/xephi/authme/settings/NewSetting.java | 16 +------ .../settings/domain/EnumPropertyType.java | 5 ++- .../authme/settings/domain/Property.java | 24 ++++------ .../authme/settings/domain/PropertyType.java | 45 +++++++------------ .../settings/NewSettingIntegrationTest.java | 13 +++--- .../xephi/authme/settings/NewSettingTest.java | 9 ++-- .../settings/domain/PropertyTypeTest.java | 28 ------------ .../properties/TestConfiguration.java | 8 ++-- .../authme/settings/properties/TestEnum.java | 16 +++++++ .../resources/config-difficult-values.yml | 4 +- .../resources/config-incomplete-sample.yml | 4 +- src/test/resources/config-sample-values.yml | 4 +- 13 files changed, 69 insertions(+), 109 deletions(-) create mode 100644 src/test/java/fr/xephi/authme/settings/properties/TestEnum.java diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 4d7c9461e..03a7a6bc0 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -224,7 +224,7 @@ public class AuthMe extends JavaPlugin { return; } - messages = new Messages(Settings.messageFile); + messages = new Messages(newSettings.getMessagesFile()); // Connect to the database and setup tables try { diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 25a5c6406..5f393cb96 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -171,19 +171,7 @@ public class NewSetting { } private String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) { - T value = property.getFromFile(configuration); - String representation = property.hasSingleQuotes() - ? singleQuoteYaml.dump(value) - : simpleYaml.dump(value); - - // If the property is a non-empty list we need to append a new line because it will be - // something like the following, which requires a new line: - // - 'item 1' - // - 'second item in list' - if (property.isList() && !((List) value).isEmpty()) { - representation = "\n" + representation; - } - + String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml); return join("\n" + indent(indent), representation.split("\\n")); } @@ -197,7 +185,7 @@ public class NewSetting { } private File buildMessagesFileFromCode(String language) { - return new File(pluginFolder.getName(), + return new File(pluginFolder, makePath("messages", "messages_" + language + ".yml")); } diff --git a/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java b/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java index c71739a5f..d38d0649d 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java +++ b/src/main/java/fr/xephi/authme/settings/domain/EnumPropertyType.java @@ -1,6 +1,7 @@ package fr.xephi.authme.settings.domain; import org.bukkit.configuration.file.FileConfiguration; +import org.yaml.snakeyaml.Yaml; /** * Enum property type. @@ -32,8 +33,8 @@ class EnumPropertyType> extends PropertyType { } @Override - public boolean hasSingleQuotes() { - return true; + public String toYaml(E value, Yaml simpleYaml, Yaml singleQuoteYaml) { + return singleQuoteYaml.dump(value.name()); } private E mapToEnum(String value) { diff --git a/src/main/java/fr/xephi/authme/settings/domain/Property.java b/src/main/java/fr/xephi/authme/settings/domain/Property.java index a67c6a492..f9637a7be 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/Property.java +++ b/src/main/java/fr/xephi/authme/settings/domain/Property.java @@ -1,6 +1,7 @@ package fr.xephi.authme.settings.domain; import org.bukkit.configuration.file.FileConfiguration; +import org.yaml.snakeyaml.Yaml; import java.util.Arrays; import java.util.List; @@ -102,24 +103,15 @@ public class Property { } /** - * Return whether the property should be represented wrapped in single quotes in YAML. - * The YAML format allows both using single quotes and not for all types but for certain - * types one representation makes more sense. Typically we wrap string-like types in - * single quotes and all other ones not. + * Format the property's value as YAML. * - * @return True if single quotes should be used, false otherwise + * @param configuration The file configuration + * @param simpleYaml YAML object (default) + * @param singleQuoteYaml YAML object using single quotes + * @return The generated YAML */ - public boolean hasSingleQuotes() { - return type.hasSingleQuotes(); - } - - /** - * Return whether the property has a list type. - * - * @return True if the property type is a list, false otherwise - */ - public boolean isList() { - return type.isList(); + public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) { + return type.toYaml(getFromFile(configuration), simpleYaml, singleQuoteYaml); } // ----- diff --git a/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java b/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java index 4be934150..28a505cfb 100644 --- a/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java +++ b/src/main/java/fr/xephi/authme/settings/domain/PropertyType.java @@ -1,6 +1,7 @@ package fr.xephi.authme.settings.domain; import org.bukkit.configuration.file.FileConfiguration; +import org.yaml.snakeyaml.Yaml; import java.util.List; @@ -13,7 +14,6 @@ import java.util.List; public abstract class PropertyType { public static final PropertyType BOOLEAN = new BooleanProperty(); - public static final PropertyType DOUBLE = new DoubleProperty(); public static final PropertyType INTEGER = new IntegerProperty(); public static final PropertyType STRING = new StringProperty(); public static final PropertyType> STRING_LIST = new StringListProperty(); @@ -39,16 +39,15 @@ public abstract class PropertyType { } /** - * Return whether the property type should be wrapped in single quotes in YAML. + * Format the value as YAML. * - * @return True if single quotes should be used, false if not + * @param value The value to export + * @param simpleYaml YAML object (default) + * @param singleQuoteYaml YAML object set to use single quotes + * @return The generated YAML */ - public boolean hasSingleQuotes() { - return false; - } - - public boolean isList() { - return false; + public String toYaml(T value, Yaml simpleYaml, Yaml singleQuoteYaml) { + return simpleYaml.dump(value); } @@ -62,16 +61,6 @@ public abstract class PropertyType { } } - /** - * Double property. - */ - private static final class DoubleProperty extends PropertyType { - @Override - public Double getFromFile(Property property, FileConfiguration configuration) { - return configuration.getDouble(property.getPath(), property.getDefaultValue()); - } - } - /** * Integer property. */ @@ -91,8 +80,8 @@ public abstract class PropertyType { return configuration.getString(property.getPath(), property.getDefaultValue()); } @Override - public boolean hasSingleQuotes() { - return true; + public String toYaml(String value, Yaml simpleYaml, Yaml singleQuoteYaml) { + return singleQuoteYaml.dump(value); } } @@ -114,13 +103,13 @@ public abstract class PropertyType { } @Override - public boolean hasSingleQuotes() { - return true; - } - - @Override - public boolean isList() { - return true; + public String toYaml(List value, Yaml simpleYaml, Yaml singleQuoteYaml) { + String yaml = singleQuoteYaml.dump(value); + // If the property is a non-empty list we need to append a new line because it will be + // something like the following, which requires a new line: + // - 'item 1' + // - 'second item in list' + return value.isEmpty() ? yaml : "\n" + yaml; } } diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index 41b2cf2bd..d01902b57 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableMap; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; +import fr.xephi.authme.settings.properties.TestEnum; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.WrapperMock; import org.bukkit.configuration.file.YamlConfiguration; @@ -48,12 +49,12 @@ public class NewSettingIntegrationTest { Map, Object> expectedValues = ImmutableMap., Object>builder() .put(TestConfiguration.DURATION_IN_SECONDS, 22) .put(TestConfiguration.SYSTEM_NAME, "Custom sys name") - .put(TestConfiguration.RATIO_LIMIT, -4.1) + .put(TestConfiguration.RATIO_ORDER, TestEnum.FIRST) .put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia", "Burundi", "Colombia")) .put(TestConfiguration.VERSION_NUMBER, 2492) .put(TestConfiguration.SKIP_BORING_FEATURES, false) .put(TestConfiguration.BORING_COLORS, Arrays.asList("beige", "gray")) - .put(TestConfiguration.DUST_LEVEL, 0.81) + .put(TestConfiguration.DUST_LEVEL, 2) .put(TestConfiguration.USE_COOL_FEATURES, true) .put(TestConfiguration.COOL_OPTIONS, Arrays.asList("Dinosaurs", "Explosions", "Big trucks")) .build(); @@ -81,12 +82,12 @@ public class NewSettingIntegrationTest { Map, Object> expectedValues = ImmutableMap., Object>builder() .put(TestConfiguration.DURATION_IN_SECONDS, 22) .put(TestConfiguration.SYSTEM_NAME, "[TestDefaultValue]") - .put(TestConfiguration.RATIO_LIMIT, 3.0) + .put(TestConfiguration.RATIO_ORDER, TestEnum.SECOND) .put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia", "Burundi", "Colombia")) .put(TestConfiguration.VERSION_NUMBER, 32046) .put(TestConfiguration.SKIP_BORING_FEATURES, false) .put(TestConfiguration.BORING_COLORS, Collections.EMPTY_LIST) - .put(TestConfiguration.DUST_LEVEL, 0.2) + .put(TestConfiguration.DUST_LEVEL, -1) .put(TestConfiguration.USE_COOL_FEATURES, false) .put(TestConfiguration.COOL_OPTIONS, Arrays.asList("Dinosaurs", "Explosions", "Big trucks")) .build(); @@ -129,12 +130,12 @@ public class NewSettingIntegrationTest { Map, Object> expectedValues = ImmutableMap., Object>builder() .put(TestConfiguration.DURATION_IN_SECONDS, 20) .put(TestConfiguration.SYSTEM_NAME, "A 'test' name") - .put(TestConfiguration.RATIO_LIMIT, -41.8) + .put(TestConfiguration.RATIO_ORDER, TestEnum.FOURTH) .put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia\\", "\tBurundi'", "Colombia?\n''")) .put(TestConfiguration.VERSION_NUMBER, -1337) .put(TestConfiguration.SKIP_BORING_FEATURES, false) .put(TestConfiguration.BORING_COLORS, Arrays.asList("it's a difficult string!", "gray\nwith new lines\n")) - .put(TestConfiguration.DUST_LEVEL, 0.2) + .put(TestConfiguration.DUST_LEVEL, -1) .put(TestConfiguration.USE_COOL_FEATURES, true) .put(TestConfiguration.COOL_OPTIONS, Collections.EMPTY_LIST) .put(additionalProperties.get(0), additionalProperties.get(0).getDefaultValue()) diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java index 232401bf6..8ae651289 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingTest.java @@ -2,6 +2,7 @@ package fr.xephi.authme.settings; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.TestConfiguration; +import fr.xephi.authme.settings.properties.TestEnum; import fr.xephi.authme.settings.propertymap.PropertyMap; import org.bukkit.configuration.file.YamlConfiguration; import org.junit.Test; @@ -37,7 +38,7 @@ public class NewSettingTest { setReturnValue(file, TestConfiguration.VERSION_NUMBER, 20); setReturnValue(file, TestConfiguration.SKIP_BORING_FEATURES, true); - setReturnValue(file, TestConfiguration.RATIO_LIMIT, 4.25); + setReturnValue(file, TestConfiguration.RATIO_ORDER, TestEnum.THIRD); setReturnValue(file, TestConfiguration.SYSTEM_NAME, "myTestSys"); // when / then @@ -45,7 +46,7 @@ public class NewSettingTest { assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20)); assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true)); - assertThat(settings.getProperty(TestConfiguration.RATIO_LIMIT), equalTo(4.25)); + assertThat(settings.getProperty(TestConfiguration.RATIO_ORDER), equalTo(TestEnum.THIRD)); assertThat(settings.getProperty(TestConfiguration.SYSTEM_NAME), equalTo("myTestSys")); assertDefaultValue(TestConfiguration.DURATION_IN_SECONDS, settings); @@ -60,8 +61,8 @@ public class NewSettingTest { when(config.getInt(eq(property.getPath()), anyInt())).thenReturn((Integer) value); } else if (value instanceof Boolean) { when(config.getBoolean(eq(property.getPath()), anyBoolean())).thenReturn((Boolean) value); - } else if (value instanceof Double) { - when(config.getDouble(eq(property.getPath()), anyDouble())).thenReturn((Double) value); + } else if (value instanceof Enum) { + when(config.getString(property.getPath())).thenReturn(((Enum) value).name()); } else { throw new UnsupportedOperationException("Value has unsupported type '" + (value == null ? "null" : value.getClass().getSimpleName()) + "'"); diff --git a/src/test/java/fr/xephi/authme/settings/domain/PropertyTypeTest.java b/src/test/java/fr/xephi/authme/settings/domain/PropertyTypeTest.java index 6dce2ad3e..df0120631 100644 --- a/src/test/java/fr/xephi/authme/settings/domain/PropertyTypeTest.java +++ b/src/test/java/fr/xephi/authme/settings/domain/PropertyTypeTest.java @@ -13,7 +13,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.equalTo; import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyDouble; import static org.mockito.Matchers.anyInt; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; @@ -33,8 +32,6 @@ public class PropertyTypeTest { when(configuration.getBoolean(eq("bool.path.test"), anyBoolean())).thenReturn(true); when(configuration.getBoolean(eq("bool.path.wrong"), anyBoolean())).thenAnswer(secondParameter()); - when(configuration.getDouble(eq("double.path.test"), anyDouble())).thenReturn(-6.4); - when(configuration.getDouble(eq("double.path.wrong"), anyDouble())).thenAnswer(secondParameter()); when(configuration.getInt(eq("int.path.test"), anyInt())).thenReturn(27); when(configuration.getInt(eq("int.path.wrong"), anyInt())).thenAnswer(secondParameter()); when(configuration.getString(eq("str.path.test"), anyString())).thenReturn("Test value"); @@ -69,31 +66,6 @@ public class PropertyTypeTest { assertThat(result, equalTo(true)); } - /* Double */ - @Test - public void shouldGetDoubleValue() { - // given - Property property = Property.newProperty(PropertyType.DOUBLE, "double.path.test", 3.8); - - // when - double result = property.getFromFile(configuration); - - // then - assertThat(result, equalTo(-6.4)); - } - - @Test - public void shouldGetDoubleDefault() { - // given - Property property = Property.newProperty(PropertyType.DOUBLE, "double.path.wrong", 12.0); - - // when - double result = property.getFromFile(configuration); - - // then - assertThat(result, equalTo(12.0)); - } - /* Integer */ @Test public void shouldGetIntValue() { diff --git a/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java b/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java index 449627f2e..dc02e9ccb 100644 --- a/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java +++ b/src/test/java/fr/xephi/authme/settings/properties/TestConfiguration.java @@ -19,8 +19,8 @@ public final class TestConfiguration implements SettingsClass { public static final Property SYSTEM_NAME = newProperty("test.systemName", "[TestDefaultValue]"); - public static final Property RATIO_LIMIT = - newProperty(PropertyType.DOUBLE, "sample.ratio.limit", 3.0); + public static final Property RATIO_ORDER = + newProperty(TestEnum.class, "sample.ratio.order", TestEnum.SECOND); public static final Property> RATIO_FIELDS = newProperty(PropertyType.STRING_LIST, "sample.ratio.fields", "a", "b", "c"); @@ -34,8 +34,8 @@ public final class TestConfiguration implements SettingsClass { public static final Property> BORING_COLORS = newProperty(PropertyType.STRING_LIST, "features.boring.colors"); - public static final Property DUST_LEVEL = - newProperty(PropertyType.DOUBLE, "features.boring.dustLevel", 0.2); + public static final Property DUST_LEVEL = + newProperty(PropertyType.INTEGER, "features.boring.dustLevel", -1); public static final Property USE_COOL_FEATURES = newProperty("features.cool.enabled", false); diff --git a/src/test/java/fr/xephi/authme/settings/properties/TestEnum.java b/src/test/java/fr/xephi/authme/settings/properties/TestEnum.java new file mode 100644 index 000000000..e02d6825a --- /dev/null +++ b/src/test/java/fr/xephi/authme/settings/properties/TestEnum.java @@ -0,0 +1,16 @@ +package fr.xephi.authme.settings.properties; + +/** + * Test enum used in {@link TestConfiguration}. + */ +public enum TestEnum { + + FIRST, + + SECOND, + + THIRD, + + FOURTH + +} diff --git a/src/test/resources/config-difficult-values.yml b/src/test/resources/config-difficult-values.yml index 157971bc5..29bc0e371 100644 --- a/src/test/resources/config-difficult-values.yml +++ b/src/test/resources/config-difficult-values.yml @@ -5,7 +5,7 @@ test: systemName: 'A ''test'' name' sample: ratio: - limit: -41.8 + order: Fourth fields: - Australia\ - ' Burundi''' @@ -23,7 +23,7 @@ features: - | gray with new lines - # dustLevel: 0.81 <-- missing property triggering rewrite + # dustLevel: 8 <-- missing property triggering rewrite cool: enabled: yes options: [] diff --git a/src/test/resources/config-incomplete-sample.yml b/src/test/resources/config-incomplete-sample.yml index a29879720..65990e84d 100644 --- a/src/test/resources/config-incomplete-sample.yml +++ b/src/test/resources/config-incomplete-sample.yml @@ -6,7 +6,7 @@ test: # systemName: 'Custom sys name' sample: ratio: -# limit: 3.0 +# order: 'THIRD' fields: - 'Australia' - 'Burundi' @@ -18,7 +18,7 @@ features: # colors: # - 'beige' # - 'gray' -# dustLevel: 0.81 +# dustLevel: 1 cool: # enabled: true options: diff --git a/src/test/resources/config-sample-values.yml b/src/test/resources/config-sample-values.yml index 1bd99d771..72cdeb790 100644 --- a/src/test/resources/config-sample-values.yml +++ b/src/test/resources/config-sample-values.yml @@ -6,7 +6,7 @@ test: systemName: 'Custom sys name' sample: ratio: - limit: -4.1 + order: 'first' fields: - 'Australia' - 'Burundi' @@ -18,7 +18,7 @@ features: colors: - 'beige' - 'gray' - dustLevel: 0.81 + dustLevel: 2 cool: enabled: true options: From 9653354135e6792693692caab4d2fc41bed09f87 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 31 Jan 2016 18:50:57 +0100 Subject: [PATCH 10/14] #450 Move Settings#getRestrictedIp() --- .../authme/process/join/AsynchronousJoin.java | 38 ++++++++++++++++--- .../fr/xephi/authme/settings/NewSetting.java | 4 +- .../fr/xephi/authme/settings/Settings.java | 37 ------------------ .../settings/SettingsMigrationService.java | 12 +++--- .../settings/NewSettingIntegrationTest.java | 1 - 5 files changed, 39 insertions(+), 53 deletions(-) diff --git a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java index cbdac41eb..2feff435c 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -49,14 +49,14 @@ public class AsynchronousJoin { } public void process() { - if (Settings.checkVeryGames) { - plugin.getVerygamesIp(player); - } - if (Utils.isUnrestricted(player)) { return; } + if (Settings.checkVeryGames) { + plugin.getVerygamesIp(player); + } + if (plugin.ess != null && Settings.disableSocialSpy) { plugin.ess.getUser(player).setSocialSpyEnabled(false); } @@ -64,13 +64,13 @@ public class AsynchronousJoin { final String ip = plugin.getIP(player); - if (Settings.isAllowRestrictedIp && !Settings.getRestrictedIp(name, ip, player.getAddress().getHostName())) { + if (Settings.isAllowRestrictedIp && !isNameRestricted(name, ip, player.getAddress().getHostName())) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { @Override public void run() { AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true); - player.kickPlayer("You are not the Owner of this account, please try another name!"); + player.kickPlayer("You are not the owner of this account. Please try another name!"); if (Settings.banUnsafeIp) plugin.getServer().banIP(ip); } @@ -282,4 +282,30 @@ public class AsynchronousJoin { }); } + /** + * Return whether the name is restricted based on the restriction setting. + * + * @param name The name to check + * @param ip The IP address of the player + * @param domain The hostname of the IP address + * @return True if the name is restricted (IP/domain is not allowed for the given name), + * false if the restrictions are met or if the name has no restrictions to it + */ + private static boolean isNameRestricted(String name, String ip, String domain) { + boolean nameFound = false; + for (String entry : Settings.getRestrictedIp) { + String[] args = entry.split(";"); + String testName = args[0]; + String testIp = args[1]; + if (testName.equalsIgnoreCase(name)) { + nameFound = true; + if ((ip != null && testIp.equals(ip)) + || (domain != null && testIp.equalsIgnoreCase(domain))) { + return false; + } + } + } + return nameFound; + } + } diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 5f393cb96..20ed0952d 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -47,7 +47,7 @@ public class NewSetting { messagesFile = buildMessagesFile(); PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); - if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { + if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) { ConsoleLogger.info("Merged new config options"); ConsoleLogger.info("Please check your config.yml file for new settings!"); save(propertyMap); @@ -67,7 +67,7 @@ public class NewSetting { this.configFile = configFile; this.pluginFolder = new File(""); - if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap)) { + if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) { save(propertyMap); } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 14794965d..7e6b13da4 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -340,43 +340,6 @@ public final class Settings { } } - /** - * Config option for setting and check restricted user by username;ip , - * return false if ip and name doesn't match with player that join the - * server, so player has a restricted access - * - * @param name String - * @param ip String - * @param domain String - * - * @return boolean - */ - public static boolean getRestrictedIp(String name, String ip, String domain) { - - Iterator iterator = getRestrictedIp.iterator(); - boolean trueOnce = false; - boolean nameFound = false; - while (iterator.hasNext()) { - String[] args = iterator.next().split(";"); - String testName = args[0]; - String testIp = args[1]; - if (testName.equalsIgnoreCase(name)) { - nameFound = true; - if (ip != null) { - if (testIp.equalsIgnoreCase(ip)) { - trueOnce = true; - } - } - if (domain != null) { - if (testIp.equalsIgnoreCase(domain)) { - trueOnce = true; - } - } - } - } - return !nameFound || trueOnce; - } - /** * Saves the configuration to disk * diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java index 0691609be..1e010f4c5 100644 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -5,7 +5,6 @@ import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Wrapper; import org.bukkit.configuration.file.FileConfiguration; import java.io.File; @@ -27,22 +26,21 @@ public final class SettingsMigrationService { * * @param configuration The file configuration to check and migrate * @param propertyMap The property map of all existing properties + * @param pluginFolder The plugin folder * @return True if there is a change and the config must be saved, false if the config is up-to-date */ - public static boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap) { - return performMigrations(configuration) || hasDeprecatedProperties(configuration) + public static boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap, File pluginFolder) { + return performMigrations(configuration, pluginFolder) || hasDeprecatedProperties(configuration) || !containsAllSettings(configuration, propertyMap); } - private static boolean performMigrations(FileConfiguration configuration) { + private static boolean performMigrations(FileConfiguration configuration, File pluginFolder) { boolean changes = false; if ("[a-zA-Z0-9_?]*".equals(configuration.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) { configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*"); changes = true; } - // TODO #450: Don't get the data folder statically - Wrapper w = Wrapper.getInstance(); - changes = changes || performMailTextToFileMigration(configuration, w.getDataFolder()); + changes = changes || performMailTextToFileMigration(configuration, pluginFolder); return changes; } diff --git a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java index d01902b57..646c18456 100644 --- a/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/settings/NewSettingIntegrationTest.java @@ -42,7 +42,6 @@ public class NewSettingIntegrationTest { // given YamlConfiguration configuration = YamlConfiguration.loadConfiguration(getConfigFile(COMPLETE_FILE)); File file = new File("unused"); - assumeThat(file.exists(), equalTo(false)); // when / then NewSetting settings = new NewSetting(configuration, file, propertyMap); From 42ae30ed3a86d25c9b0fe91ac39bc0d6ec955842 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sun, 31 Jan 2016 21:22:19 +0100 Subject: [PATCH 11/14] #450 Move Settings#isEmailCorrect to Utils class --- src/main/java/fr/xephi/authme/AuthMe.java | 11 ++- .../executable/authme/SetEmailCommand.java | 4 +- .../executable/register/RegisterCommand.java | 3 +- .../fr/xephi/authme/process/Management.java | 9 +- .../process/email/AsyncChangeEmail.java | 13 ++- .../fr/xephi/authme/settings/Settings.java | 38 +------- src/main/java/fr/xephi/authme/util/Utils.java | 27 ++++++ .../java/fr/xephi/authme/util/UtilsTest.java | 93 +++++++++++++++++++ 8 files changed, 147 insertions(+), 51 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 03a7a6bc0..86f541bb4 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -49,6 +49,8 @@ import fr.xephi.authme.settings.OtherAccounts; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.Spawn; import fr.xephi.authme.settings.properties.DatabaseSettings; +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.CollectionUtils; @@ -292,7 +294,7 @@ public class AuthMe extends JavaPlugin { setupApi(); // Set up the management - management = new Management(this); + management = new Management(this, newSettings); // Set up the BungeeCord hook setupBungeeCordHook(); @@ -339,12 +341,13 @@ public class AuthMe extends JavaPlugin { */ private void showSettingsWarnings() { // Force single session disabled - if (!Settings.isForceSingleSessionEnabled) { + if (!newSettings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) { ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!"); } // Session timeout disabled - if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) { + if (newSettings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0 + && newSettings.getProperty(PluginSettings.SESSIONS_ENABLED)) { ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!"); } } @@ -399,7 +402,7 @@ public class AuthMe extends JavaPlugin { * Set up the BungeeCord hook. */ private void setupBungeeCordHook() { - if (Settings.bungee) { + if (newSettings.getProperty(HooksSettings.BUNGEECORD)) { Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord"); Bukkit.getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeCordMessage(this)); } diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java index 57e3d08e5..ca794bb46 100644 --- a/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/authme/SetEmailCommand.java @@ -5,7 +5,7 @@ import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.command.CommandService; import fr.xephi.authme.command.ExecutableCommand; import fr.xephi.authme.output.MessageKey; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import java.util.List; @@ -20,7 +20,7 @@ public class SetEmailCommand implements ExecutableCommand { final String playerEmail = arguments.get(1); // Validate the email address - if (!Settings.isEmailCorrect(playerEmail)) { + if (!Utils.isEmailCorrect(playerEmail, commandService.getSettings())) { commandService.send(sender, MessageKey.INVALID_EMAIL); return; } diff --git a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java index 8ba9f2cb7..175d067c0 100644 --- a/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java +++ b/src/main/java/fr/xephi/authme/command/executable/register/RegisterCommand.java @@ -6,6 +6,7 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.process.Management; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; import java.util.List; @@ -26,7 +27,7 @@ public class RegisterCommand extends PlayerCommand { return; } final String email = arguments.get(0); - if (!Settings.isEmailCorrect(email)) { + if (!Utils.isEmailCorrect(email, commandService.getSettings())) { commandService.send(player, MessageKey.INVALID_EMAIL); return; } diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 6d262308d..5e62c711b 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -8,6 +8,7 @@ import fr.xephi.authme.process.logout.AsynchronousLogout; import fr.xephi.authme.process.quit.AsynchronousQuit; import fr.xephi.authme.process.register.AsyncRegister; import fr.xephi.authme.process.unregister.AsynchronousUnregister; +import fr.xephi.authme.settings.NewSetting; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitScheduler; @@ -17,15 +18,17 @@ public class Management { private final AuthMe plugin; private final BukkitScheduler sched; + private final NewSetting settings; /** * Constructor for Management. * * @param plugin AuthMe */ - public Management(AuthMe plugin) { + public Management(AuthMe plugin, NewSetting settings) { this.plugin = plugin; this.sched = this.plugin.getServer().getScheduler(); + this.settings = settings; } public void performLogin(final Player player, final String password, final boolean forceLogin) { @@ -94,7 +97,7 @@ public class Management { sched.runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - new AsyncChangeEmail(player, plugin, null, newEmail, newEmailVerify).process(); + new AsyncChangeEmail(player, plugin, null, newEmail, newEmailVerify, settings).process(); } }); } @@ -103,7 +106,7 @@ public class Management { sched.runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { - new AsyncChangeEmail(player, plugin, oldEmail, newEmail).process(); + new AsyncChangeEmail(player, plugin, oldEmail, newEmail, settings).process(); } }); } diff --git a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java index e59aaab89..bd41cf52d 100644 --- a/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java +++ b/src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java @@ -5,8 +5,10 @@ import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.StringUtils; +import fr.xephi.authme.util.Utils; import org.bukkit.entity.Player; /** @@ -19,18 +21,21 @@ public class AsyncChangeEmail { private final String newEmail; private final String newEmailVerify; private final Messages m; + private final NewSetting settings; - public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, String newEmailVerify) { + public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, String newEmailVerify, + NewSetting settings) { this.m = plugin.getMessages(); this.player = player; this.plugin = plugin; this.oldEmail = oldEmail; this.newEmail = newEmail; this.newEmailVerify = newEmailVerify; + this.settings = settings; } - public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail) { - this(player, plugin, oldEmail, newEmail, newEmail); + public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, NewSetting settings) { + this(player, plugin, oldEmail, newEmail, newEmail, settings); } public void process() { @@ -57,7 +62,7 @@ public class AsyncChangeEmail { return; } } - if (!Settings.isEmailCorrect(newEmail)) { + if (!Utils.isEmailCorrect(newEmail, settings)) { m.send(player, MessageKey.INVALID_NEW_EMAIL); return; } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 7e6b13da4..0efe63130 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -361,7 +361,7 @@ public final class Settings { * * @return String */ - public static String checkLang(String lang) { + private static String checkLang(String lang) { if (new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + lang + ".yml").exists()) { ConsoleLogger.info("Set Language to: " + lang); return lang; @@ -420,42 +420,6 @@ public final class Settings { } } - /** - * Method isEmailCorrect. - * - * @param email String - * - * @return boolean - */ - public static boolean isEmailCorrect(String email) { - if (!email.contains("@")) - return false; - if (email.equalsIgnoreCase("your@email.com")) - return false; - String emailDomain = email.split("@")[1]; - boolean correct = true; - if (emailWhitelist != null && !emailWhitelist.isEmpty()) { - for (String domain : emailWhitelist) { - if (!domain.equalsIgnoreCase(emailDomain)) { - correct = false; - } else { - correct = true; - break; - } - } - return correct; - } - if (emailBlacklist != null && !emailBlacklist.isEmpty()) { - for (String domain : emailBlacklist) { - if (domain.equalsIgnoreCase(emailDomain)) { - correct = false; - break; - } - } - } - return correct; - } - /** * Saves current configuration (plus defaults) to disk. *

diff --git a/src/main/java/fr/xephi/authme/util/Utils.java b/src/main/java/fr/xephi/authme/util/Utils.java index 58d296bfa..f12c8b341 100644 --- a/src/main/java/fr/xephi/authme/util/Utils.java +++ b/src/main/java/fr/xephi/authme/util/Utils.java @@ -7,8 +7,10 @@ import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.events.AuthMeTeleportEvent; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.EmailSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; @@ -19,6 +21,7 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.List; /** * Utility class for various operations used in the codebase. @@ -254,6 +257,30 @@ public final class Utils { } } + public static boolean isEmailCorrect(String email, NewSetting settings) { + if (!email.contains("@") || "your@email.com".equalsIgnoreCase(email)) { + return false; + } + final String emailDomain = email.split("@")[1]; + + List whitelist = settings.getProperty(EmailSettings.DOMAIN_WHITELIST); + if (!CollectionUtils.isEmpty(whitelist)) { + return containsIgnoreCase(whitelist, emailDomain); + } + + List blacklist = settings.getProperty(EmailSettings.DOMAIN_BLACKLIST); + return CollectionUtils.isEmpty(blacklist) || !containsIgnoreCase(blacklist, emailDomain); + } + + private static boolean containsIgnoreCase(Collection coll, String needle) { + for (String entry : coll) { + if (entry.equalsIgnoreCase(needle)) { + return true; + } + } + return false; + } + /** */ public enum GroupType { diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index 40769ae53..f6d6827eb 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -3,14 +3,18 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.EmailSettings; import org.bukkit.entity.Player; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; @@ -92,6 +96,95 @@ public class UtilsTest { assertThat(players, hasSize(2)); } + // ---------------- + // Tests for Utils#isEmailCorrect() + // ---------------- + @Test + public void shouldAcceptEmailWithEmptyLists() { + // given + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST); + + // when + boolean result = Utils.isEmailCorrect("test@example.org", settings); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldAcceptEmailWithWhitelist() { + // given + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) + .willReturn(Arrays.asList("domain.tld", "example.com")); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST); + + // when + boolean result = Utils.isEmailCorrect("TesT@Example.com", settings); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldRejectEmailNotInWhitelist() { + // given + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)) + .willReturn(Arrays.asList("domain.tld", "example.com")); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST); + + // when + boolean result = Utils.isEmailCorrect("email@other-domain.abc", settings); + + // then + assertThat(result, equalTo(false)); + } + + @Test + public void shouldAcceptEmailNotInBlacklist() { + // given + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) + .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); + + // when + boolean result = Utils.isEmailCorrect("sample@valid-name.tld", settings); + + // then + assertThat(result, equalTo(true)); + } + + @Test + public void shouldRejectEmailInBlacklist() { + // given + NewSetting settings = mock(NewSetting.class); + given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST); + given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)) + .willReturn(Arrays.asList("Example.org", "a-test-name.tld")); + + // when + boolean result = Utils.isEmailCorrect("sample@a-Test-name.tld", settings); + + // then + assertThat(result, equalTo(false)); + } + + @Test + public void shouldRejectInvalidEmail() { + // given/when/then + assertThat(Utils.isEmailCorrect("invalidinput", mock(NewSetting.class)), equalTo(false)); + } + + @Test + public void shouldRejectDefaultEmail() { + // given/when/then + assertThat(Utils.isEmailCorrect("your@email.com", mock(NewSetting.class)), equalTo(false)); + } + // Note: This method is used through reflections @SuppressWarnings("unused") public static Player[] onlinePlayersImpl() { From 3e30a3471446991457bd1e43048461fb7e49bb7c Mon Sep 17 00:00:00 2001 From: ljacqu Date: Wed, 3 Feb 2016 22:36:01 +0100 Subject: [PATCH 12/14] #450 Move Settings#loadEmailText and #getWelcomeMessage --- src/main/java/fr/xephi/authme/AuthMe.java | 11 +- .../fr/xephi/authme/mail/SendMailSSL.java | 102 +++++++++--------- .../fr/xephi/authme/process/Management.java | 5 +- .../process/login/AsynchronousLogin.java | 43 +++----- .../process/login/ProcessSyncPlayerLogin.java | 32 +++--- .../process/register/AsyncRegister.java | 8 +- .../register/ProcessSyncPasswordRegister.java | 34 +++--- .../fr/xephi/authme/settings/NewSetting.java | 64 +++++++++++ .../fr/xephi/authme/settings/Settings.java | 65 +---------- 9 files changed, 183 insertions(+), 181 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 86f541bb4..b44a581c2 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -86,6 +86,8 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.logging.Level; import java.util.logging.Logger; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT; +import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD; import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER; /** @@ -328,12 +330,9 @@ public class AuthMe extends JavaPlugin { */ private void setupMailApi() { // Make sure the mail API is enabled - if (Settings.getmailAccount.isEmpty() || Settings.getmailPassword.isEmpty()) { - return; + if (!newSettings.getProperty(MAIL_ACCOUNT).isEmpty() && !newSettings.getProperty(MAIL_PASSWORD).isEmpty()) { + this.mail = new SendMailSSL(this, newSettings); } - - // Set up the mail API - this.mail = new SendMailSSL(this); } /** @@ -483,7 +482,7 @@ public class AuthMe extends JavaPlugin { Graph databaseBackend = metrics.createGraph("Database backend"); // Custom graphs - if (Settings.messageFile.exists()) { + if (newSettings.getMessagesFile().exists()) { messagesLanguage.addPlotter(new Metrics.Plotter(Settings.messagesLanguage) { @Override diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index 692497d0d..8279b8dfa 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -1,25 +1,26 @@ package fr.xephi.authme.mail; -import java.io.File; -import java.io.IOException; -import java.security.Security; -import java.util.Properties; - -import javax.activation.DataSource; -import javax.activation.FileDataSource; -import javax.imageio.ImageIO; -import javax.mail.Session; - -import org.apache.commons.mail.EmailException; -import org.apache.commons.mail.HtmlEmail; -import org.bukkit.Bukkit; - import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.ImageGenerator; import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.util.StringUtils; +import org.apache.commons.mail.EmailConstants; +import org.apache.commons.mail.EmailException; +import org.apache.commons.mail.HtmlEmail; +import org.bukkit.Bukkit; + +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.imageio.ImageIO; +import javax.mail.Session; +import java.io.File; +import java.io.IOException; +import java.security.Security; +import java.util.Properties; + /** * @author Xephi59 @@ -27,13 +28,15 @@ import fr.xephi.authme.util.StringUtils; public class SendMailSSL { private final AuthMe plugin; + private final NewSetting settings; - public SendMailSSL(AuthMe plugin) { + public SendMailSSL(AuthMe plugin, NewSetting settings) { this.plugin = plugin; + this.settings = settings; } public void main(final PlayerAuth auth, final String newPass) { - final String mailText = replaceMailTags(Settings.getMailText, plugin, auth, newPass); + final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass); Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override @@ -41,21 +44,23 @@ public class SendMailSSL { Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); HtmlEmail email; try { - email = initializeMail(auth); + email = initializeMail(auth, settings); } catch (EmailException e) { - ConsoleLogger.showError("Failed to create email with the given settings: " + StringUtils.formatException(e)); + ConsoleLogger.showError("Failed to create email with the given settings: " + + StringUtils.formatException(e)); return; } String content = mailText; // Generate an image? File file = null; - if (Settings.generateImage) { + if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) { try { file = generateImage(auth, plugin, newPass); content = embedImageIntoEmailContent(file, email, content); } catch (IOException | EmailException e) { - ConsoleLogger.showError("Unable to send new password as image for email " + auth.getEmail() + ": " + StringUtils.formatException(e)); + ConsoleLogger.showError("Unable to send new password as image for email " + auth.getEmail() + + ": " + StringUtils.formatException(e)); } } @@ -68,43 +73,39 @@ public class SendMailSSL { }); } - private static File generateImage(PlayerAuth auth, AuthMe plugin, - String newPass) throws IOException { + private static File generateImage(PlayerAuth auth, AuthMe plugin, String newPass) throws IOException { ImageGenerator gen = new ImageGenerator(newPass); - File file = new File(plugin.getDataFolder() + File.separator + auth.getNickname() + "_new_pass.jpg"); + File file = new File(plugin.getDataFolder(), auth.getNickname() + "_new_pass.jpg"); ImageIO.write(gen.generateImage(), "jpg", file); return file; } - private static String embedImageIntoEmailContent(File image, - HtmlEmail email, String content) throws EmailException { + private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content) + throws EmailException { DataSource source = new FileDataSource(image); String tag = email.embed(source, image.getName()); return content.replace("", ""); } - private static HtmlEmail initializeMail(PlayerAuth auth) + private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings) throws EmailException { - String senderName; - if (StringUtils.isEmpty(Settings.getmailSenderName)) { - senderName = Settings.getmailAccount; - } else { - senderName = Settings.getmailSenderName; - } - String senderMail = Settings.getmailAccount; - String mailPassword = Settings.getmailPassword; - int port = Settings.getMailPort; + String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT); + String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME)) + ? senderMail + : settings.getProperty(EmailSettings.MAIL_SENDER_NAME); + String mailPassword = settings.getProperty(EmailSettings.MAIL_PASSWORD); + int port = settings.getProperty(EmailSettings.SMTP_PORT); HtmlEmail email = new HtmlEmail(); - email.setCharset(org.apache.commons.mail.EmailConstants.UTF_8); + email.setCharset(EmailConstants.UTF_8); email.setSmtpPort(port); - email.setHostName(Settings.getmailSMTP); + email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST)); email.addTo(auth.getEmail()); email.setFrom(senderMail, senderName); - email.setSubject(Settings.getMailSubject); + email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT)); email.setAuthentication(senderMail, mailPassword); - setPropertiesForPort(email, port); + setPropertiesForPort(email, port, settings); return email; } @@ -113,7 +114,8 @@ public class SendMailSSL { email.setHtmlMsg(content); email.setTextMsg(content); } catch (EmailException e) { - ConsoleLogger.showError("Your email.html config contains an error and cannot be sent: " + StringUtils.formatException(e)); + ConsoleLogger.showError("Your email.html config contains an error and cannot be sent: " + + StringUtils.formatException(e)); return false; } try { @@ -125,17 +127,19 @@ public class SendMailSSL { } } - private static String replaceMailTags(String mailText, AuthMe plugin, - PlayerAuth auth, String newPass) { - return mailText.replace("", auth.getNickname()).replace("", plugin.getServer().getServerName()).replace("", newPass); + private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) { + return mailText + .replace("", auth.getNickname()) + .replace("", plugin.getServer().getServerName()) + .replace("", newPass); } - @SuppressWarnings("deprecation") - private static void setPropertiesForPort(HtmlEmail email, int port) + private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings) throws EmailException { switch (port) { case 587: - if (!Settings.emailOauth2Token.isEmpty()) { + String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN); + if (!oAuth2Token.isEmpty()) { if (Security.getProvider("Google OAuth2 Provider") == null) { Security.addProvider(new OAuth2Provider()); } @@ -146,7 +150,7 @@ public class SendMailSSL { mailProperties.setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2"); mailProperties.setProperty("mail.smtp.auth.login.disable", "true"); mailProperties.setProperty("mail.smtp.auth.plain.disable", "true"); - mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, Settings.emailOauth2Token); + mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oAuth2Token); email.setMailSession(Session.getInstance(mailProperties)); } else { email.setStartTLSEnabled(true); @@ -159,7 +163,7 @@ public class SendMailSSL { email.setSSLCheckServerIdentity(true); break; case 465: - email.setSslSmtpPort("" + port); + email.setSslSmtpPort(Integer.toString(port)); email.setSSL(true); break; default: diff --git a/src/main/java/fr/xephi/authme/process/Management.java b/src/main/java/fr/xephi/authme/process/Management.java index 5e62c711b..80971e9cf 100644 --- a/src/main/java/fr/xephi/authme/process/Management.java +++ b/src/main/java/fr/xephi/authme/process/Management.java @@ -36,7 +36,8 @@ public class Management { @Override public void run() { - new AsynchronousLogin(player, password, forceLogin, plugin, plugin.getDataSource()).process(); + new AsynchronousLogin(player, password, forceLogin, plugin, plugin.getDataSource(), settings) + .process(); } }); } @@ -56,7 +57,7 @@ public class Management { @Override public void run() { - new AsyncRegister(player, password, email, plugin, plugin.getDataSource()).process(); + new AsyncRegister(player, password, email, plugin, plugin.getDataSource(), settings).process(); } }); } diff --git a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java index 7109840f4..f2c3660e1 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -11,8 +11,11 @@ import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.task.MessageTask; +import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Utils; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -34,6 +37,7 @@ public class AsynchronousLogin { private final DataSource database; private final Messages m; private final String ip; + private final NewSetting settings; /** * Constructor for AsynchronousLogin. @@ -43,8 +47,10 @@ public class AsynchronousLogin { * @param forceLogin boolean * @param plugin AuthMe * @param data DataSource + * @param settings The settings */ - public AsynchronousLogin(Player player, String password, boolean forceLogin, AuthMe plugin, DataSource data) { + public AsynchronousLogin(Player player, String password, boolean forceLogin, AuthMe plugin, DataSource data, + NewSetting settings) { this.m = plugin.getMessages(); this.player = player; this.name = player.getName().toLowerCase(); @@ -54,6 +60,7 @@ public class AsynchronousLogin { this.plugin = plugin; this.database = data; this.ip = plugin.getIP(player); + this.settings = settings; } protected boolean needsCaptcha() { @@ -98,7 +105,7 @@ public class AsynchronousLogin { msg = m.retrieve(MessageKey.REGISTER_MESSAGE); } BukkitTask msgT = Bukkit.getScheduler().runTaskAsynchronously(plugin, - new MessageTask(plugin, name, msg, Settings.getWarnMessageInterval)); + new MessageTask(plugin, name, msg, settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL))); LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT); } return null; @@ -165,12 +172,10 @@ public class AsynchronousLogin { if (!forceLogin) m.send(player, MessageKey.LOGIN_SUCCESS); - displayOtherAccounts(auth, player); + displayOtherAccounts(auth); - if (Settings.recallEmail) { - if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) { - m.send(player, MessageKey.EMAIL_ADDED_SUCCESS); - } + if (Settings.recallEmail && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) { + m.send(player, MessageKey.EMAIL_ADDED_SUCCESS); } if (!Settings.noConsoleSpam) { @@ -186,7 +191,7 @@ public class AsynchronousLogin { // task, we schedule it in the end // so that we can be sure, and have not to care if it might be // processed in other order. - ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database); + ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database, settings); if (syncPlayerLogin.getLimbo() != null) { if (syncPlayerLogin.getLimbo().getTimeoutTaskId() != null) { syncPlayerLogin.getLimbo().getTimeoutTaskId().cancel(); @@ -215,7 +220,7 @@ public class AsynchronousLogin { } } - public void displayOtherAccounts(PlayerAuth auth, Player p) { + public void displayOtherAccounts(PlayerAuth auth) { if (!Settings.displayOtherAccounts) { return; } @@ -223,30 +228,16 @@ public class AsynchronousLogin { return; } List auths = this.database.getAllAuthsByName(auth); - if (auths.isEmpty()) { + if (auths.isEmpty() || auths.size() == 1) { return; } - if (auths.size() == 1) { - return; - } - StringBuilder message = new StringBuilder("[AuthMe] "); - int i = 0; - for (String account : auths) { - i++; - message.append(account); - if (i != auths.size()) { - message.append(", "); - } else { - message.append('.'); - } - } - + String message = "[AuthMe] " + StringUtils.join(", ", auths) + "."; for (Player player : Utils.getOnlinePlayers()) { if (plugin.getPermissionsManager().hasPermission(player, PlayerPermission.SEE_OTHER_ACCOUNTS) || (player.getName().equals(this.player.getName()) && plugin.getPermissionsManager().hasPermission(player, PlayerPermission.SEE_OWN_ACCOUNTS))) { player.sendMessage("[AuthMe] The player " + auth.getNickname() + " has " + auths.size() + " accounts"); - player.sendMessage(message.toString()); + player.sendMessage(message); } } } diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index 27c09174e..07c5b6d40 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -1,5 +1,7 @@ package fr.xephi.authme.process.login; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; @@ -24,6 +26,8 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.Utils; import fr.xephi.authme.util.Utils.GroupType; +import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN; + /** */ public class ProcessSyncPlayerLogin implements Runnable { @@ -36,24 +40,26 @@ public class ProcessSyncPlayerLogin implements Runnable { private final DataSource database; private final PluginManager pm; private final JsonCache playerCache; + private final NewSetting settings; /** * Constructor for ProcessSyncPlayerLogin. * * @param player Player * @param plugin AuthMe - * @param data DataSource + * @param database DataSource */ public ProcessSyncPlayerLogin(Player player, AuthMe plugin, - DataSource data) { + DataSource database, NewSetting settings) { this.plugin = plugin; - this.database = data; + this.database = database; this.pm = plugin.getServer().getPluginManager(); this.player = player; this.name = player.getName().toLowerCase(); this.limbo = LimboCache.getInstance().getLimboPlayer(name); this.auth = database.getAuth(name); this.playerCache = new JsonCache(); + this.settings = settings; } /** @@ -152,7 +158,7 @@ public class ProcessSyncPlayerLogin implements Runnable { } } - if (Settings.protectInventoryBeforeLogInEnabled) { + if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) { restoreInventory(); } @@ -188,27 +194,27 @@ public class ProcessSyncPlayerLogin implements Runnable { // Login is finish, display welcome message if we use email registration if (Settings.useWelcomeMessage && Settings.emailRegistration) if (Settings.broadcastWelcomeMessage) { - for (String s : Settings.welcomeMsg) { + for (String s : settings.getWelcomeMessage()) { Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); } } else { - for (String s : Settings.welcomeMsg) { + for (String s : settings.getWelcomeMessage()) { player.sendMessage(plugin.replaceAllInfo(s, player)); } } - // Login is now finish , we can force all commands + // Login is now finished; we can force all commands forceCommands(); sendTo(); } private void sendTo() { - if (Settings.sendPlayerTo.isEmpty()) - return; - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("Connect"); - out.writeUTF(Settings.sendPlayerTo); - player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Connect"); + out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER)); + player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + } } } diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java index d1b1f900d..60d3da15b 100644 --- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java @@ -9,6 +9,7 @@ import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.output.Messages; import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.NewSetting; import fr.xephi.authme.settings.Settings; import org.bukkit.entity.Player; @@ -24,8 +25,10 @@ public class AsyncRegister { private final AuthMe plugin; private final DataSource database; private final Messages m; + private final NewSetting settings; - public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data) { + public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data, + NewSetting settings) { this.m = plugin.getMessages(); this.player = player; this.password = password; @@ -34,6 +37,7 @@ public class AsyncRegister { this.plugin = plugin; this.database = data; this.ip = plugin.getIP(player); + this.settings = settings; } private boolean preRegisterCheck() throws Exception { @@ -137,7 +141,7 @@ public class AsyncRegister { plugin.getManagement().performLogin(player, "dontneed", true); } plugin.otherAccounts.addPlayer(player.getUniqueId()); - ProcessSyncPasswordRegister sync = new ProcessSyncPasswordRegister(player, plugin); + ProcessSyncPasswordRegister sync = new ProcessSyncPasswordRegister(player, plugin, settings); plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, sync); } } diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java index 1b4b0555e..6d875ee0f 100644 --- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java +++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java @@ -1,5 +1,7 @@ package fr.xephi.authme.process.register; +import fr.xephi.authme.settings.NewSetting; +import fr.xephi.authme.settings.properties.HooksSettings; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.potion.PotionEffectType; @@ -30,6 +32,7 @@ public class ProcessSyncPasswordRegister implements Runnable { protected final String name; private final AuthMe plugin; private final Messages m; + private final NewSetting settings; /** * Constructor for ProcessSyncPasswordRegister. @@ -37,11 +40,12 @@ public class ProcessSyncPasswordRegister implements Runnable { * @param player Player * @param plugin AuthMe */ - public ProcessSyncPasswordRegister(Player player, AuthMe plugin) { + public ProcessSyncPasswordRegister(Player player, AuthMe plugin, NewSetting settings) { this.m = plugin.getMessages(); this.player = player; this.name = player.getName().toLowerCase(); this.plugin = plugin; + this.settings = settings; } private void sendBungeeMessage() { @@ -63,11 +67,6 @@ public class ProcessSyncPasswordRegister implements Runnable { } } - /** - * Method forceLogin. - * - * @param player Player - */ private void forceLogin(Player player) { Utils.teleportToSpawn(player); LimboCache cache = LimboCache.getInstance(); @@ -88,11 +87,6 @@ public class ProcessSyncPasswordRegister implements Runnable { } } - /** - * Method run. - * - * @see java.lang.Runnable#run() - */ @Override public void run() { LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name); @@ -141,11 +135,11 @@ public class ProcessSyncPasswordRegister implements Runnable { // Register is finish and player is logged, display welcome message if (Settings.useWelcomeMessage) { if (Settings.broadcastWelcomeMessage) { - for (String s : Settings.welcomeMsg) { + for (String s : settings.getWelcomeMessage()) { plugin.getServer().broadcastMessage(plugin.replaceAllInfo(s, player)); } } else { - for (String s : Settings.welcomeMsg) { + for (String s : settings.getWelcomeMessage()) { player.sendMessage(plugin.replaceAllInfo(s, player)); } } @@ -161,18 +155,18 @@ public class ProcessSyncPasswordRegister implements Runnable { sendBungeeMessage(); } - // Register is now finish , we can force all commands + // Register is now finished; we can force all commands forceCommands(); sendTo(); } private void sendTo() { - if (Settings.sendPlayerTo.isEmpty()) - return; - ByteArrayDataOutput out = ByteStreams.newDataOutput(); - out.writeUTF("Connect"); - out.writeUTF(Settings.sendPlayerTo); - player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) { + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF("Connect"); + out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER)); + player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray()); + } } } diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 20ed0952d..1361f2274 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -1,9 +1,11 @@ package fr.xephi.authme.settings; import com.google.common.annotations.VisibleForTesting; +import com.google.common.io.Files; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.properties.PluginSettings; +import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.SettingsFieldRetriever; import fr.xephi.authme.settings.propertymap.PropertyMap; import fr.xephi.authme.util.CollectionUtils; @@ -16,6 +18,7 @@ import org.yaml.snakeyaml.Yaml; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -31,7 +34,10 @@ public class NewSetting { private final File pluginFolder; private final File configFile; private FileConfiguration configuration; + /** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */ private File messagesFile; + private List welcomeMessage; + private String emailMessage; /** * Constructor. Checks the given {@link FileConfiguration} object for completeness. @@ -45,6 +51,8 @@ public class NewSetting { this.configFile = configFile; this.pluginFolder = pluginFolder; messagesFile = buildMessagesFile(); + welcomeMessage = readWelcomeMessage(); + emailMessage = readEmailMessage(); PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) { @@ -110,6 +118,14 @@ public class NewSetting { return messagesFile; } + public String getEmailMessage() { + return emailMessage; + } + + public List getWelcomeMessage() { + return welcomeMessage; + } + /** * Reload the configuration. */ @@ -189,6 +205,54 @@ public class NewSetting { makePath("messages", "messages_" + language + ".yml")); } + private List readWelcomeMessage() { + if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { + final File welcomeFile = new File(pluginFolder, "welcome.txt"); + final Charset charset = Charset.forName("UTF-8"); + if (!welcomeFile.exists()) { + try { + Files.write( + "Welcome {PLAYER} to {SERVER} server\n\nThis server uses AuthMe protection!", + welcomeFile, charset); + } catch (IOException e) { + ConsoleLogger.showError("Failed to create file '" + welcomeFile.getPath() + "': " + + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } + } + try { + return Files.readLines(welcomeFile, charset); + } catch (IOException e) { + ConsoleLogger.showError("Failed to read file '" + welcomeFile.getPath() + "': " + + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } + } + return new ArrayList<>(0); + } + + private String readEmailMessage() { + final File emailFile = new File(pluginFolder, "email.txt"); + final Charset charset = Charset.forName("UTF-8"); + if (!emailFile.exists()) { + try { + Files.write("", emailFile, charset); + } catch (IOException e) { + ConsoleLogger.showError("Failed to create file '" + emailFile.getPath() + "': " + + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } + } + try { + return StringUtils.join("", Files.readLines(emailFile, charset)); + } catch (IOException e) { + ConsoleLogger.showError("Failed to read file '" + emailFile.getPath() + "': " + + StringUtils.formatException(e)); + ConsoleLogger.writeStackTrace(e); + } + return ""; + } + private static Yaml newYaml(boolean useSingleQuotes) { DumperOptions options = new DumperOptions(); options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 30fd3055d..2ef204423 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -1,13 +1,10 @@ package fr.xephi.authme.settings; -import com.google.common.base.Charsets; -import com.google.common.io.Files; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource.DataSourceType; import fr.xephi.authme.security.HashAlgorithm; -import fr.xephi.authme.util.StringUtils; import fr.xephi.authme.util.Wrapper; import org.bukkit.configuration.file.YamlConfiguration; @@ -30,12 +27,10 @@ public final class Settings { public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder(); public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules"); public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache"); - private static final File EMAIL_FILE = new File(PLUGIN_FOLDER, "email.html"); private static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml"); public static final File LOG_FILE = new File(PLUGIN_FOLDER, "authme.log"); // This is not an option! public static boolean antiBotInAction = false; - public static File messageFile; public static List allowCommands; public static List getJoinPermissions; public static List getUnrestrictedName; @@ -48,7 +43,6 @@ public final class Settings { public static List forceCommandsAsConsole; public static List forceRegisterCommands; public static List forceRegisterCommandsAsConsole; - public static List welcomeMsg; public static List unsafePasswords; public static List emailBlacklist; public static List emailWhitelist; @@ -85,11 +79,10 @@ public final class Settings { backupWindowsPath, getRegisteredGroup, messagesLanguage, getMySQLlastlocX, getMySQLlastlocY, getMySQLlastlocZ, rakamakUsers, rakamakUsersIp, getmailAccount, - getmailPassword, getmailSMTP, getMySQLColumnId, getmailSenderName, - getMailSubject, getMailText, getMySQLlastlocWorld, defaultWorld, + getMySQLColumnId, getMySQLlastlocWorld, defaultWorld, getPhpbbPrefix, getWordPressPrefix, getMySQLColumnLogged, spawnPriority, crazyloginFileName, getPassRegex, - getMySQLColumnRealName, emailOauth2Token, sendPlayerTo; + getMySQLColumnRealName, sendPlayerTo; public static int getWarnMessageInterval, getSessionTimeout, getRegistrationTimeout, getMaxNickLength, getMinNickLength, getPasswordMinLen, getMovementRadius, getmaxRegPerIp, @@ -129,7 +122,6 @@ public final class Settings { if (exist) { instance.saveDefaults(); } - messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml"); } public static void loadVariables() { @@ -217,19 +209,14 @@ public final class Settings { noConsoleSpam = configFile.getBoolean("Security.console.noConsoleSpam", false); removePassword = configFile.getBoolean("Security.console.removePassword", true); getmailAccount = configFile.getString("Email.mailAccount", ""); - getmailPassword = configFile.getString("Email.mailPassword", ""); - getmailSMTP = configFile.getString("Email.mailSMTP", "smtp.gmail.com"); getMailPort = configFile.getInt("Email.mailPort", 465); getRecoveryPassLength = configFile.getInt("Email.RecoveryPasswordLength", 8); getMySQLOtherUsernameColumn = configFile.getStringList("ExternalBoardOptions.mySQLOtherUsernameColumns"); displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true); getMySQLColumnId = configFile.getString("DataSource.mySQLColumnId", "id"); - getmailSenderName = configFile.getString("Email.mailSenderName", ""); useCaptcha = configFile.getBoolean("Security.captcha.useCaptcha", false); maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5); captchaLength = configFile.getInt("Security.captcha.captchaLength", 5); - getMailSubject = configFile.getString("Email.mailSubject", "Your new AuthMe Password"); - getMailText = loadEmailText(); emailRegistration = configFile.getBoolean("settings.registration.enableEmailRegistrationSystem", false); saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8); getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1); @@ -288,25 +275,8 @@ public final class Settings { generateImage = configFile.getBoolean("Email.generateImage", false); preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); - emailOauth2Token = configFile.getString("Email.emailOauth2Token", ""); sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", ""); - // Load the welcome message - getWelcomeMessage(); - - } - - private static String loadEmailText() { - if (!EMAIL_FILE.exists()) { - plugin.saveResource("email.html", false); - } - try { - return Files.toString(EMAIL_FILE, Charsets.UTF_8); - } catch (IOException e) { - ConsoleLogger.showError("Error loading email text: " + StringUtils.formatException(e)); - ConsoleLogger.writeStackTrace(e); - return ""; - } } /** @@ -388,37 +358,6 @@ public final class Settings { } } - private static void getWelcomeMessage() { - AuthMe plugin = AuthMe.getInstance(); - welcomeMsg = new ArrayList<>(); - if (!useWelcomeMessage) { - return; - } - if (!(new File(plugin.getDataFolder() + File.separator + "welcome.txt").exists())) { - try { - FileWriter fw = new FileWriter(plugin.getDataFolder() + File.separator + "welcome.txt", true); - BufferedWriter w = new BufferedWriter(fw); - w.write("Welcome {PLAYER} on {SERVER} server"); - w.newLine(); - w.write("This server uses " + AuthMe.getPluginName() + " protection!"); - w.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - try { - FileReader fr = new FileReader(plugin.getDataFolder() + File.separator + "welcome.txt"); - BufferedReader br = new BufferedReader(fr); - String line; - while ((line = br.readLine()) != null) { - welcomeMsg.add(line); - } - br.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - /** * Saves current configuration (plus defaults) to disk. *

From ab719c4204e4f4800b1873127f4768ec5c8ea8dd Mon Sep 17 00:00:00 2001 From: ljacqu Date: Fri, 5 Feb 2016 22:30:57 +0100 Subject: [PATCH 13/14] Minor - remove messages language from old settings --- src/main/java/fr/xephi/authme/AuthMe.java | 47 +++++++++---------- .../fr/xephi/authme/settings/Settings.java | 7 +-- 2 files changed, 22 insertions(+), 32 deletions(-) diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index b44a581c2..9dc1d6857 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -178,15 +178,6 @@ public class AuthMe extends JavaPlugin { return pluginBuildNumber; } - /** - * Get the plugin's Settings. - * - * @return Plugin's settings. - */ - public Settings getSettings() { - return settings; - } - /** * Get the Messages instance. * @@ -478,12 +469,13 @@ public class AuthMe extends JavaPlugin { private void setupMetrics() { try { Metrics metrics = new Metrics(this); - Graph messagesLanguage = metrics.createGraph("Messages language"); - Graph databaseBackend = metrics.createGraph("Database backend"); + Graph languageGraph = metrics.createGraph("Messages language"); + Graph backendGraph = metrics.createGraph("Database backend"); // Custom graphs if (newSettings.getMessagesFile().exists()) { - messagesLanguage.addPlotter(new Metrics.Plotter(Settings.messagesLanguage) { + String messagesLanguage = newSettings.getProperty(PluginSettings.MESSAGES_LANGUAGE); + languageGraph.addPlotter(new Metrics.Plotter(messagesLanguage) { @Override public int getValue() { @@ -491,7 +483,9 @@ public class AuthMe extends JavaPlugin { } }); } - databaseBackend.addPlotter(new Metrics.Plotter(Settings.getDataSource.toString()) { + + DataSource.DataSourceType dataSource = newSettings.getProperty(DatabaseSettings.BACKEND); + backendGraph.addPlotter(new Metrics.Plotter(dataSource.toString()) { @Override public int getValue() { @@ -503,8 +497,9 @@ public class AuthMe extends JavaPlugin { ConsoleLogger.info("Metrics started successfully!"); } catch (Exception e) { // Failed to submit the metrics data + ConsoleLogger.showError("Can't start Metrics! The plugin will work anyway... (Encountered " + + StringUtils.formatException(e) + ")"); ConsoleLogger.writeStackTrace(e); - ConsoleLogger.showError("Can't start Metrics! The plugin will work anyway..."); } } @@ -884,18 +879,18 @@ public class AuthMe extends JavaPlugin { } public String replaceAllInfo(String message, Player player) { - int playersOnline = Utils.getOnlinePlayers().size(); - message = message.replace("&", "\u00a7"); - message = message.replace("{PLAYER}", player.getName()); - message = message.replace("{ONLINE}", "" + playersOnline); - message = message.replace("{MAXPLAYERS}", "" + server.getMaxPlayers()); - message = message.replace("{IP}", getIP(player)); - message = message.replace("{LOGINS}", "" + PlayerCache.getInstance().getLogged()); - message = message.replace("{WORLD}", player.getWorld().getName()); - message = message.replace("{SERVER}", server.getServerName()); - message = message.replace("{VERSION}", server.getBukkitVersion()); - message = message.replace("{COUNTRY}", GeoLiteAPI.getCountryName(getIP(player))); - return message; + String playersOnline = Integer.toString(Utils.getOnlinePlayers().size()); + return message + .replace("&", "\u00a7") + .replace("{PLAYER}", player.getName()) + .replace("{ONLINE}", playersOnline) + .replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers())) + .replace("{IP}", getIP(player)) + .replace("{LOGINS}", Integer.toString(PlayerCache.getInstance().getLogged())) + .replace("{WORLD}", player.getWorld().getName()) + .replace("{SERVER}", server.getServerName()) + .replace("{VERSION}", server.getBukkitVersion()) + .replace("{COUNTRY}", GeoLiteAPI.getCountryName(getIP(player))); } /** diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 2ef204423..c745cf845 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -8,11 +8,7 @@ import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.util.Wrapper; import org.bukkit.configuration.file.YamlConfiguration; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; @@ -77,7 +73,7 @@ public final class Settings { getMySQLColumnIp, getMySQLColumnLastLogin, getMySQLColumnSalt, getMySQLColumnGroup, getMySQLColumnEmail, unRegisteredGroup, backupWindowsPath, getRegisteredGroup, - messagesLanguage, getMySQLlastlocX, getMySQLlastlocY, + getMySQLlastlocX, getMySQLlastlocY, getMySQLlastlocZ, rakamakUsers, rakamakUsersIp, getmailAccount, getMySQLColumnId, getMySQLlastlocWorld, defaultWorld, getPhpbbPrefix, getWordPressPrefix, getMySQLColumnLogged, @@ -125,7 +121,6 @@ public final class Settings { } public static void loadVariables() { - messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage", "en").toLowerCase()); isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false); isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true); isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true); From 99b7b80f1dae79d79f71a5c3b56bfcae8bcf6098 Mon Sep 17 00:00:00 2001 From: ljacqu Date: Sat, 6 Feb 2016 17:10:00 +0100 Subject: [PATCH 14/14] #450 Fix copying of JAR files to plugin folder - Create SettingsMigrationService#copyFileFromResource (inspired from CustomSettings) - Use new method to copy missing files in plugin folder from JAR - Create YamlFileConfiguration inside NewSetting: FileConfiguration object provided by JavaPlugin#getConfig() sets default values from the JAR's config.yml :( - Change ConsoleLogger to take logger from plugin (work in progress) --- pom.xml | 1 + src/main/java/fr/xephi/authme/AuthMe.java | 18 ++++- .../java/fr/xephi/authme/ConsoleLogger.java | 30 ++++--- .../fr/xephi/authme/settings/NewSetting.java | 78 ++++++++----------- .../fr/xephi/authme/settings/Settings.java | 23 +----- .../settings/SettingsMigrationService.java | 47 ++++++++++- src/main/resources/welcome.txt | 3 + .../authme/ConsoleLoggerTestInitializer.java | 20 +++++ .../xephi/authme/output/Log4JFilterTest.java | 4 +- .../output/MessagesIntegrationTest.java | 10 ++- .../authme/security/crypts/BcryptTest.java | 2 + .../authme/security/crypts/XFBCRYPTTest.java | 4 +- .../java/fr/xephi/authme/util/UtilsTest.java | 2 + 13 files changed, 156 insertions(+), 86 deletions(-) create mode 100644 src/main/resources/welcome.txt create mode 100644 src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java diff --git a/pom.xml b/pom.xml index 7a77f60ff..9bbbd39b5 100644 --- a/pom.xml +++ b/pom.xml @@ -97,6 +97,7 @@ src/main/resources/ email.html + welcome.txt diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 980e3e955..c5a26048c 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -13,6 +13,7 @@ import java.util.logging.Logger; import com.google.common.base.Charsets; import com.google.common.io.Resources; +import fr.xephi.authme.settings.SettingsMigrationService; import org.apache.logging.log4j.LogManager; import org.bukkit.Bukkit; @@ -207,11 +208,21 @@ public class AuthMe extends JavaPlugin { // Set various instances server = getServer(); plugin = this; + ConsoleLogger.setLogger(getLogger()); setPluginInfos(); // Load settings and custom configurations, if it fails, stop the server due to security reasons. newSettings = createNewSetting(); + if (newSettings == null) { + ConsoleLogger.showError("Could not load configuration. Aborting."); + server.shutdown(); + return; + } + ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING), + new File(getDataFolder(), "authme.log")); + + // Old settings manager if (!loadSettings()) { server.shutdown(); setEnabled(false); @@ -425,7 +436,6 @@ public class AuthMe extends JavaPlugin { private boolean loadSettings() { try { settings = new Settings(this); - Settings.reload(); return true; } catch (Exception e) { ConsoleLogger.logException("Can't load the configuration file... Something went wrong. " @@ -436,8 +446,10 @@ public class AuthMe extends JavaPlugin { } private NewSetting createNewSetting() { - File configFile = new File(getDataFolder() + "config.yml"); - return new NewSetting(getConfig(), configFile, getDataFolder()); + File configFile = new File(getDataFolder(), "config.yml"); + return SettingsMigrationService.copyFileFromResource(configFile, "config.yml") + ? new NewSetting(configFile, getDataFolder()) + : null; } /** diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java index 605cabc08..eca20fbba 100644 --- a/src/main/java/fr/xephi/authme/ConsoleLogger.java +++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java @@ -1,16 +1,16 @@ package fr.xephi.authme; import com.google.common.base.Throwables; -import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.StringUtils; -import fr.xephi.authme.util.Wrapper; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardOpenOption; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; +import java.util.logging.Logger; /** * The plugin's static logger. @@ -19,21 +19,31 @@ public final class ConsoleLogger { private static final String NEW_LINE = System.getProperty("line.separator"); private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]"); - - private static Wrapper wrapper = Wrapper.getInstance(); + private static Logger logger; + private static boolean useLogging = false; + private static File logFile; private ConsoleLogger() { // Service class } + public static void setLogger(Logger logger) { + ConsoleLogger.logger = logger; + } + + public static void setLoggingOptions(boolean useLogging, File logFile) { + ConsoleLogger.useLogging = useLogging; + ConsoleLogger.logFile = logFile; + } + /** * Print an info message. * * @param message String */ public static void info(String message) { - wrapper.getLogger().info(message); - if (Settings.useLogging) { + logger.info(message); + if (useLogging) { writeLog(message); } } @@ -44,8 +54,8 @@ public final class ConsoleLogger { * @param message String */ public static void showError(String message) { - wrapper.getLogger().warning(message); - if (Settings.useLogging) { + logger.warning(message); + if (useLogging) { writeLog("ERROR: " + message); } } @@ -61,7 +71,7 @@ public final class ConsoleLogger { dateTime = DATE_FORMAT.format(new Date()); } try { - Files.write(Settings.LOG_FILE.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(), + Files.write(logFile.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(), StandardOpenOption.APPEND, StandardOpenOption.CREATE); } catch (IOException ignored) { @@ -74,7 +84,7 @@ public final class ConsoleLogger { * @param th The Throwable whose stack trace should be logged */ public static void writeStackTrace(Throwable th) { - if (Settings.useLogging) { + if (useLogging) { writeLog(Throwables.getStackTraceAsString(th)); } } diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java index 85ae65058..29e833d0a 100644 --- a/src/main/java/fr/xephi/authme/settings/NewSetting.java +++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java @@ -24,7 +24,7 @@ import java.util.Arrays; import java.util.List; import java.util.Map; -import static fr.xephi.authme.util.StringUtils.makePath; +import static fr.xephi.authme.settings.SettingsMigrationService.copyFileFromResource; /** * The new settings manager. @@ -42,24 +42,14 @@ public class NewSetting { /** * Constructor. Checks the given {@link FileConfiguration} object for completeness. * - * @param configuration The configuration to interact with * @param configFile The configuration file * @param pluginFolder The AuthMe plugin folder */ - public NewSetting(FileConfiguration configuration, File configFile, File pluginFolder) { - this.configuration = configuration; + public NewSetting(File configFile, File pluginFolder) { + this.configuration = YamlConfiguration.loadConfiguration(configFile); this.configFile = configFile; this.pluginFolder = pluginFolder; - messagesFile = buildMessagesFile(); - welcomeMessage = readWelcomeMessage(); - emailMessage = readEmailMessage(); - - PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); - if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) { - ConsoleLogger.info("Merged new config options"); - ConsoleLogger.info("Please check your config.yml file for new settings!"); - save(propertyMap); - } + validateAndLoadOptions(); } /** @@ -131,6 +121,7 @@ public class NewSetting { */ public void reload() { configuration = YamlConfiguration.loadConfiguration(configFile); + validateAndLoadOptions(); } private void save(PropertyMap propertyMap) { @@ -185,6 +176,19 @@ public class NewSetting { } } + private void validateAndLoadOptions() { + PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields(); + if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) { + ConsoleLogger.info("Merged new config options"); + ConsoleLogger.info("Please check your config.yml file for new settings!"); + save(propertyMap); + } + + messagesFile = buildMessagesFile(); + welcomeMessage = readWelcomeMessage(); + emailMessage = readEmailMessage(); + } + private String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) { String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml); return join("\n" + indent(indent), representation.split("\\n")); @@ -196,59 +200,45 @@ public class NewSetting { if (messagesFile.exists()) { return messagesFile; } - return buildMessagesFileFromCode("en"); + + return copyFileFromResource(messagesFile, buildMessagesFilePathFromCode(languageCode)) + ? messagesFile + : buildMessagesFileFromCode("en"); } private File buildMessagesFileFromCode(String language) { - return new File(pluginFolder, - makePath("messages", "messages_" + language + ".yml")); + return new File(pluginFolder, buildMessagesFilePathFromCode(language)); + } + + private static String buildMessagesFilePathFromCode(String language) { + return StringUtils.makePath("messages", "messages_" + language + ".yml"); } private List readWelcomeMessage() { if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) { final File welcomeFile = new File(pluginFolder, "welcome.txt"); final Charset charset = Charset.forName("UTF-8"); - if (!welcomeFile.exists()) { + if (copyFileFromResource(welcomeFile, "welcome.txt")) { try { - Files.write( - "Welcome {PLAYER} to {SERVER} server\n\nThis server uses AuthMe protection!", - welcomeFile, charset); + return Files.readLines(welcomeFile, charset); } catch (IOException e) { - ConsoleLogger.showError("Failed to create file '" + welcomeFile.getPath() + "': " - + StringUtils.formatException(e)); - ConsoleLogger.writeStackTrace(e); + ConsoleLogger.logException("Failed to read file '" + welcomeFile.getPath() + "':", e); } } - try { - return Files.readLines(welcomeFile, charset); - } catch (IOException e) { - ConsoleLogger.showError("Failed to read file '" + welcomeFile.getPath() + "': " + - StringUtils.formatException(e)); - ConsoleLogger.writeStackTrace(e); - } } return new ArrayList<>(0); } private String readEmailMessage() { - final File emailFile = new File(pluginFolder, "email.txt"); + final File emailFile = new File(pluginFolder, "email.html"); final Charset charset = Charset.forName("UTF-8"); - if (!emailFile.exists()) { + if (copyFileFromResource(emailFile, "email.html")) { try { - Files.write("", emailFile, charset); + return StringUtils.join("", Files.readLines(emailFile, charset)); } catch (IOException e) { - ConsoleLogger.showError("Failed to create file '" + emailFile.getPath() + "': " - + StringUtils.formatException(e)); - ConsoleLogger.writeStackTrace(e); + ConsoleLogger.logException("Failed to read file '" + emailFile.getPath() + "':", e); } } - try { - return StringUtils.join("", Files.readLines(emailFile, charset)); - } catch (IOException e) { - ConsoleLogger.showError("Failed to read file '" + emailFile.getPath() + "': " + - StringUtils.formatException(e)); - ConsoleLogger.writeStackTrace(e); - } return ""; } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 96d15d12e..ff7116213 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -6,7 +6,7 @@ import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.datasource.DataSource.DataSourceType; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.util.Wrapper; -import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.configuration.file.FileConfiguration; import java.io.File; import java.io.IOException; @@ -87,7 +87,7 @@ public final class Settings { getmaxRegPerEmail, bCryptLog2Rounds, getPhpbbGroup, antiBotSensibility, antiBotDuration, delayRecall, getMaxLoginPerIp, getMaxJoinPerIp; - protected static YamlConfiguration configFile; + protected static FileConfiguration configFile; private static AuthMe plugin; private static Settings instance; @@ -99,25 +99,8 @@ public final class Settings { public Settings(AuthMe pl) { instance = this; plugin = pl; - configFile = (YamlConfiguration) plugin.getConfig(); - } - - /** - * Method reload. - * - * @throws Exception if something went wrong - */ - public static void reload() throws Exception { - plugin.getLogger().info("Loading Configuration File..."); - boolean exist = SETTINGS_FILE.exists(); - if (!exist) { - plugin.saveDefaultConfig(); - } - configFile.load(SETTINGS_FILE); + configFile = plugin.getConfig(); loadVariables(); - if (exist) { - instance.saveDefaults(); - } } public static void loadVariables() { diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java index 1e010f4c5..0a41301c7 100644 --- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java +++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java @@ -1,17 +1,20 @@ package fr.xephi.authme.settings; import com.google.common.annotations.VisibleForTesting; +import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.settings.domain.Property; import fr.xephi.authme.settings.propertymap.PropertyMap; -import fr.xephi.authme.util.StringUtils; import org.bukkit.configuration.file.FileConfiguration; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS; +import static java.lang.String.format; /** * Service for verifying that the configuration is up-to-date. @@ -86,15 +89,51 @@ public final class SettingsMigrationService { } final File emailFile = new File(dataFolder, "email.html"); + final String mailText = configuration.getString(oldSettingPath) + .replace("", "") + .replace("", "") + .replace("", "") + .replace("", ""); if (!emailFile.exists()) { try (FileWriter fw = new FileWriter(emailFile)) { - fw.write(configuration.getString("Email.mailText")); + fw.write(mailText); } catch (IOException e) { - ConsoleLogger.showError("Could not create email.html configuration file: " - + StringUtils.formatException(e)); + ConsoleLogger.logException("Could not create email.html configuration file:", e); } } return true; } + /** + * Copy a resource file (from the JAR) to the given file if it doesn't exist. + * + * @param destinationFile The file to check and copy to (outside of JAR) + * @param resourcePath Absolute path to the resource file (path to file within JAR) + * @return False if the file does not exist and could not be copied, true otherwise + */ + public static boolean copyFileFromResource(File destinationFile, String resourcePath) { + if (destinationFile.exists()) { + return true; + } else if (!destinationFile.getParentFile().exists() && !destinationFile.getParentFile().mkdirs()) { + ConsoleLogger.showError("Cannot create parent directories for '" + destinationFile + "'"); + return false; + } + + // ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/' + final String normalizedPath = resourcePath.replace("\\", "/"); + try (InputStream is = AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath)) { + if (is == null) { + ConsoleLogger.showError(format("Cannot copy resource '%s' to file '%s': cannot load resource", + resourcePath, destinationFile.getPath())); + } else { + Files.copy(is, destinationFile.toPath()); + return true; + } + } catch (IOException e) { + ConsoleLogger.logException(format("Cannot copy resource '%s' to file '%s':", + resourcePath, destinationFile.getPath()), e); + } + return false; + } + } diff --git a/src/main/resources/welcome.txt b/src/main/resources/welcome.txt new file mode 100644 index 000000000..1c49f042b --- /dev/null +++ b/src/main/resources/welcome.txt @@ -0,0 +1,3 @@ +Welcome {PLAYER} on {SERVER} server + +This server uses AuthMeReloaded protection! diff --git a/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java b/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java new file mode 100644 index 000000000..cfa871e3e --- /dev/null +++ b/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java @@ -0,0 +1,20 @@ +package fr.xephi.authme; + +import org.mockito.Mockito; + +import java.util.logging.Logger; + +/** + * Test initializer for {@link ConsoleLogger}. + */ +public class ConsoleLoggerTestInitializer { + + private ConsoleLoggerTestInitializer() { + } + + public static Logger setupLogger() { + Logger logger = Mockito.mock(Logger.class); + ConsoleLogger.setLogger(logger); + return logger; + } +} diff --git a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java b/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java index fdd338919..b9977de8e 100644 --- a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java +++ b/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java @@ -219,8 +219,8 @@ public class Log4JFilterTest { * Mocks a {@link Message} object and makes it return the given formatted message. * * @param formattedMessage the formatted message the mock should return - - * @return Message mock */ + * @return Message mock + */ private static Message mockMessage(String formattedMessage) { Message message = Mockito.mock(Message.class); when(message.getFormattedMessage()).thenReturn(formattedMessage); diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java index 6e63a934d..2d3e7b08f 100644 --- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java +++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java @@ -1,9 +1,11 @@ package fr.xephi.authme.output; +import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.util.WrapperMock; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.junit.Before; +import org.junit.BeforeClass; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; @@ -27,6 +29,12 @@ public class MessagesIntegrationTest { private static final String YML_TEST_FILE = "messages_test.yml"; private Messages messages; + @BeforeClass + public static void setup() { + WrapperMock.createInstance(); + ConsoleLoggerTestInitializer.setupLogger(); + } + /** * Loads the messages in the file {@code messages_test.yml} in the test resources folder. * The file does not contain all messages defined in {@link MessageKey} and its contents @@ -34,8 +42,6 @@ public class MessagesIntegrationTest { */ @Before public void setUpMessages() { - WrapperMock.createInstance(); - URL url = getClass().getClassLoader().getResource(YML_TEST_FILE); if (url == null) { throw new RuntimeException("File '" + YML_TEST_FILE + "' could not be loaded"); diff --git a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java index 106689ae7..6ee291143 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java @@ -1,5 +1,6 @@ package fr.xephi.authme.security.crypts; +import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; @@ -13,6 +14,7 @@ public class BcryptTest extends AbstractEncryptionMethodTest { public static void setUpSettings() { WrapperMock.createInstance(); Settings.bCryptLog2Rounds = 8; + ConsoleLoggerTestInitializer.setupLogger(); } public BcryptTest() { diff --git a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java index 3b7294a04..ed49ccd71 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java @@ -1,5 +1,6 @@ package fr.xephi.authme.security.crypts; +import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.util.WrapperMock; import org.junit.BeforeClass; @@ -9,8 +10,9 @@ import org.junit.BeforeClass; public class XFBCRYPTTest extends AbstractEncryptionMethodTest { @BeforeClass - public static void setUpWrapper() { + public static void setup() { WrapperMock.createInstance(); + ConsoleLoggerTestInitializer.setupLogger(); } public XFBCRYPTTest() { diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java index 526e511fe..67723c494 100644 --- a/src/test/java/fr/xephi/authme/util/UtilsTest.java +++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java @@ -1,6 +1,7 @@ package fr.xephi.authme.util; import fr.xephi.authme.AuthMe; +import fr.xephi.authme.ConsoleLoggerTestInitializer; import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.permission.PermissionsManager; import fr.xephi.authme.settings.NewSetting; @@ -39,6 +40,7 @@ public class UtilsTest { public static void setUpMocks() { WrapperMock wrapperMock = WrapperMock.createInstance(); authMeMock = wrapperMock.getAuthMe(); + ConsoleLoggerTestInitializer.setupLogger(); } @Before