diff --git a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java b/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java index bbacd6c55..64a935515 100644 --- a/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java +++ b/src/main/java/fr/xephi/authme/data/limbo/persistence/DistributedFilesPersistenceHandler.java @@ -41,10 +41,7 @@ class DistributedFilesPersistenceHandler implements LimboPersistenceHandler { @Inject DistributedFilesPersistenceHandler(@DataFolder File dataFolder, BukkitService bukkitService, Settings settings) { cacheFolder = new File(dataFolder, "playerdata"); - if (!cacheFolder.exists()) { - // TODO ljacqu 20170313: Create FileUtils#mkdirs - cacheFolder.mkdirs(); - } + FileUtils.createDirectory(cacheFolder); gson = new GsonBuilder() .registerTypeAdapter(LimboPlayer.class, new LimboPlayerSerializer()) diff --git a/src/main/java/fr/xephi/authme/datasource/converter/RakamakConverter.java b/src/main/java/fr/xephi/authme/datasource/converter/RakamakConverter.java index 4257f0aa7..a65dfbc24 100644 --- a/src/main/java/fr/xephi/authme/datasource/converter/RakamakConverter.java +++ b/src/main/java/fr/xephi/authme/datasource/converter/RakamakConverter.java @@ -8,6 +8,7 @@ import fr.xephi.authme.security.PasswordSecurity; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.ConverterSettings; +import fr.xephi.authme.util.Utils; import org.bukkit.command.CommandSender; import javax.inject.Inject; @@ -85,8 +86,7 @@ public class RakamakConverter implements Converter { .build(); database.saveAuth(auth); } - ConsoleLogger.info("Rakamak database has been imported correctly"); - sender.sendMessage("Rakamak database has been imported correctly"); + Utils.logAndSendMessage(sender, "Rakamak database has been imported correctly"); } catch (IOException ex) { ConsoleLogger.logException("Can't open the rakamak database file! Does it exist?", ex); } diff --git a/src/main/java/fr/xephi/authme/security/HashUtils.java b/src/main/java/fr/xephi/authme/security/HashUtils.java index 946af52be..3578c80f3 100644 --- a/src/main/java/fr/xephi/authme/security/HashUtils.java +++ b/src/main/java/fr/xephi/authme/security/HashUtils.java @@ -85,12 +85,22 @@ public final class HashUtils { * @param algorithm The algorithm to hash the message with * @return The digest in its hexadecimal representation */ - private static String hash(String message, MessageDigestAlgorithm algorithm) { - MessageDigest md = getDigest(algorithm); - md.reset(); - md.update(message.getBytes()); - byte[] digest = md.digest(); + public static String hash(String message, MessageDigest algorithm) { + algorithm.reset(); + algorithm.update(message.getBytes()); + byte[] digest = algorithm.digest(); return String.format("%0" + (digest.length << 1) + "x", new BigInteger(1, digest)); } + /** + * Hash the message with the given algorithm and return the hash in its hexadecimal notation. + * + * @param message The message to hash + * @param algorithm The algorithm to hash the message with + * @return The digest in its hexadecimal representation + */ + private static String hash(String message, MessageDigestAlgorithm algorithm) { + return hash(message, getDigest(algorithm)); + } + } diff --git a/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java b/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java index 989ef8383..9f5574380 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java +++ b/src/main/java/fr/xephi/authme/security/crypts/RoyalAuth.java @@ -1,14 +1,17 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.security.HashUtils; +import fr.xephi.authme.security.MessageDigestAlgorithm; + +import java.security.MessageDigest; public class RoyalAuth extends UnsaltedMethod { @Override public String computeHash(String password) { - for (int i = 0; i < 25; i++) { - // TODO ljacqu 20151228: HashUtils#sha512 gets a new message digest each time... - password = HashUtils.sha512(password); + MessageDigest algorithm = HashUtils.getDigest(MessageDigestAlgorithm.SHA512); + for (int i = 0; i < 25; ++i) { + password = HashUtils.hash(password, algorithm); } return password; } diff --git a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java index 26f7d03b9..13f28004f 100644 --- a/src/main/java/fr/xephi/authme/settings/SpawnLoader.java +++ b/src/main/java/fr/xephi/authme/settings/SpawnLoader.java @@ -45,7 +45,6 @@ public class SpawnLoader implements Reloadable { */ @Inject SpawnLoader(@DataFolder File pluginFolder, Settings settings, PluginHookService pluginHookService) { - // TODO ljacqu 20160312: Check if resource could be copied and handle the case if not File spawnFile = new File(pluginFolder, "spawn.yml"); FileUtils.copyFileFromResource(spawnFile, "spawn.yml"); this.authMeConfigurationFile = spawnFile; diff --git a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java b/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java index 985630cfa..0fddecd57 100644 --- a/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java +++ b/src/main/java/fr/xephi/authme/task/purge/PurgeExecutor.java @@ -194,7 +194,6 @@ class PurgeExecutor { } // TODO: What is this method for? Is it correct? - // TODO: Make it work with OfflinePlayers group data. synchronized void purgePermissions(Collection cleared) { if (!settings.getProperty(PurgeSettings.REMOVE_PERMISSIONS)) { return; diff --git a/src/main/java/fr/xephi/authme/util/FileUtils.java b/src/main/java/fr/xephi/authme/util/FileUtils.java index c9edcf735..fa8c858ad 100644 --- a/src/main/java/fr/xephi/authme/util/FileUtils.java +++ b/src/main/java/fr/xephi/authme/util/FileUtils.java @@ -30,7 +30,7 @@ public final class FileUtils { public static boolean copyFileFromResource(File destinationFile, String resourcePath) { if (destinationFile.exists()) { return true; - } else if (!destinationFile.getParentFile().exists() && !destinationFile.getParentFile().mkdirs()) { + } else if (!createDirectory(destinationFile.getParentFile())) { ConsoleLogger.warning("Cannot create parent directories for '" + destinationFile + "'"); return false; } @@ -50,6 +50,20 @@ public final class FileUtils { return false; } + /** + * Creates the given directory. + * + * @param dir the directory to create + * @return true upon success, false otherwise + */ + public static boolean createDirectory(File dir) { + if (!dir.exists() && !dir.mkdirs()) { + ConsoleLogger.warning("Could not create directory '" + dir + "'"); + return false; + } + return true; + } + /** * Returns a JAR file as stream. Returns null if it doesn't exist. * diff --git a/src/test/java/fr/xephi/authme/IsEqualByReflectionMatcher.java b/src/test/java/fr/xephi/authme/IsEqualByReflectionMatcher.java new file mode 100644 index 000000000..a6033ffd3 --- /dev/null +++ b/src/test/java/fr/xephi/authme/IsEqualByReflectionMatcher.java @@ -0,0 +1,84 @@ +package fr.xephi.authme; + +import org.hamcrest.Description; +import org.hamcrest.Matcher; +import org.hamcrest.TypeSafeMatcher; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +import static org.junit.Assert.fail; + +/** + * Matcher which checks with reflection that all fields have the same value. + * This matcher considers all non-static fields until the Object parent. + */ +public final class IsEqualByReflectionMatcher extends TypeSafeMatcher { + + private final T expected; + + private IsEqualByReflectionMatcher(T expected) { + this.expected = expected; + } + + /** + * Creates a matcher that checks if all fields are the same as on the {@code expected} object. + * + * @param expected the object to match + * @param the object's type + * @return the matcher for the expected object + */ + public static Matcher isEqualTo(T expected) { + return new IsEqualByReflectionMatcher<>(expected); + } + + @Override + protected boolean matchesSafely(T item) { + return assertAreFieldsEqual(item); + } + + @Override + public void describeTo(Description description) { + description.appendText("parameters " + expected); + } + + private boolean assertAreFieldsEqual(T item) { + if (expected.getClass() != item.getClass()) { + fail("Classes don't match, got " + expected.getClass().getSimpleName() + + " and " + item.getClass().getSimpleName()); + return false; + } + + List fieldsToCheck = getAllFields(expected); + for (Field field : fieldsToCheck) { + Object lhsValue = ReflectionTestUtils.getFieldValue(field, expected); + Object rhsValue = ReflectionTestUtils.getFieldValue(field, item); + if (!Objects.equals(lhsValue, rhsValue)) { + fail("Field '" + field.getName() + "' does not have same value: '" + + lhsValue + "' vs. '" + rhsValue + "'"); + return false; + } + } + return true; + } + + private static List getAllFields(Object object) { + List fields = new ArrayList<>(); + Class currentClass = object.getClass(); + while (currentClass != null) { + for (Field f : currentClass.getDeclaredFields()) { + if (!Modifier.isStatic(f.getModifiers())) { + fields.add(f); + } + } + if (currentClass == Object.class) { + break; + } + currentClass = currentClass.getSuperclass(); + } + return fields; + } +} diff --git a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java index 6224a6065..d345ca8e1 100644 --- a/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java +++ b/src/test/java/fr/xephi/authme/command/executable/register/RegisterCommandTest.java @@ -1,6 +1,5 @@ package fr.xephi.authme.command.executable.register; -import fr.xephi.authme.ReflectionTestUtils; import fr.xephi.authme.TestHelper; import fr.xephi.authme.mail.EmailService; import fr.xephi.authme.message.MessageKey; @@ -10,7 +9,6 @@ import fr.xephi.authme.process.register.RegistrationType; import fr.xephi.authme.process.register.executors.EmailRegisterParams; import fr.xephi.authme.process.register.executors.PasswordRegisterParams; import fr.xephi.authme.process.register.executors.RegistrationMethod; -import fr.xephi.authme.process.register.executors.RegistrationParameters; import fr.xephi.authme.process.register.executors.TwoFactorRegisterParams; import fr.xephi.authme.security.HashAlgorithm; import fr.xephi.authme.service.CommonService; @@ -20,9 +18,6 @@ import fr.xephi.authme.settings.properties.SecuritySettings; import org.bukkit.command.BlockCommandSender; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.hamcrest.Description; -import org.hamcrest.Matcher; -import org.hamcrest.TypeSafeMatcher; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; @@ -31,16 +26,11 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; -import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; -import java.util.List; -import java.util.Objects; +import static fr.xephi.authme.IsEqualByReflectionMatcher.isEqualTo; import static org.hamcrest.Matchers.containsString; -import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; @@ -306,56 +296,4 @@ public class RegisterCommandTest { verify(management).performRegister(eq(RegistrationMethod.PASSWORD_REGISTRATION), argThat(isEqualTo(PasswordRegisterParams.of(player, "myPass", null)))); } - - - // TODO ljacqu 20170317: Document and extract as util - - private static

Matcher

isEqualTo(P expected) { - return new TypeSafeMatcher

() { - @Override - protected boolean matchesSafely(RegistrationParameters item) { - assertAreParamsEqual(expected, item); - return true; - } - - @Override - public void describeTo(Description description) { - description.appendText("parameters " + expected); - } - }; - } - - private static void assertAreParamsEqual(RegistrationParameters lhs, RegistrationParameters rhs) { - if (lhs.getClass() != rhs.getClass()) { - fail("Params classes don't match, got " + lhs.getClass().getSimpleName() - + " and " + rhs.getClass().getSimpleName()); - } - - List fieldsToCheck = getFields(lhs); - for (Field field : fieldsToCheck) { - Object lhsValue = ReflectionTestUtils.getFieldValue(field, lhs); - Object rhsValue = ReflectionTestUtils.getFieldValue(field, rhs); - if (!Objects.equals(lhsValue, rhsValue)) { - fail("Field '" + field.getName() + "' does not have same value: '" - + lhsValue + "' vs. '" + rhsValue + "'"); - } - } - } - - private static List getFields(RegistrationParameters params) { - List fields = new ArrayList<>(); - Class currentClass = params.getClass(); - while (currentClass != null) { - for (Field f : currentClass.getDeclaredFields()) { - if (!Modifier.isStatic(f.getModifiers())) { - fields.add(f); - } - } - if (currentClass == RegistrationParameters.class) { - break; - } - currentClass = currentClass.getSuperclass(); - } - return fields; - } } diff --git a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java index dd6b6c789..f1bb641d5 100644 --- a/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java +++ b/src/test/java/fr/xephi/authme/service/AntiBotServiceTest.java @@ -11,7 +11,6 @@ import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.ProtectionSettings; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitTask; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; @@ -82,7 +81,6 @@ public class AntiBotServiceTest { } @Test - @Ignore // TODO ljacqu 20161030: Fix test public void shouldActivateAntibot() { // given - listening antibot runSyncDelayedTaskWithDelay(bukkitService);