diff --git a/pom.xml b/pom.xml index 869cbe815..7e8cd70ba 100644 --- a/pom.xml +++ b/pom.xml @@ -1,786 +1,781 @@ - - 4.0.0 + + 4.0.0 - fr.xephi - authme - 5.2-SNAPSHOT - jar + fr.xephi + authme + 5.2-SNAPSHOT + jar - AuthMeReloaded - Authentication plugin for CraftBukkit/Spigot! - 2013 - http://dev.bukkit.org/bukkit-plugins/authme-reloaded/ - + AuthMeReloaded + Authentication plugin for CraftBukkit/Spigot! + 2013 + http://dev.bukkit.org/bukkit-plugins/authme-reloaded/ + - - AuthMe-Team - https://github.com/AuthMe-Team - + + AuthMe-Team + https://github.com/AuthMe-Team + - - scm:git:https://github.com/Xephi/AuthMeReloaded.git - scm:git:git@github.com:Xephi/AuthMeReloaded.git - http://github.com/Xephi/AuthMeReloaded - + + scm:git:https://github.com/Xephi/AuthMeReloaded.git + scm:git:git@github.com:Xephi/AuthMeReloaded.git + http://github.com/Xephi/AuthMeReloaded + - - jenkins - http://ci.xephi.fr/job/AuthMeReloaded/ - + + jenkins + http://ci.xephi.fr/job/AuthMeReloaded/ + - - GitHub - https://github.com/Xephi/AuthMeReloaded/issues - + + GitHub + https://github.com/Xephi/AuthMeReloaded/issues + - - - The GNU General Public Licence version 3 (GPLv3) - http://www.gnu.org/licenses/gpl-3.0.html - - + + + The GNU General Public Licence version 3 (GPLv3) + http://www.gnu.org/licenses/gpl-3.0.html + + - - 3.3.3 - + + 3.3.3 + - - UTF-8 + + UTF-8 - - AuthMe - fr.xephi.authme.AuthMe - Xephi, sgdc3, DNx5, timvisee, games647, ljacqu - Unknown + + AuthMe + fr.xephi.authme.AuthMe + Xephi, sgdc3, DNx5, timvisee, games647, ljacqu + Unknown - - 1.7 + + 1.7 - - 1.8.8-R0.1-SNAPSHOT - + + 1.8.8-R0.1-SNAPSHOT + - - - jenkins - - - env.BUILD_NUMBER - - - - ${env.BUILD_NUMBER} - - - + + + jenkins + + + env.BUILD_NUMBER + + + + ${env.BUILD_NUMBER} + + + - - AuthMe-${project.version} - src/main/java - src/test/java + + AuthMe-${project.version} + src/main/java + src/test/java - - - . - true - src/main/resources/ - - plugin.yml - - - - . - true - src/main/resources/ - - email.html - - - - . - false - src/main/resources/ - - *.yml - - - plugin.yml - - - - ./messages/ - false - src/main/resources/messages/ - - *.yml - - - - - - src/test/resources - - + + + . + true + src/main/resources/ + + plugin.yml + + + + . + true + src/main/resources/ + + email.html + + + + . + false + src/main/resources/ + + *.yml + + + plugin.yml + + + + ./messages/ + false + src/main/resources/messages/ + + *.yml + + + + + + src/test/resources + + - - - - - org.eclipse.m2e - lifecycle-mapping - 1.0.0 - - - - - - org.codehaus.mojo - buildnumber-maven-plugin - [1.0,) - - create-timestamp - - - - - true - true - - - - - - - - - + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + org.codehaus.mojo + buildnumber-maven-plugin + [1.0,) + + create-timestamp + + + + + true + true + + + + + + + + + - - - org.apache.maven.plugins - maven-compiler-plugin - 3.3 - - 1.7 - ${javaVersion} - - + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.7 + ${javaVersion} + + - - org.codehaus.mojo - buildnumber-maven-plugin - 1.4 - - dd-MM-yy_HH-mm - build.time - - - - generate-resources - - create-timestamp - - - - - - - - org.apache.maven.plugins - maven-shade-plugin - 2.4.2 - - false - false - - - org.mcstats - fr.xephi.authme - - - com.google.gson - fr.xephi.authme.libs.gson - - - com.zaxxer.hikari - fr.xephi.authme.libs.hikari - - - org.slf4j - fr.xephi.authme.libs.slf4j - - - com.maxmind.geoip - fr.xephi.authme.libs.geoip - - - net.ricecode.similarity - fr.xephi.authme.libs.similarity - - - - - - package - - shade - - - - - - - org.jacoco - jacoco-maven-plugin - 0.7.5.201505241946 - - - prepare-agent - - prepare-agent - - - - - - - org.eluder.coveralls - coveralls-maven-plugin - 4.1.0 - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.10.3 - - fr.xephi.authme.api.*:fr.xephi.authme.events.* - - + + org.codehaus.mojo + buildnumber-maven-plugin + 1.4 + + dd-MM-yy_HH-mm + build.time + + - attach-javadocs + generate-resources - jar + create-timestamp - - - + - - - - spigot-repo - http://hub.spigotmc.org/nexus/content/groups/public - + + + org.apache.maven.plugins + maven-shade-plugin + 2.4.2 + + false + false + + + org.mcstats + fr.xephi.authme + + + com.google.gson + fr.xephi.authme.libs.gson + + + com.zaxxer.hikari + fr.xephi.authme.libs.hikari + + + org.slf4j + fr.xephi.authme.libs.slf4j + + + com.maxmind.geoip + fr.xephi.authme.libs.geoip + + + net.ricecode.similarity + fr.xephi.authme.libs.similarity + + + + + + package + + shade + + + + - - - ess-repo - http://ci.drtshock.net/plugin/repository/everything - + + org.jacoco + jacoco-maven-plugin + 0.7.5.201505241946 + + + prepare-agent + + prepare-agent + + + + - - - minelink-thirdparty - http://repo.minelink.net/content/repositories/public - + + org.eluder.coveralls + coveralls-maven-plugin + 4.1.0 + + - - - dmulloy2-repo - http://repo.dmulloy2.net/content/groups/public/ - + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + UTF-8 + UTF-8 + true + + + + - - - onarandombox - http://repo.onarandombox.com/content/groups/public - + + + + spigot-repo + http://hub.spigotmc.org/nexus/content/groups/public + - - - vault-repo - http://nexus.theyeticave.net/content/repositories/pub_releases - + + + ess-repo + http://ci.drtshock.net/plugin/repository/everything + - - - luricos-releases - http://repo.luricos.de/content/repositories/releases - + + + minelink-thirdparty + http://repo.minelink.net/content/repositories/public + - - - xephi-repo - http://ci.xephi.fr/plugin/repository/everything/ - + + + dmulloy2-repo + http://repo.dmulloy2.net/content/groups/public/ + - - - pex-repo - http://pex-repo.aoeu.xyz/ - - + + + onarandombox + http://repo.onarandombox.com/content/groups/public + - - - - com.zaxxer - HikariCP - 2.4.3 - compile - - - slf4j-api - org.slf4j - - - true - - - org.slf4j - slf4j-jdk14 - 1.7.13 - compile - true - + + + vault-repo + http://nexus.theyeticave.net/content/repositories/pub_releases + - - - org.apache.logging.log4j - log4j-core - - 2.0-beta9 - provided - true - + + + luricos-releases + http://repo.luricos.de/content/repositories/releases + - - - org.apache.commons - commons-email - 1.4 - compile - true - + + + xephi-repo + http://ci.xephi.fr/plugin/repository/everything/ + - - - com.google.code.gson - gson - 2.5 - compile - true - + + + pex-repo + http://pex-repo.aoeu.xyz/ + + - - - com.maxmind.geoip - geoip-api - 1.2.15 - compile - true - + + + + com.zaxxer + HikariCP + 2.4.3 + compile + + + slf4j-api + org.slf4j + + + true + + + org.slf4j + slf4j-jdk14 + 1.7.13 + compile + true + - - - org.mcstats.bukkit - metrics - R8-SNAPSHOT - compile - - - org.bukkit - bukkit - - - true - + + + org.apache.logging.log4j + log4j-core + + 2.0-beta9 + provided + true + - - - org.bukkit - bukkit - ${bukkitVersion} - provided - true - - - junit - junit - - - json-simple - com.googlecode.json-simple - - - gson - com.google.code.gson - - - persistence-api - javax.persistence - - - + + + org.apache.commons + commons-email + 1.4 + compile + true + - - - com.comphenix.protocol - ProtocolLib - 3.6.5-SNAPSHOT - provided - true - - - cglib-nodep - cglib - - - BukkitExecutors - com.comphenix.executors - - - + + + com.google.code.gson + gson + 2.5 + compile + true + - - - ru.tehkode - PermissionsEx - 1.23.1 - provided - - - org.bukkit - bukkit - - - net.gravitydevelopment.updater - updater - - - commons-dbcp - commons-dbcp - - - AccountsClient - com.mojang - - - + + + com.maxmind.geoip + geoip-api + 1.2.15 + compile + true + - - - org.anjocaido - groupmanagerx - 2.2-SNAPSHOT - provided - - - org.bukkit - bukkit - - - + + + org.mcstats.bukkit + metrics + R8-SNAPSHOT + compile + + + org.bukkit + bukkit + + + true + - - - de.bananaco - bPermissions - 2.12-DEV - provided - - - org.bukkit - bukkit - - - + + + org.bukkit + bukkit + ${bukkitVersion} + provided + true + + + junit + junit + + + json-simple + com.googlecode.json-simple + + + gson + com.google.code.gson + + + persistence-api + javax.persistence + + + - - - org.tyrannyofheaven.bukkit - zPermissions - 1.3-SNAPSHOT - provided - - - org.bukkit - bukkit - - - com.sk89q - worldguard - - - com.sk89q - worldedit - - - VaultAPI - net.milkbowl.vault - - - uuidprovider - net.kaikk.mc - - - ToHPluginUtils - org.tyrannyofheaven.bukkit - - - + + + com.comphenix.protocol + ProtocolLib + 3.6.5-SNAPSHOT + provided + true + + + cglib-nodep + cglib + + + BukkitExecutors + com.comphenix.executors + + + - - - net.milkbowl.vault - VaultAPI - 1.5 - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - true - + + + ru.tehkode + PermissionsEx + 1.23.1 + provided + + + org.bukkit + bukkit + + + net.gravitydevelopment.updater + updater + + + commons-dbcp + commons-dbcp + + + AccountsClient + com.mojang + + + - - - com.onarandombox.multiversecore - Multiverse-Core - 2.5 - jar - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - AllPay - com.fernferret.allpay - - - Vault - net.milkbowl.vault - - - VaultAPI - net.milkbowl.vault - - - CommandHandler - com.pneumaticraft.commandhandler - - - SerializationConfig - me.main__.util - - - Logging - com.dumptruckman.minecraft - - - metrics - org.mcstats.bukkit - - - buscript - com.dumptruckman.minecraft - - - junit - junit - - - true - + + + org.anjocaido + groupmanagerx + 2.2-SNAPSHOT + provided + + + org.bukkit + bukkit + + + - - - net.ess3 - EssentialsX - 2.0.1-SNAPSHOT - provided - - - org.spigotmc - spigot-api - - - true - + + + de.bananaco + bPermissions + 2.12-DEV + provided + + + org.bukkit + bukkit + + + - - - net.minelink - CombatTagPlus - 1.2.1-SNAPSHOT - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - CombatTagPlusHook - net.minelink - - - CombatTagPlusFactions-v1_6 - net.minelink - - - CombatTagPlusCompat-v1_7_R3 - net.minelink - - - CombatTagPlusFactions-v1_8 - net.minelink - - - CombatTagPlusCompat-v1_7_R4 - net.minelink - - - CombatTagPlusWG-v5 - net.minelink - - - CombatTagPlusWG-v6 - net.minelink - - - CombatTagPlusCompat-API - net.minelink - - - CombatTagPlusFactions-v2_6 - net.minelink - - - CombatTagPlusCompat-v1_8_R3 - net.minelink - - - CombatTagPlusFactions-v2_7 - net.minelink - - - CombatTagPlusCompat-v1_8_R2 - net.minelink - - - CombatTagPlusCompat-v1_8_R1 - net.minelink - - - metrics-lite - org.mcstats.bukkit - - - true - + + + org.tyrannyofheaven.bukkit + zPermissions + 1.3-SNAPSHOT + provided + + + org.bukkit + bukkit + + + com.sk89q + worldguard + + + com.sk89q + worldedit + + + VaultAPI + net.milkbowl.vault + + + uuidprovider + net.kaikk.mc + + + ToHPluginUtils + org.tyrannyofheaven.bukkit + + + - - - de.luricos.bukkit - xAuth - 2.6 - provided - - - org.bukkit - bukkit - - - org.bukkit - craftbukkit - - - updater - net.gravitydevelopment.updater - - - lombok - org.projectlombok - - - EssentialsGroupManager - net.ess3 - - - PermissionsEx - ru.tehkode - - - AccountsClient - com.mojang - - - log4j-core - org.apache.logging.log4j - - - true - + + + net.milkbowl.vault + VaultAPI + 1.5 + provided + + + org.bukkit + bukkit + + + org.bukkit + craftbukkit + + + true + - - - junit - junit - test - 4.12 - true - - - org.hamcrest - java-hamcrest - test - 2.0.0.0 - true - - - org.mockito - mockito-core - test - 2.0.5-beta - true - - - hamcrest-core - org.hamcrest - - - + + + com.onarandombox.multiversecore + Multiverse-Core + 2.5 + jar + provided + + + org.bukkit + bukkit + + + org.bukkit + craftbukkit + + + AllPay + com.fernferret.allpay + + + Vault + net.milkbowl.vault + + + VaultAPI + net.milkbowl.vault + + + CommandHandler + com.pneumaticraft.commandhandler + + + SerializationConfig + me.main__.util + + + Logging + com.dumptruckman.minecraft + + + metrics + org.mcstats.bukkit + + + buscript + com.dumptruckman.minecraft + + + junit + junit + + + true + - - - net.ricecode - string-similarity - 1.0.0 - compile - true - - + + + net.ess3 + EssentialsX + 2.0.1-SNAPSHOT + provided + + + org.spigotmc + spigot-api + + + true + + + + + net.minelink + CombatTagPlus + 1.2.1-SNAPSHOT + provided + + + org.bukkit + bukkit + + + org.bukkit + craftbukkit + + + CombatTagPlusHook + net.minelink + + + CombatTagPlusFactions-v1_6 + net.minelink + + + CombatTagPlusCompat-v1_7_R3 + net.minelink + + + CombatTagPlusFactions-v1_8 + net.minelink + + + CombatTagPlusCompat-v1_7_R4 + net.minelink + + + CombatTagPlusWG-v5 + net.minelink + + + CombatTagPlusWG-v6 + net.minelink + + + CombatTagPlusCompat-API + net.minelink + + + CombatTagPlusFactions-v2_6 + net.minelink + + + CombatTagPlusCompat-v1_8_R3 + net.minelink + + + CombatTagPlusFactions-v2_7 + net.minelink + + + CombatTagPlusCompat-v1_8_R2 + net.minelink + + + CombatTagPlusCompat-v1_8_R1 + net.minelink + + + metrics-lite + org.mcstats.bukkit + + + true + + + + + de.luricos.bukkit + xAuth + 2.6 + provided + + + org.bukkit + bukkit + + + org.bukkit + craftbukkit + + + updater + net.gravitydevelopment.updater + + + lombok + org.projectlombok + + + EssentialsGroupManager + net.ess3 + + + PermissionsEx + ru.tehkode + + + AccountsClient + com.mojang + + + log4j-core + org.apache.logging.log4j + + + true + + + + + junit + junit + test + 4.12 + true + + + org.hamcrest + java-hamcrest + test + 2.0.0.0 + true + + + org.mockito + mockito-core + test + 2.0.5-beta + true + + + hamcrest-core + org.hamcrest + + + + + + + net.ricecode + string-similarity + 1.0.0 + compile + true + + diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java index 41ba8ff48..70c8bfd6b 100644 --- a/src/main/java/fr/xephi/authme/AuthMe.java +++ b/src/main/java/fr/xephi/authme/AuthMe.java @@ -1,6 +1,8 @@ package fr.xephi.authme; import com.earth2me.essentials.Essentials; +import com.google.common.base.Charsets; +import com.google.common.io.Resources; import com.onarandombox.MultiverseCore.MultiverseCore; import fr.xephi.authme.api.API; import fr.xephi.authme.api.NewAPI; @@ -30,7 +32,6 @@ import fr.xephi.authme.listener.AuthMePlayerListener; import fr.xephi.authme.listener.AuthMePlayerListener16; import fr.xephi.authme.listener.AuthMePlayerListener18; import fr.xephi.authme.listener.AuthMeServerListener; -import fr.xephi.authme.listener.AuthMeServerStop; import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter; import fr.xephi.authme.mail.SendMailSSL; import fr.xephi.authme.modules.ModuleManager; @@ -66,11 +67,8 @@ import org.bukkit.scheduler.BukkitTask; import org.mcstats.Metrics; import org.mcstats.Metrics.Graph; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStreamReader; import java.net.URL; -import java.net.URLConnection; import java.util.Calendar; import java.util.Collection; import java.util.Date; @@ -133,6 +131,7 @@ public class AuthMe extends JavaPlugin { /** * Get the plugin's instance. + * * @return AuthMe */ public static AuthMe getInstance() { @@ -141,6 +140,7 @@ public class AuthMe extends JavaPlugin { /** * Get the plugin's name. + * * @return The plugin's name. */ public static String getPluginName() { @@ -149,6 +149,7 @@ public class AuthMe extends JavaPlugin { /** * Get the plugin's version. + * * @return The plugin's version. */ public static String getPluginVersion() { @@ -157,6 +158,7 @@ public class AuthMe extends JavaPlugin { /** * Get the plugin's build number. + * * @return The plugin's build number. */ public static String getPluginBuildNumber() { @@ -165,6 +167,7 @@ public class AuthMe extends JavaPlugin { /** * Get the plugin's Settings. + * * @return Plugin's settings. */ public Settings getSettings() { @@ -173,6 +176,7 @@ public class AuthMe extends JavaPlugin { /** * Get the Messages instance. + * * @return Plugin's messages. */ public Messages getMessages() { @@ -272,7 +276,6 @@ public class AuthMe extends JavaPlugin { new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.START); - // Setup the inventory backup playerBackup = new JsonCache(); @@ -303,13 +306,6 @@ public class AuthMe extends JavaPlugin { // Show settings warnings showSettingsWarnings(); - // Register a server shutdown hook - try { - Runtime.getRuntime().addShutdownHook(new AuthMeServerStop(this)); - } catch (Exception e){ - e.printStackTrace(); - } - // Sponsor messages ConsoleLogger.info("AuthMe hooks perfectly with the VeryGames server hosting!"); ConsoleLogger.info("Development builds are available on our jenkins, thanks to f14stelt."); @@ -435,7 +431,7 @@ public class AuthMe extends JavaPlugin { // Set up the API api = new NewAPI(this); - // Setup the old deprecated API + // Set up the deprecated API new API(this); } @@ -517,10 +513,10 @@ public class AuthMe extends JavaPlugin { public void onDisable() { // Save player data Collection players = Utils.getOnlinePlayers(); - if (players != null) { - for (Player player : players) { - this.savePlayer(player); - } + for (Player player : players) { + savePlayer(player); + // TODO: add a MessageKey + player.kickPlayer("Server is restarting or AuthMe plugin was disabled."); } // Do backup on stop if enabled @@ -593,16 +589,16 @@ public class AuthMe extends JavaPlugin { // TODO: Move this to another place maybe ? if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) { - ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " + + 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()) { + for (PlayerAuth auth : database.getAllAuths()) { HashedPassword hashedPassword = passwordSecurity.computeHash( HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname()); auth.setPassword(hashedPassword); - database.updatePassword(auth); - } - Settings.setValue("settings.security.passwordHash", "SHA256"); - Settings.reload(); + database.updatePassword(auth); + } + Settings.setValue("settings.security.passwordHash", "SHA256"); + Settings.reload(); } if (Settings.isCachingEnabled) { @@ -715,10 +711,9 @@ public class AuthMe extends JavaPlugin { inventoryProtector = null; } } - if (tabComplete == null) - { - tabComplete = new AuthMeTabCompletePacketAdapter(this); - tabComplete.register(); + if (tabComplete == null) { + tabComplete = new AuthMeTabCompletePacketAdapter(this); + tabComplete.register(); } } @@ -889,50 +884,34 @@ public class AuthMe extends JavaPlugin { * Gets a player's real IP through VeryGames method. * * @param player The player to process. - * */ @Deprecated public void getVerygamesIp(final Player player) { - final String name = player.getName().toLowerCase(); - Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable(){ - @Override - public void run() { - String realIP = player.getAddress().getAddress().getHostAddress(); - if (realIp.containsKey(name)) - realIP = realIp.get(name); - String sUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; - sUrl = sUrl.replace("%IP%", realIP) - .replace("%PORT%", "" + player.getAddress().getPort()); - try { - URL url = new URL(sUrl); - URLConnection urlCon = url.openConnection(); - urlCon.setConnectTimeout(5000); - urlCon.setReadTimeout(5000); - try (BufferedReader in = new BufferedReader(new InputStreamReader(urlCon.getInputStream()))) { - String inputLine = in.readLine(); - if (!StringUtils.isEmpty(inputLine) && !inputLine.equalsIgnoreCase("error") - && !inputLine.contains("error")) { - realIP = inputLine; - } - } catch (IOException e) { - ConsoleLogger.showError("Could not read from Very Games API - " + StringUtils.formatException(e)); - } - } catch (IOException e) { - ConsoleLogger.showError("Could not fetch Very Games API with URL '" + sUrl + "' - " - + StringUtils.formatException(e)); - } - if (realIp.containsKey(name)) - realIp.remove(name); - realIp.putIfAbsent(name, realIP); - } - }); + final String name = player.getName().toLowerCase(); + String currentIp = player.getAddress().getAddress().getHostAddress(); + if (realIp.containsKey(name)) { + currentIp = realIp.get(name); + } + String sUrl = "http://monitor-1.verygames.net/api/?action=ipclean-real-ip&out=raw&ip=%IP%&port=%PORT%"; + sUrl = sUrl.replace("%IP%", currentIp).replace("%PORT%", "" + player.getAddress().getPort()); + try { + String result = Resources.toString(new URL(sUrl), Charsets.UTF_8); + if (!StringUtils.isEmpty(result) && !result.equalsIgnoreCase("error") && !result.contains("error")) { + currentIp = result; + realIp.put(name, currentIp); + } + } catch (IOException e) { + ConsoleLogger.showError("Could not fetch Very Games API with URL '" + + sUrl + "' - " + StringUtils.formatException(e)); + } } public String getIP(final Player player) { final String name = player.getName().toLowerCase(); String ip = player.getAddress().getAddress().getHostAddress(); - if (realIp.containsKey(name)) + if (realIp.containsKey(name)) { ip = realIp.get(name); + } return ip; } @@ -983,6 +962,8 @@ public class AuthMe extends JavaPlugin { /** * Return the management instance. + * + * @return management The Management */ public Management getManagement() { return management; diff --git a/src/main/java/fr/xephi/authme/DataManager.java b/src/main/java/fr/xephi/authme/DataManager.java index 451667ad1..e0afe6bfc 100644 --- a/src/main/java/fr/xephi/authme/DataManager.java +++ b/src/main/java/fr/xephi/authme/DataManager.java @@ -1,12 +1,5 @@ package fr.xephi.authme; -import fr.xephi.authme.permission.PermissionsManager; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.Utils; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Player; - import java.io.File; import java.util.List; import java.util.concurrent.Callable; @@ -14,6 +7,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.entity.Player; + +import fr.xephi.authme.permission.PermissionsManager; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.Utils; + /** */ public class DataManager { @@ -65,7 +66,7 @@ public class DataManager { /** * Method purgeAntiXray. * - * @param cleared List + * @param cleared List of String */ public synchronized void purgeAntiXray(List cleared) { int i = 0; @@ -90,7 +91,7 @@ public class DataManager { /** * Method purgeLimitedCreative. * - * @param cleared List + * @param cleared List of String */ public synchronized void purgeLimitedCreative(List cleared) { int i = 0; @@ -127,7 +128,7 @@ public class DataManager { /** * Method purgeDat. * - * @param cleared List + * @param cleared List of String */ public synchronized void purgeDat(List cleared) { int i = 0; @@ -160,7 +161,7 @@ public class DataManager { /** * Method purgeEssentials. * - * @param cleared List + * @param cleared List of String */ @SuppressWarnings("deprecation") public void purgeEssentials(List cleared) { diff --git a/src/main/java/fr/xephi/authme/api/NewAPI.java b/src/main/java/fr/xephi/authme/api/NewAPI.java index 6f42432e1..03fed1a80 100644 --- a/src/main/java/fr/xephi/authme/api/NewAPI.java +++ b/src/main/java/fr/xephi/authme/api/NewAPI.java @@ -1,15 +1,16 @@ package fr.xephi.authme.api; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Server; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; import fr.xephi.authme.util.Utils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Server; -import org.bukkit.entity.Player; -import org.bukkit.plugin.Plugin; /** * The current API of AuthMe. @@ -76,7 +77,7 @@ public class NewAPI { } /** - * @param player + * @param player a Player * * @return true if player is a npc */ @@ -85,7 +86,7 @@ public class NewAPI { } /** - * @param player + * @param player a Player * * @return true if the player is unrestricted */ diff --git a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java index b8c7552a2..41672c0c9 100644 --- a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java +++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java @@ -1,11 +1,12 @@ package fr.xephi.authme.cache.auth; -import fr.xephi.authme.security.crypts.HashedPassword; -import org.bukkit.Location; - import static com.google.common.base.Objects.firstNonNull; import static com.google.common.base.Preconditions.checkNotNull; +import org.bukkit.Location; + +import fr.xephi.authme.security.crypts.HashedPassword; + /** */ @@ -24,7 +25,7 @@ public class PlayerAuth { private String realName; /** - * + * @param serialized String */ public PlayerAuth(String serialized) { this.deserialize(serialized); @@ -340,6 +341,8 @@ public class PlayerAuth { /** * Method to deserialize PlayerAuth + * + * @param str String */ public void deserialize(String str) { String[] args = str.split(";"); diff --git a/src/main/java/fr/xephi/authme/command/CommandDescription.java b/src/main/java/fr/xephi/authme/command/CommandDescription.java index d398af674..22a3f05cd 100644 --- a/src/main/java/fr/xephi/authme/command/CommandDescription.java +++ b/src/main/java/fr/xephi/authme/command/CommandDescription.java @@ -12,12 +12,13 @@ import static com.google.common.base.Preconditions.checkArgument; import static java.util.Arrays.asList; /** - * Command description - defines which labels ("names") will lead to a command and points to the + * Command description – defines which labels ("names") will lead to a command and points to the * {@link ExecutableCommand} implementation that executes the logic of the command. * - * CommandDescription instances are built hierarchically and have one parent or {@code null} for base commands - * (main commands such as /authme) and may have multiple children extending the mapping of the parent: e.g. if - * /authme has a child whose label is "register", then "/authme register" is the command that the child defines. + * CommandDescription instances are built hierarchically: they have one parent, or {@code null} for base commands + * (main commands such as {@code /authme}), and may have multiple children extending the mapping of the parent: e.g. if + * {@code /authme} has a child whose label is {@code "register"}, then {@code /authme register} is the command that + * the child defines. */ public class CommandDescription { @@ -102,10 +103,11 @@ public class CommandDescription { } /** - * Get all relative labels of this command. For example, if this object describes "/authme register" and - * "/authme r", then "r" and "register" are the relative labels, whereas "authme" is the label of the parent. + * Return all relative labels of this command. For example, if this object describes {@code /authme register} and + * {@code /authme r}, then it will return a list with {@code register} and {@code r}. The parent label + * {@code authme} is not returned. * - * @return All relative labels. + * @return All labels of the command description. */ public List getLabels() { return labels; diff --git a/src/main/java/fr/xephi/authme/command/CommandHandler.java b/src/main/java/fr/xephi/authme/command/CommandHandler.java index 8a3480eec..e3ab671b4 100644 --- a/src/main/java/fr/xephi/authme/command/CommandHandler.java +++ b/src/main/java/fr/xephi/authme/command/CommandHandler.java @@ -1,11 +1,12 @@ package fr.xephi.authme.command; -import fr.xephi.authme.util.StringUtils; -import org.bukkit.command.CommandSender; - import java.util.ArrayList; import java.util.List; +import org.bukkit.command.CommandSender; + +import fr.xephi.authme.util.StringUtils; + /** * The AuthMe command handler, responsible for mapping incoming commands to the correct {@link CommandDescription} * or to display help messages for unknown invocations. @@ -16,6 +17,8 @@ public class CommandHandler { /** * Create a command handler. + * + * @param commandService The CommandService instance */ public CommandHandler(CommandService commandService) { this.commandService = commandService; @@ -45,6 +48,12 @@ public class CommandHandler { return !FoundResultStatus.MISSING_BASE_COMMAND.equals(result.getResultStatus()); } + /** + * Execute the command for the given command sender. + * + * @param sender The sender which initiated the command + * @param result The mapped result + */ private void executeCommand(CommandSender sender, FoundCommandResult result) { ExecutableCommand executableCommand = result.getCommandDescription().getExecutableCommand(); List arguments = result.getArguments(); diff --git a/src/main/java/fr/xephi/authme/command/CommandService.java b/src/main/java/fr/xephi/authme/command/CommandService.java index b53fc2e8d..08a2790e8 100644 --- a/src/main/java/fr/xephi/authme/command/CommandService.java +++ b/src/main/java/fr/xephi/authme/command/CommandService.java @@ -1,5 +1,9 @@ package fr.xephi.authme.command; +import java.util.List; + +import org.bukkit.command.CommandSender; + import fr.xephi.authme.AuthMe; import fr.xephi.authme.command.help.HelpProvider; import fr.xephi.authme.datasource.DataSource; @@ -8,9 +12,6 @@ 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 org.bukkit.command.CommandSender; - -import java.util.List; /** * Service for implementations of {@link ExecutableCommand} to execute some common tasks. @@ -31,6 +32,7 @@ public class CommandService { * @param commandMapper Command mapper * @param helpProvider Help provider * @param messages Messages instance + * @param passwordSecurity The Password Security instance */ public CommandService(AuthMe authMe, CommandMapper commandMapper, HelpProvider helpProvider, Messages messages, PasswordSecurity passwordSecurity) { @@ -51,6 +53,13 @@ public class CommandService { messages.send(sender, messageKey); } + /** + * Send a message to a player. + * + * @param sender The command sender to send the message to + * @param messageKey The message key to send + * @param replacements The replacement arguments for the message key's tags + */ public void send(CommandSender sender, MessageKey messageKey, String... replacements) { messages.send(sender, messageKey, replacements); } @@ -119,7 +128,7 @@ public class CommandService { } /** - * Returns the management instance of the plugin. + * Return the management instance of the plugin. * * @return The Management instance linked to the AuthMe instance */ @@ -127,11 +136,22 @@ public class CommandService { return authMe.getManagement(); } + /** + * Return the permissions manager. + * + * @return the permissions manager + */ public PermissionsManager getPermissionsManager() { // TODO ljacqu 20151226: Might be nicer to pass the perm manager via constructor return authMe.getPermissionsManager(); } + /** + * Retrieve a message by its message key. + * + * @param key The message to retrieve + * @return The message + */ public String[] retrieveMessage(MessageKey key) { return messages.retrieve(key); } diff --git a/src/main/java/fr/xephi/authme/command/FoundCommandResult.java b/src/main/java/fr/xephi/authme/command/FoundCommandResult.java index 53de7f4d2..520eec243 100644 --- a/src/main/java/fr/xephi/authme/command/FoundCommandResult.java +++ b/src/main/java/fr/xephi/authme/command/FoundCommandResult.java @@ -5,7 +5,7 @@ import java.util.List; /** * Result of a command mapping by {@link CommandHandler}. An object of this class represents a successful mapping * as well as erroneous ones, as communicated with {@link FoundResultStatus}. - *

+ *

* Fields other than {@link FoundResultStatus} are available depending, among other factors, on the status: *

    *
  • {@link FoundResultStatus#SUCCESS} entails that mapping the input to a command was successful. Therefore, diff --git a/src/main/java/fr/xephi/authme/command/PlayerCommand.java b/src/main/java/fr/xephi/authme/command/PlayerCommand.java index a607803b7..2d7aca0b9 100644 --- a/src/main/java/fr/xephi/authme/command/PlayerCommand.java +++ b/src/main/java/fr/xephi/authme/command/PlayerCommand.java @@ -1,10 +1,10 @@ package fr.xephi.authme.command; +import java.util.List; + import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.List; - /** * Common base type for player-only commands, handling the verification that the command sender is indeed a player. */ @@ -35,7 +35,7 @@ public abstract class PlayerCommand implements ExecutableCommand { /** * Return an alternative command (textual representation) that is not restricted to players only. - * Example: "authme register <playerName> <password>" + * Example: {@code "authme register "} * * @return Alternative command not only for players, or null if not applicable */ diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java index 50c833538..e573c6d04 100644 --- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java @@ -7,6 +7,7 @@ import com.google.common.cache.LoadingCache; import com.google.common.cache.RemovalListener; import com.google.common.cache.RemovalListeners; import com.google.common.cache.RemovalNotification; +import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.security.crypts.HashedPassword; @@ -52,15 +53,6 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method isAuthAvailable. - * - * @param user String - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String) - */ @Override public synchronized boolean isAuthAvailable(String user) { return getAuth(user) != null; @@ -91,15 +83,6 @@ public class CacheDataSource implements DataSource { return cachedAuths.getUnchecked(user).orNull(); } - /** - * Method saveAuth. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth) - */ @Override public synchronized boolean saveAuth(PlayerAuth auth) { boolean result = source.saveAuth(auth); @@ -109,15 +92,6 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method updatePassword. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth) - */ @Override public synchronized boolean updatePassword(PlayerAuth auth) { boolean result = source.updatePassword(auth); @@ -137,15 +111,6 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method updateSession. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth) - */ @Override public boolean updateSession(PlayerAuth auth) { boolean result = source.updateSession(auth); @@ -155,47 +120,20 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method updateQuitLoc. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth) - */ @Override public boolean updateQuitLoc(final PlayerAuth auth) { - boolean result = source.updateSession(auth); + boolean result = source.updateQuitLoc(auth); if (result) { cachedAuths.refresh(auth.getNickname()); } return result; } - /** - * Method getIps. - * - * @param ip String - * - * @return int - * - * @see fr.xephi.authme.datasource.DataSource#getIps(String) - */ @Override public int getIps(String ip) { return source.getIps(ip); } - /** - * Method purgeDatabase. - * - * @param until long - * - * @return int - * - * @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long) - */ @Override public int purgeDatabase(long until) { int cleared = source.purgeDatabase(until); @@ -209,15 +147,6 @@ public class CacheDataSource implements DataSource { return cleared; } - /** - * Method autoPurgeDatabase. - * - * @param until long - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long) - */ @Override public List autoPurgeDatabase(long until) { List cleared = source.autoPurgeDatabase(until); @@ -227,15 +156,6 @@ public class CacheDataSource implements DataSource { return cleared; } - /** - * Method removeAuth. - * - * @param name String - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#removeAuth(String) - */ @Override public synchronized boolean removeAuth(String name) { name = name.toLowerCase(); @@ -246,22 +166,17 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method close. - * - * @see fr.xephi.authme.datasource.DataSource#close() - */ @Override public synchronized void close() { - exec.shutdown(); + try { + exec.shutdown(); + exec.awaitTermination(8, TimeUnit.SECONDS); + } catch (InterruptedException e) { + ConsoleLogger.writeStackTrace(e); + } source.close(); } - /** - * Method reload. - * - * @see fr.xephi.authme.datasource.DataSource#reload() - */ @Override public void reload() { // unused method exec.execute(new Runnable() { @@ -273,15 +188,6 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method updateEmail. - * - * @param auth PlayerAuth - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth) - */ @Override public synchronized boolean updateEmail(final PlayerAuth auth) { boolean result = source.updateEmail(auth); @@ -291,55 +197,21 @@ public class CacheDataSource implements DataSource { return result; } - /** - * Method getAllAuthsByName. - * - * @param auth PlayerAuth - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth) - */ @Override public synchronized List getAllAuthsByName(PlayerAuth auth) { return source.getAllAuthsByName(auth); } - /** - * Method getAllAuthsByIp. - * - * @param ip String - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String) - */ @Override public synchronized List getAllAuthsByIp(final String ip) { return source.getAllAuthsByIp(ip); } - /** - * Method getAllAuthsByEmail. - * - * @param email String - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String) - */ @Override public synchronized List getAllAuthsByEmail(final String email) { return source.getAllAuthsByEmail(email); } - /** - * Method purgeBanned. - * - * @param banned List - * - * @see fr.xephi.authme.datasource.DataSource#purgeBanned(List) - */ @Override public synchronized void purgeBanned(final List banned) { exec.execute(new Runnable() { @@ -351,39 +223,16 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method getType. - * - * @return DataSourceType - * - * @see fr.xephi.authme.datasource.DataSource#getType() - */ @Override public DataSourceType getType() { return source.getType(); } - /** - * Method isLogged. - * - * @param user String - * - * @return boolean - * - * @see fr.xephi.authme.datasource.DataSource#isLogged(String) - */ @Override public boolean isLogged(String user) { return PlayerCache.getInstance().isAuthenticated(user); } - /** - * Method setLogged. - * - * @param user String - * - * @see fr.xephi.authme.datasource.DataSource#setLogged(String) - */ @Override public void setLogged(final String user) { exec.execute(new Runnable() { @@ -394,13 +243,6 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method setUnlogged. - * - * @param user String - * - * @see fr.xephi.authme.datasource.DataSource#setUnlogged(String) - */ @Override public void setUnlogged(final String user) { exec.execute(new Runnable() { @@ -411,11 +253,6 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method purgeLogged. - * - * @see fr.xephi.authme.datasource.DataSource#purgeLogged() - */ @Override public void purgeLogged() { exec.execute(new Runnable() { @@ -427,26 +264,11 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method getAccountsRegistered. - * - * @return int - * - * @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered() - */ @Override public int getAccountsRegistered() { return source.getAccountsRegistered(); } - /** - * Method updateName. - * - * @param oldOne String - * @param newOne String - * - * @see fr.xephi.authme.datasource.DataSource#updateName(String, String) - */ @Override public void updateName(final String oldOne, final String newOne) { exec.execute(new Runnable() { @@ -458,25 +280,11 @@ public class CacheDataSource implements DataSource { }); } - /** - * Method getAllAuths. - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#getAllAuths() - */ @Override public List getAllAuths() { return source.getAllAuths(); } - /** - * Method getLoggedPlayers. - * - * @return List - * - * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers() - */ @Override public List getLoggedPlayers() { return new ArrayList<>(PlayerCache.getInstance().getCache().values()); diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java index babba2ccc..2f466defc 100644 --- a/src/main/java/fr/xephi/authme/datasource/DataSource.java +++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java @@ -79,7 +79,7 @@ public interface DataSource { * * @param until long * - * @return List + * @return List of String */ List autoPurgeDatabase(long until); @@ -115,7 +115,7 @@ public interface DataSource { * * @param auth PlayerAuth * - * @return List + * @return List of String */ List getAllAuthsByName(PlayerAuth auth); @@ -124,7 +124,7 @@ public interface DataSource { * * @param ip String * - * @return List * @throws Exception + * @return List of String * @throws Exception */ List getAllAuthsByIp(String ip); @@ -133,7 +133,7 @@ public interface DataSource { * * @param email String * - * @return List * @throws Exception + * @return List of String * @throws Exception */ List getAllAuthsByEmail(String email); @@ -153,7 +153,7 @@ public interface DataSource { /** * Method purgeBanned. * - * @param banned List + * @param banned List of String */ void purgeBanned(List banned); @@ -207,14 +207,14 @@ public interface DataSource { /** * Method getAllAuths. * - * @return List + * @return List of PlayerAuth */ List getAllAuths(); /** * Method getLoggedPlayers. * - * @return List + * @return List of PlayerAuth */ List getLoggedPlayers(); diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java index b84a84c92..4d7b4b38e 100644 --- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java +++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java @@ -406,7 +406,7 @@ public class FlatFile implements DataSource { * * @param until long * - * @return List * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long) + * @return List of String * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long) */ @Override public List autoPurgeDatabase(long until) { @@ -622,7 +622,7 @@ public class FlatFile implements DataSource { * * @param auth PlayerAuth * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth) + * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth) */ @Override public List getAllAuthsByName(PlayerAuth auth) { @@ -659,7 +659,7 @@ public class FlatFile implements DataSource { * * @param ip String * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String) + * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String) */ @Override public List getAllAuthsByIp(String ip) { @@ -696,7 +696,7 @@ public class FlatFile implements DataSource { * * @param email String * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String) + * @return List of String * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String) */ @Override public List getAllAuthsByEmail(String email) { @@ -731,7 +731,7 @@ public class FlatFile implements DataSource { /** * Method purgeBanned. * - * @param banned List + * @param banned List of String * * @see fr.xephi.authme.datasource.DataSource#purgeBanned(List) */ @@ -876,7 +876,7 @@ public class FlatFile implements DataSource { /** * Method getAllAuths. * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuths() + * @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getAllAuths() */ @Override public List getAllAuths() { @@ -928,7 +928,7 @@ public class FlatFile implements DataSource { /** * Method getLoggedPlayers. * - * @return List * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers() + * @return List of PlayerAuth * @see fr.xephi.authme.datasource.DataSource#getLoggedPlayers() */ @Override public List getLoggedPlayers() { diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java index f3870db50..876bbfa18 100644 --- a/src/main/java/fr/xephi/authme/datasource/SQLite.java +++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java @@ -1,11 +1,5 @@ package fr.xephi.authme.datasource; -import fr.xephi.authme.ConsoleLogger; -import fr.xephi.authme.cache.auth.PlayerAuth; -import fr.xephi.authme.security.crypts.HashedPassword; -import fr.xephi.authme.settings.Settings; -import fr.xephi.authme.util.StringUtils; - import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; @@ -15,6 +9,12 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.List; +import fr.xephi.authme.ConsoleLogger; +import fr.xephi.authme.cache.auth.PlayerAuth; +import fr.xephi.authme.security.crypts.HashedPassword; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.StringUtils; + /** */ public class SQLite implements DataSource { @@ -40,7 +40,8 @@ public class SQLite implements DataSource { /** * Constructor for SQLite. * - * @throws ClassNotFoundException * @throws SQLException + * @throws ClassNotFoundException Exception + * @throws SQLException Exception */ public SQLite() throws ClassNotFoundException, SQLException { this.database = Settings.getMySQLDatabase; @@ -69,11 +70,6 @@ public class SQLite implements DataSource { } } - /** - * Method connect. - * - * @throws ClassNotFoundException * @throws SQLException - */ private synchronized void connect() throws ClassNotFoundException, SQLException { Class.forName("org.sqlite.JDBC"); ConsoleLogger.info("SQLite driver loaded"); @@ -81,11 +77,6 @@ public class SQLite implements DataSource { } - /** - * Method setup. - * - * @throws SQLException - */ private synchronized void setup() throws SQLException { Statement st = null; ResultSet rs = null; @@ -147,13 +138,6 @@ public class SQLite implements DataSource { ConsoleLogger.info("SQLite Setup finished"); } - /** - * Method isAuthAvailable. - * - * @param user String - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#isAuthAvailable(String) - */ @Override public synchronized boolean isAuthAvailable(String user) { PreparedStatement pst = null; @@ -224,13 +208,6 @@ public class SQLite implements DataSource { } } - /** - * Method saveAuth. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#saveAuth(PlayerAuth) - */ @Override public synchronized boolean saveAuth(PlayerAuth auth) { PreparedStatement pst = null; @@ -270,13 +247,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method updatePassword. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updatePassword(PlayerAuth) - */ @Override public synchronized boolean updatePassword(PlayerAuth auth) { return updatePassword(auth.getNickname(), auth.getPassword()); @@ -309,13 +279,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method updateSession. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateSession(PlayerAuth) - */ @Override public boolean updateSession(PlayerAuth auth) { PreparedStatement pst = null; @@ -335,13 +298,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method purgeDatabase. - * - * @param until long - * - * @return int * @see fr.xephi.authme.datasource.DataSource#purgeDatabase(long) - */ @Override public int purgeDatabase(long until) { PreparedStatement pst = null; @@ -358,13 +314,6 @@ public class SQLite implements DataSource { } } - /** - * Method autoPurgeDatabase. - * - * @param until long - * - * @return List * @see fr.xephi.authme.datasource.DataSource#autoPurgeDatabase(long) - */ @Override public List autoPurgeDatabase(long until) { PreparedStatement pst = null; @@ -387,13 +336,6 @@ public class SQLite implements DataSource { } } - /** - * Method removeAuth. - * - * @param user String - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#removeAuth(String) - */ @Override public synchronized boolean removeAuth(String user) { PreparedStatement pst = null; @@ -410,13 +352,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method updateQuitLoc. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateQuitLoc(PlayerAuth) - */ @Override public boolean updateQuitLoc(PlayerAuth auth) { PreparedStatement pst = null; @@ -437,13 +372,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method getIps. - * - * @param ip String - * - * @return int * @see fr.xephi.authme.datasource.DataSource#getIps(String) - */ @Override public int getIps(String ip) { PreparedStatement pst = null; @@ -467,13 +395,6 @@ public class SQLite implements DataSource { } } - /** - * Method updateEmail. - * - * @param auth PlayerAuth - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#updateEmail(PlayerAuth) - */ @Override public boolean updateEmail(PlayerAuth auth) { PreparedStatement pst = null; @@ -491,11 +412,6 @@ public class SQLite implements DataSource { return true; } - /** - * Method close. - * - * @see fr.xephi.authme.datasource.DataSource#close() - */ @Override public synchronized void close() { try { @@ -505,20 +421,10 @@ public class SQLite implements DataSource { } } - /** - * Method reload. - * - * @see fr.xephi.authme.datasource.DataSource#reload() - */ @Override public void reload() { } - /** - * Method close. - * - * @param st Statement - */ private void close(Statement st) { if (st != null) { try { @@ -529,11 +435,6 @@ public class SQLite implements DataSource { } } - /** - * Method close. - * - * @param rs ResultSet - */ private void close(ResultSet rs) { if (rs != null) { try { @@ -544,13 +445,6 @@ public class SQLite implements DataSource { } } - /** - * Method getAllAuthsByName. - * - * @param auth PlayerAuth - * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByName(PlayerAuth) - */ @Override public List getAllAuthsByName(PlayerAuth auth) { PreparedStatement pst = null; @@ -575,13 +469,6 @@ public class SQLite implements DataSource { } } - /** - * Method getAllAuthsByIp. - * - * @param ip String - * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByIp(String) - */ @Override public List getAllAuthsByIp(String ip) { PreparedStatement pst = null; @@ -606,13 +493,6 @@ public class SQLite implements DataSource { } } - /** - * Method getAllAuthsByEmail. - * - * @param email String - * - * @return List * @see fr.xephi.authme.datasource.DataSource#getAllAuthsByEmail(String) - */ @Override public List getAllAuthsByEmail(String email) { PreparedStatement pst = null; @@ -653,23 +533,11 @@ public class SQLite implements DataSource { } } - /** - * Method getType. - * - * @return DataSourceType * @see fr.xephi.authme.datasource.DataSource#getType() - */ @Override public DataSourceType getType() { return DataSourceType.SQLITE; } - /** - * Method isLogged. - * - * @param user String - * - * @return boolean * @see fr.xephi.authme.datasource.DataSource#isLogged(String) - */ @Override public boolean isLogged(String user) { PreparedStatement pst = null; @@ -690,13 +558,6 @@ public class SQLite implements DataSource { return false; } - /** - * Method setLogged. - * - * @param user String - * - * @see fr.xephi.authme.datasource.DataSource#setLogged(String) - */ @Override public void setLogged(String user) { PreparedStatement pst = null; @@ -712,13 +573,6 @@ public class SQLite implements DataSource { } } - /** - * Method setUnlogged. - * - * @param user String - * - * @see fr.xephi.authme.datasource.DataSource#setUnlogged(String) - */ @Override public void setUnlogged(String user) { PreparedStatement pst = null; @@ -735,11 +589,6 @@ public class SQLite implements DataSource { } } - /** - * Method purgeLogged. - * - * @see fr.xephi.authme.datasource.DataSource#purgeLogged() - */ @Override public void purgeLogged() { PreparedStatement pst = null; @@ -755,11 +604,6 @@ public class SQLite implements DataSource { } } - /** - * Method getAccountsRegistered. - * - * @return int * @see fr.xephi.authme.datasource.DataSource#getAccountsRegistered() - */ @Override public int getAccountsRegistered() { int result = 0; @@ -795,11 +639,6 @@ public class SQLite implements DataSource { } } - /** - * Method getAllAuths. - * - * @return List - */ @Override public List getAllAuths() { List auths = new ArrayList<>(); @@ -821,11 +660,6 @@ public class SQLite implements DataSource { return auths; } - /** - * Method getLoggedPlayers. - * - * @return List - */ @Override public List getLoggedPlayers() { List auths = new ArrayList<>(); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java index 42a11b3ff..2e365e932 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java @@ -193,7 +193,7 @@ public class AuthMePlayerListener implements Listener { } if (Settings.isForceSurvivalModeEnabled - && !player.hasPermission(PlayerPermission.BYPASS_FORCE_SURVIVAL.getNode())) { + && !player.hasPermission(PlayerPermission.BYPASS_FORCE_SURVIVAL.getNode())) { player.setGameMode(GameMode.SURVIVAL); } @@ -206,9 +206,6 @@ public class AuthMePlayerListener implements Listener { joinMessage.put(name, joinMsg); } - if (Settings.checkVeryGames) - plugin.getVerygamesIp(player); - // Shedule login task so works after the prelogin // (Fix found by Koolaid5000) Bukkit.getScheduler().runTask(plugin, new Runnable() { @@ -222,21 +219,24 @@ public class AuthMePlayerListener implements Listener { @EventHandler(priority = EventPriority.HIGHEST) public void onPreLogin(AsyncPlayerPreLoginEvent event) { PlayerAuth auth = plugin.getDataSource().getAuth(event.getName()); - if (auth != null && auth.getRealName() != null && !auth.getRealName().isEmpty() && - !auth.getRealName().equals("Player") && !auth.getRealName().equals(event.getName())) { - event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); - event.setKickMessage("You should join using username: " + ChatColor.AQUA + auth.getRealName() + - ChatColor.RESET + "\nnot: " + ChatColor.RED + event.getName()); // TODO: write a better message - return; - } - - if (auth != null && auth.getRealName().equals("Player")) { - auth.setRealName(event.getName()); - plugin.getDataSource().saveAuth(auth); + if (Settings.preventOtherCase && auth != null && auth.getRealName() != null) { + String realName = auth.getRealName(); + if (!realName.isEmpty() && !realName.equals("Player") && !realName.equals(event.getName())) { + event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); + // TODO: Add a message like : MessageKey.INVALID_NAME_CASE + event.setKickMessage("You should join using username: " + ChatColor.AQUA + realName + + ChatColor.RESET + "\nnot: " + ChatColor.RED + event.getName()); + return; + } + if (realName.isEmpty() || realName.equals("Player")) { + auth.setRealName(event.getName()); + plugin.getDataSource().saveAuth(auth); + } } + String playerIP = event.getAddress().getHostAddress(); if (auth == null && Settings.enableProtection) { - String countryCode = GeoLiteAPI.getCountryCode(event.getAddress().getHostAddress()); + String countryCode = GeoLiteAPI.getCountryCode(playerIP); if (!Settings.countriesBlacklist.isEmpty() && Settings.countriesBlacklist.contains(countryCode)) { event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER); event.setKickMessage(m.retrieveSingle(MessageKey.COUNTRY_BANNED_ERROR)); @@ -274,21 +274,26 @@ public class AuthMePlayerListener implements Listener { // Get the permissions manager PermissionsManager permsMan = plugin.getPermissionsManager(); - if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL - && permsMan.hasPermission(player, PlayerPermission.IS_VIP)) { - int playersOnline = Utils.getOnlinePlayers().size(); - if (playersOnline > plugin.getServer().getMaxPlayers()) { - event.allow(); - } else { - Player pl = plugin.generateKickPlayer(Utils.getOnlinePlayers()); - if (pl != null) { - pl.kickPlayer(m.retrieveSingle(MessageKey.KICK_FOR_VIP)); + if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL) { + if (permsMan.hasPermission(player, PlayerPermission.IS_VIP)) { + int playersOnline = Utils.getOnlinePlayers().size(); + if (playersOnline > plugin.getServer().getMaxPlayers()) { event.allow(); } else { - ConsoleLogger.info("The player " + event.getPlayer().getName() + " tried to join, but the server was full"); - event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER)); - event.setResult(PlayerLoginEvent.Result.KICK_FULL); + Player pl = plugin.generateKickPlayer(Utils.getOnlinePlayers()); + if (pl != null) { + pl.kickPlayer(m.retrieveSingle(MessageKey.KICK_FOR_VIP)); + event.allow(); + } else { + ConsoleLogger.info("The player " + event.getPlayer().getName() + " tried to join, but the server was full"); + event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER)); + event.setResult(PlayerLoginEvent.Result.KICK_FULL); + } } + } else { + event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER)); + event.setResult(PlayerLoginEvent.Result.KICK_FULL); + return; } } @@ -296,12 +301,6 @@ public class AuthMePlayerListener implements Listener { return; } - if (event.getResult() == PlayerLoginEvent.Result.KICK_FULL && !permsMan.hasPermission(player, PlayerPermission.IS_VIP)) { - event.setKickMessage(m.retrieveSingle(MessageKey.KICK_FULL_SERVER)); - event.setResult(PlayerLoginEvent.Result.KICK_FULL); - return; - } - final String name = player.getName().toLowerCase(); boolean isAuthAvailable = plugin.getDataSource().isAuthAvailable(name); diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java deleted file mode 100644 index eed3bd908..000000000 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java +++ /dev/null @@ -1,30 +0,0 @@ -package fr.xephi.authme.listener; - -import org.bukkit.entity.Player; - -import fr.xephi.authme.AuthMe; -import fr.xephi.authme.settings.Settings; - -public class AuthMeServerStop extends Thread { - - private AuthMe plugin; - - public AuthMeServerStop(AuthMe plugin) { - this.plugin = plugin; - } - - public void run() { - // TODO: add a MessageKey - if (Settings.kickPlayersBeforeStopping) { - plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() - { - @Override - public void run() { - for (Player p : plugin.getServer().getOnlinePlayers()) { - p.kickPlayer("Server is restarting"); - } - } - }); - } - } -} diff --git a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java index f09de526a..24e64c742 100644 --- a/src/main/java/fr/xephi/authme/permission/DefaultPermission.java +++ b/src/main/java/fr/xephi/authme/permission/DefaultPermission.java @@ -25,7 +25,11 @@ public enum DefaultPermission { this.title = title; } - /** Return the textual representation. */ + /** + * Return the textual representation. + * + * @return String + */ public String getTitle() { return title; } diff --git a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java index 09b235254..9078b1ab7 100644 --- a/src/main/java/fr/xephi/authme/permission/PermissionsManager.java +++ b/src/main/java/fr/xephi/authme/permission/PermissionsManager.java @@ -1,10 +1,11 @@ package fr.xephi.authme.permission; -import de.bananaco.bpermissions.api.ApiLayer; -import de.bananaco.bpermissions.api.CalculableType; -import fr.xephi.authme.command.CommandDescription; -import fr.xephi.authme.util.CollectionUtils; -import net.milkbowl.vault.permission.Permission; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + import org.anjocaido.groupmanager.GroupManager; import org.anjocaido.groupmanager.permissions.AnjoPermissionsHandler; import org.bukkit.Bukkit; @@ -17,24 +18,25 @@ import org.bukkit.plugin.Plugin; import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.RegisteredServiceProvider; import org.tyrannyofheaven.bukkit.zPermissions.ZPermissionsService; + +import de.bananaco.bpermissions.api.ApiLayer; +import de.bananaco.bpermissions.api.CalculableType; +import fr.xephi.authme.command.CommandDescription; +import fr.xephi.authme.util.CollectionUtils; +import net.milkbowl.vault.permission.Permission; import ru.tehkode.permissions.PermissionManager; import ru.tehkode.permissions.PermissionUser; import ru.tehkode.permissions.bukkit.PermissionsEx; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.logging.Logger; - /** + *

    * PermissionsManager. - *

    + *

    * A permissions manager, to manage and use various permissions systems. * This manager supports dynamic plugin hooking and various other features. - *

    + *

    * Written by Tim Visée. - * + *

    * @author Tim Visée, http://timvisee.com * @version 0.2.1 */ @@ -296,8 +298,8 @@ public class PermissionsManager implements PermissionsService { } Player player = (Player) sender; - return hasPermission(player, permissionNode.getNode(), def) - || hasPermission(player, permissionNode.getWildcardNode().getNode(), def); + return hasPermission(player, permissionNode.getNode(), def); + // || hasPermission(player, permissionNode.getWildcardNode().getNode(), def); } public boolean hasPermission(Player player, Iterable nodes, boolean def) { 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 56656e97f..cbdac41eb 100644 --- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java +++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java @@ -49,6 +49,10 @@ public class AsynchronousJoin { } public void process() { + if (Settings.checkVeryGames) { + plugin.getVerygamesIp(player); + } + if (Utils.isUnrestricted(player)) { return; } @@ -58,6 +62,8 @@ public class AsynchronousJoin { } final String ip = plugin.getIP(player); + + if (Settings.isAllowRestrictedIp && !Settings.getRestrictedIp(name, ip, player.getAddress().getHostName())) { sched.scheduleSyncDelayedTask(plugin, new Runnable() { @@ -110,7 +116,6 @@ public class AsynchronousJoin { }); } } - placePlayerSafely(player, spawnLoc); LimboCache.getInstance().updateLimboPlayer(player); @@ -126,6 +131,22 @@ public class AsynchronousJoin { } } + if (Settings.isSessionsEnabled && (PlayerCache.getInstance().isAuthenticated(name) || database.isLogged(name))) { + if (plugin.sessions.containsKey(name)) { + plugin.sessions.get(name).cancel(); + plugin.sessions.remove(name); + } + PlayerAuth auth = database.getAuth(name); + database.setUnlogged(name); + PlayerCache.getInstance().removePlayer(name); + if (auth != null && auth.getIp().equals(ip)) { + m.send(player, MessageKey.SESSION_RECONNECTION); + plugin.getManagement().performLogin(player, "dontneed", true); + return; + } else if (Settings.sessionExpireOnIpChange) { + m.send(player, MessageKey.SESSION_EXPIRED); + } + } } else { if (!Settings.unRegisteredGroup.isEmpty()) { Utils.setGroup(player, Utils.GroupType.UNREGISTERED); @@ -179,7 +200,7 @@ public class AsynchronousJoin { if (Settings.applyBlindEffect) { int blindTimeOut; // Allow infinite blindness effect - if(timeOut <= 0) { + if (timeOut <= 0) { blindTimeOut = 99999; } else { blindTimeOut = timeOut; @@ -196,23 +217,6 @@ public class AsynchronousJoin { LimboCache.getInstance().getLimboPlayer(name).setTimeoutTaskId(id); } - if (Settings.isSessionsEnabled && isAuthAvailable && (PlayerCache.getInstance().isAuthenticated(name) || database.isLogged(name))) { - if (plugin.sessions.containsKey(name)) { - plugin.sessions.get(name).cancel(); - plugin.sessions.remove(name); - } - PlayerAuth auth = database.getAuth(name); - database.setUnlogged(name); - PlayerCache.getInstance().removePlayer(name); - if (auth != null && auth.getIp().equals(ip)) { - m.send(player, MessageKey.SESSION_RECONNECTION); - plugin.getManagement().performLogin(player, "dontneed", true); - return; - } else if (Settings.sessionExpireOnIpChange) { - m.send(player, MessageKey.SESSION_EXPIRED); - } - } - String[] msg; if (isAuthAvailable) { msg = m.retrieve(MessageKey.LOGIN_MESSAGE); 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 8297224bf..9b911da17 100644 --- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java @@ -33,6 +33,7 @@ public class AsynchronousLogin { private final AuthMe plugin; private final DataSource database; private final Messages m; + private final String ip; /** * Constructor for AsynchronousLogin. @@ -52,10 +53,7 @@ public class AsynchronousLogin { this.forceLogin = forceLogin; this.plugin = plugin; this.database = data; - } - - protected String getIP() { - return plugin.getIP(player); + this.ip = plugin.getIP(player); } protected boolean needsCaptcha() { @@ -87,7 +85,9 @@ public class AsynchronousLogin { m.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); return null; } - if (!database.isAuthAvailable(name)) { + + PlayerAuth pAuth = database.getAuth(name); + if (pAuth == null) { m.send(player, MessageKey.USER_NOT_REGISTERED); if (LimboCache.getInstance().hasLimboPlayer(name)) { LimboCache.getInstance().getLimboPlayer(name).getMessageTaskId().cancel(); @@ -97,43 +97,45 @@ public class AsynchronousLogin { } else { msg = m.retrieve(MessageKey.REGISTER_MESSAGE); } - BukkitTask msgT = Bukkit.getScheduler().runTaskAsynchronously(plugin, new MessageTask(plugin, name, msg, Settings.getWarnMessageInterval)); + BukkitTask msgT = Bukkit.getScheduler().runTaskAsynchronously(plugin, + new MessageTask(plugin, name, msg, Settings.getWarnMessageInterval)); LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT); } return null; } - if (Settings.getMaxLoginPerIp > 0 && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) && !getIP().equalsIgnoreCase("127.0.0.1") && !getIP().equalsIgnoreCase("localhost")) { - if (plugin.isLoggedIp(name, getIP())) { - m.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); - return null; - } - } - PlayerAuth pAuth = database.getAuth(name); - if (pAuth == null) { - m.send(player, MessageKey.USER_NOT_REGISTERED); - return null; - } + if (!Settings.getMySQLColumnGroup.isEmpty() && pAuth.getGroupId() == Settings.getNonActivatedGroup) { m.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED); return null; } - if (Settings.preventOtherCase && !player.getName().equals(pAuth.getRealName())) { - // TODO: Add a message like : MessageKey.INVALID_NAME_CASE - m.send(player, MessageKey.USERNAME_ALREADY_ONLINE_ERROR); - return null; + if (Settings.getMaxLoginPerIp > 0 + && !plugin.getPermissionsManager().hasPermission(player, PlayerPermission.ALLOW_MULTIPLE_ACCOUNTS) + && !ip.equalsIgnoreCase("127.0.0.1") && !ip.equalsIgnoreCase("localhost")) { + if (plugin.isLoggedIp(name, ip)) { + m.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); + return null; + } } + AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player); Bukkit.getServer().getPluginManager().callEvent(event); - if (!event.canLogin()) + if (!event.canLogin()) { return null; + } return pAuth; } public void process() { PlayerAuth pAuth = preAuth(); - if (pAuth == null || needsCaptcha()) + if (pAuth == null || needsCaptcha()) { return; + } + + if (pAuth.getIp().equals("127.0.0.1") && !pAuth.getIp().equals(ip)) { + pAuth.setIp(ip); + database.saveAuth(pAuth); + } String email = pAuth.getEmail(); boolean passwordVerified = forceLogin || plugin.getPasswordSecurity() @@ -143,7 +145,7 @@ public class AsynchronousLogin { PlayerAuth auth = PlayerAuth.builder() .name(name) .realName(realName) - .ip(getIP()) + .ip(ip) .lastLogin(new Date().getTime()) .email(email) .password(pAuth.getPassword()) @@ -184,14 +186,16 @@ 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. - ProcessSyncronousPlayerLogin syncronousPlayerLogin = new ProcessSyncronousPlayerLogin(player, plugin, database); - if (syncronousPlayerLogin.getLimbo() != null) { - if (syncronousPlayerLogin.getLimbo().getTimeoutTaskId() != null) - syncronousPlayerLogin.getLimbo().getTimeoutTaskId().cancel(); - if (syncronousPlayerLogin.getLimbo().getMessageTaskId() != null) - syncronousPlayerLogin.getLimbo().getMessageTaskId().cancel(); + ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database); + if (syncPlayerLogin.getLimbo() != null) { + if (syncPlayerLogin.getLimbo().getTimeoutTaskId() != null) { + syncPlayerLogin.getLimbo().getTimeoutTaskId().cancel(); + } + if (syncPlayerLogin.getLimbo().getMessageTaskId() != null) { + syncPlayerLogin.getLimbo().getMessageTaskId().cancel(); + } } - Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, syncronousPlayerLogin); + Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, syncPlayerLogin); } else if (player.isOnline()) { if (!Settings.noConsoleSpam) ConsoleLogger.info(realName + " used the wrong password"); diff --git a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java similarity index 96% rename from src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java rename to src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java index c4562d506..27c09174e 100644 --- a/src/main/java/fr/xephi/authme/process/login/ProcessSyncronousPlayerLogin.java +++ b/src/main/java/fr/xephi/authme/process/login/ProcessSyncPlayerLogin.java @@ -26,7 +26,7 @@ import fr.xephi.authme.util.Utils.GroupType; /** */ -public class ProcessSyncronousPlayerLogin implements Runnable { +public class ProcessSyncPlayerLogin implements Runnable { private final LimboPlayer limbo; private final Player player; @@ -38,14 +38,14 @@ public class ProcessSyncronousPlayerLogin implements Runnable { private final JsonCache playerCache; /** - * Constructor for ProcessSyncronousPlayerLogin. + * Constructor for ProcessSyncPlayerLogin. * * @param player Player * @param plugin AuthMe * @param data DataSource */ - public ProcessSyncronousPlayerLogin(Player player, AuthMe plugin, - DataSource data) { + public ProcessSyncPlayerLogin(Player player, AuthMe plugin, + DataSource data) { this.plugin = plugin; this.database = data; this.pm = plugin.getServer().getPluginManager(); diff --git a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java index 42c633afc..2a3a5d3e0 100644 --- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java +++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java @@ -93,6 +93,7 @@ public class AsynchronousQuit { database.setUnlogged(name); } + plugin.realIp.remove(name); Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerQuit(plugin, player, isOp, needToChange)); } } diff --git a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java index 50572eb61..6d9ab98dc 100644 --- a/src/main/java/fr/xephi/authme/security/HashAlgorithm.java +++ b/src/main/java/fr/xephi/authme/security/HashAlgorithm.java @@ -3,9 +3,8 @@ package fr.xephi.authme.security; import fr.xephi.authme.security.crypts.EncryptionMethod; /** - * The list of hash algorithms supported by AuthMe. The implementing class must define a public - * constructor which takes either no arguments, or a DataSource object (when the salt is stored - * separately, writes to the database are necessary). + * The list of hash algorithms supported by AuthMe. The linked {@link EncryptionMethod} implementation + * must be able to be instantiated with the default constructor. */ public enum HashAlgorithm { diff --git a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java index eb8c717a9..a8ea653bb 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java +++ b/src/main/java/fr/xephi/authme/security/crypts/BCRYPT.java @@ -15,6 +15,7 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.security.crypts.description.HasSalt; +import fr.xephi.authme.security.crypts.description.Usage; import fr.xephi.authme.security.crypts.description.Recommendation; import fr.xephi.authme.security.crypts.description.SaltType; import fr.xephi.authme.security.crypts.description.Usage; @@ -108,7 +109,6 @@ public class BCRYPT implements EncryptionMethod { * * @throws IllegalArgumentException if the length is invalid */ - private static String encode_base64(byte d[], int len) throws IllegalArgumentException { int off = 0; diff --git a/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java b/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java index 269c1365e..cd8af9249 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java +++ b/src/main/java/fr/xephi/authme/security/crypts/CRAZYCRYPT1.java @@ -10,8 +10,6 @@ import fr.xephi.authme.security.crypts.description.HasSalt; import java.nio.charset.Charset; import java.security.MessageDigest; -@Recommendation(Usage.DO_NOT_USE) -@HasSalt(SaltType.USERNAME) public class CRAZYCRYPT1 extends UsernameSaltMethod { private static final char[] CRYPTCHARS = diff --git a/src/main/java/fr/xephi/authme/security/crypts/IPB3.java b/src/main/java/fr/xephi/authme/security/crypts/IPB3.java index 85789b881..4abfe5d45 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/IPB3.java +++ b/src/main/java/fr/xephi/authme/security/crypts/IPB3.java @@ -8,7 +8,7 @@ import fr.xephi.authme.security.crypts.description.Usage; import static fr.xephi.authme.security.HashUtils.md5; -@Recommendation(Usage.DO_NOT_USE) +@Recommendation(Usage.ACCEPTABLE) @HasSalt(value = SaltType.TEXT, length = 5) public class IPB3 extends SeparateSaltMethod { diff --git a/src/main/java/fr/xephi/authme/security/crypts/MYBB.java b/src/main/java/fr/xephi/authme/security/crypts/MYBB.java index 97418640c..555f3213a 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/MYBB.java +++ b/src/main/java/fr/xephi/authme/security/crypts/MYBB.java @@ -1,9 +1,15 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.security.RandomString; +import fr.xephi.authme.security.crypts.description.HasSalt; +import fr.xephi.authme.security.crypts.description.Recommendation; +import fr.xephi.authme.security.crypts.description.SaltType; +import fr.xephi.authme.security.crypts.description.Usage; import static fr.xephi.authme.security.HashUtils.md5; +@Recommendation(Usage.ACCEPTABLE) +@HasSalt(value = SaltType.TEXT, length = 8) public class MYBB extends SeparateSaltMethod { @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/WBB3.java b/src/main/java/fr/xephi/authme/security/crypts/WBB3.java index 6cc123005..28e975856 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/WBB3.java +++ b/src/main/java/fr/xephi/authme/security/crypts/WBB3.java @@ -1,9 +1,15 @@ package fr.xephi.authme.security.crypts; import fr.xephi.authme.security.RandomString; +import fr.xephi.authme.security.crypts.description.HasSalt; +import fr.xephi.authme.security.crypts.description.Recommendation; +import fr.xephi.authme.security.crypts.description.SaltType; +import fr.xephi.authme.security.crypts.description.Usage; import static fr.xephi.authme.security.HashUtils.sha1; +@Recommendation(Usage.ACCEPTABLE) +@HasSalt(value = SaltType.TEXT, length = 40) public class WBB3 extends SeparateSaltMethod { @Override diff --git a/src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java b/src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java index 0169d1927..72d8e8fb6 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java +++ b/src/main/java/fr/xephi/authme/security/crypts/WHIRLPOOL.java @@ -241,8 +241,9 @@ public class WHIRLPOOL extends UnsaltedMethod { * * @param source plaintext data to hash. * @param sourceBits how many bits of plaintext to process. - *

    - * This method maintains the invariant: bufferBits < 512 + *

    + * This method maintains the invariant: bufferBits < 512 + *

    */ public void NESSIEadd(byte[] source, long sourceBits) { /* @@ -322,10 +323,12 @@ public class WHIRLPOOL extends UnsaltedMethod { } /** + *

    * Get the hash value from the hashing state. - *

    - * This method uses the invariant: bufferBits < 512 - * + *

    + *

    + * This method uses the invariant: bufferBits < 512 + *

    * @param digest byte[] */ public void NESSIEfinalize(byte[] digest) { @@ -367,7 +370,7 @@ public class WHIRLPOOL extends UnsaltedMethod { * Delivers string input data to the hashing algorithm. * * @param source plaintext data to hash (ASCII text string). - * This method maintains the invariant: bufferBits < 512 + * This method maintains the invariant: bufferBits < 512 */ public void NESSIEadd(String source) { if (source.length() > 0) { diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java b/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java index f515717e7..bf179fff2 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java +++ b/src/main/java/fr/xephi/authme/security/crypts/description/AsciiRestricted.java @@ -6,7 +6,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Denotes an encryption algorithm that is restricted to the ASCII charset. + * Denotes a hashing algorithm that is restricted to the ASCII charset. */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java b/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java index 1baf1e196..0723a4ddb 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java +++ b/src/main/java/fr/xephi/authme/security/crypts/description/HasSalt.java @@ -13,10 +13,18 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface HasSalt { - /** The type of the salt. */ + /** + * The type of the salt. + * + * @return The salt type + */ SaltType value(); - /** For text salts, the length of the salt. */ + /** + * For text salts, the length of the salt. + * + * @return The length of the salt the algorithm uses, or 0 if not defined or not applicable. + */ int length() default 0; } diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java b/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java index f37c3eac3..4b832a681 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java +++ b/src/main/java/fr/xephi/authme/security/crypts/description/Recommendation.java @@ -6,13 +6,19 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** - * Annotation to mark a hash algorithm with the usage recommendation, see {@link Usage}. + * Annotation to mark a hash algorithm with the usage recommendation. + * + * @see Usage */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Recommendation { - /** The recommendation for using the hash algorithm. */ + /** + * The recommendation for using the hash algorithm. + * + * @return The recommended usage + */ Usage value(); } diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java b/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java index 7d6b225ca..40b923fa9 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java +++ b/src/main/java/fr/xephi/authme/security/crypts/description/SaltType.java @@ -8,7 +8,7 @@ public enum SaltType { /** Random, newly generated text. */ TEXT, - /** Salt is based on the username, including variations and repetitions. */ + /** Salt is based on the username, including variations and repetitions thereof. */ USERNAME, /** No salt. */ diff --git a/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java b/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java index ecf37a980..c11c335ac 100644 --- a/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java +++ b/src/main/java/fr/xephi/authme/security/crypts/description/Usage.java @@ -2,6 +2,12 @@ package fr.xephi.authme.security.crypts.description; /** * Usage recommendation that can be provided for a hash algorithm. + *

    + * Use the following rules of thumb: + *

      + *
    • Hashes using MD5 may be {@link #ACCEPTABLE} but never {@link #RECOMMENDED}.
    • + *
    • Hashes using no salt or one based on the username should be {@link #DO_NOT_USE}.
    • + *
    */ public enum Usage { diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java b/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java index 5b0268c18..88ff11bfc 100644 --- a/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java +++ b/src/main/java/fr/xephi/authme/security/pbkdf2/MacBasedPRF.java @@ -1,15 +1,16 @@ package fr.xephi.authme.security.pbkdf2; -import javax.crypto.Mac; -import javax.crypto.spec.SecretKeySpec; import java.security.InvalidKeyException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + /** - * Default PRF implementation based on standard javax.crypt.Mac mechanisms. *

    - *


    + * Default PRF implementation based on standard javax.crypt.Mac mechanisms. + *

    *

    * A free Java implementation of Password Based Key Derivation Function 2 as * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java index d1dab3025..59bc96df2 100644 --- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java +++ b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2.java @@ -75,7 +75,7 @@ public interface PBKDF2 { /** * Allow setting of configured parameters. * - * @param parameters + * @param parameters PBKDF2Parameters */ void setParameters(PBKDF2Parameters parameters); diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Engine.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Engine.java index c78f786ad..d32b8752d 100644 --- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Engine.java +++ b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Engine.java @@ -8,20 +8,17 @@ import java.security.SecureRandom; /** *

    * Request for Comments: 2898 PKCS #5: Password-Based Cryptography Specification - *

    + *

    * Version 2.0 - *

    + *

    *

    * PBKDF2 (P, S, c, dkLen) - *

    - *

    + *

    * Options: *
      *
    • PRF underlying pseudorandom function (hLen denotes the length in octets * of the pseudorandom function output). PRF is pluggable.
    • *
    - *

    - *

    * Input: *

      *
    • P password, an octet string
    • @@ -30,15 +27,11 @@ import java.security.SecureRandom; *
    • dkLen intended length in octets of the derived key, a positive integer, * at most (2^32 - 1) * hLen
    • *
    - *

    - *

    * Output: *

      *
    • DK derived key, a dkLen-octet string
    • *
    *

    - *


    - *

    * A free Java implementation of Password Based Key Derivation Function 2 as * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner *

    @@ -115,13 +108,14 @@ public class PBKDF2Engine implements PBKDF2 { * ISO-8559-1 encoding. Output result as * "Salt:iteration-count:PBKDF2" with binary data in hexadecimal * encoding. - *

    + *

    * Example: Password "password" (without the quotes) leads to * 48290A0B96C426C3:1000:973899B1D4AFEB3ED371060D0797E0EE0142BD04 - * + *

    * @param args Supply the password as argument. * - * @throws IOException * @throws NoSuchAlgorithmException * @throws NoSuchAlgorithmException + * @throws IOException an ioexception occured + * @throws NoSuchAlgorithmException a NoSuchAlgorithmException occured */ public static void main(String[] args) throws IOException, NoSuchAlgorithmException { @@ -266,8 +260,8 @@ public class PBKDF2Engine implements PBKDF2 { /** * Integer division with ceiling function. * - * @param a - * @param b + * @param a Integer + * @param b Integer * * @return ceil(a/b) * @see RFC 2898 5.2 Step * 2. @@ -288,7 +282,7 @@ public class PBKDF2Engine implements PBKDF2 { * @param prf Pseudo Random Function * @param S Salt as array of bytes * @param c Iteration count - * @param blockIndex + * @param blockIndex Integer * * @see RFC 2898 5.2 Step * 3. @@ -314,8 +308,8 @@ public class PBKDF2Engine implements PBKDF2 { * Block-Xor. Xor source bytes into destination byte buffer. Destination * buffer must be same length or less than source buffer. * - * @param dest - * @param src + * @param dest byte array + * @param src byte array */ protected void xor(byte[] dest, byte[] src) { for (int i = 0; i < dest.length; i++) { @@ -326,9 +320,9 @@ public class PBKDF2Engine implements PBKDF2 { /** * Four-octet encoding of the integer i, most significant octet first. * - * @param dest - * @param offset - * @param i + * @param dest byte array + * @param offset Integer + * @param i Integer * * @see RFC 2898 5.2 Step * 3. diff --git a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Parameters.java b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Parameters.java index b7b158a0c..04abaa9f8 100644 --- a/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Parameters.java +++ b/src/main/java/fr/xephi/authme/security/pbkdf2/PBKDF2Parameters.java @@ -5,8 +5,6 @@ package fr.xephi.authme.security.pbkdf2; * Parameter data holder for PBKDF2 configuration. *

    *

    - *


    - *

    * A free Java implementation of Password Based Key Derivation Function 2 as * defined by RFC 2898. Copyright (c) 2007 Matthias Gärtner *

    diff --git a/src/main/java/fr/xephi/authme/settings/OtherAccounts.java b/src/main/java/fr/xephi/authme/settings/OtherAccounts.java index 063e6af60..6e2796a32 100644 --- a/src/main/java/fr/xephi/authme/settings/OtherAccounts.java +++ b/src/main/java/fr/xephi/authme/settings/OtherAccounts.java @@ -1,13 +1,13 @@ package fr.xephi.authme.settings; -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; - import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + /** * @author Xephi59 * @version $Revision: 1.0 $ @@ -88,7 +88,7 @@ public class OtherAccounts extends CustomConfiguration { * * @param uuid UUID * - * @return List + * @return StringList */ public List getAllPlayersByUUID(UUID uuid) { return this.getStringList(uuid.toString()); diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 6080d45eb..cfb28f75e 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -1,32 +1,27 @@ 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.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.io.InputStream; -import java.io.InputStreamReader; -import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.regex.Pattern; -import org.bukkit.configuration.file.YamlConfiguration; - -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.Wrapper; - /** */ public final class Settings { @@ -122,7 +117,7 @@ public final class Settings { /** * Method reload. * - * @throws Exception + * @throws Exception if something went wrong */ public static void reload() throws Exception { plugin.getLogger().info("Loading Configuration File..."); @@ -141,7 +136,6 @@ public final class Settings { messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml"); } - public static void loadVariables() { helpHeader = configFile.getString("settings.helpHeader", "AuthMeReloaded"); messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage", "en").toLowerCase()); @@ -311,35 +305,22 @@ public final class Settings { } private static String loadEmailText() { - if (!EMAIL_FILE.exists()) - saveDefaultEmailText(); - StringBuilder str = new StringBuilder(); - try { - BufferedReader in = new BufferedReader(new FileReader(EMAIL_FILE)); - String s; - while ((s = in.readLine()) != null) - str.append(s); - in.close(); - } catch (IOException ignored) { + if (!EMAIL_FILE.exists()) { + plugin.saveResource("email.html", false); } - return str.toString(); - } - - private static void saveDefaultEmailText() { - InputStream file = plugin.getResource("email.html"); - StringBuilder str = new StringBuilder(); try { - BufferedReader in = new BufferedReader(new InputStreamReader(file, Charset.forName("utf-8"))); - String s; - while ((s = in.readLine()) != null) - str.append(s); - in.close(); - Files.touch(EMAIL_FILE); - Files.write(str.toString(), EMAIL_FILE, Charsets.UTF_8); - } catch (Exception ignored) { + return Files.toString(EMAIL_FILE, Charsets.UTF_8); + } catch (IOException e) { + ConsoleLogger.showError(e.getMessage()); + ConsoleLogger.writeStackTrace(e); + return ""; } } + /** + * @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(); @@ -380,8 +361,9 @@ public final class Settings { * 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 name String + * @param ip String + * @param domain String * * @return boolean */ @@ -396,14 +378,12 @@ public final class Settings { String testIp = args[1]; if (testName.equalsIgnoreCase(name)) { nameFound = true; - if (ip != null) - { + if (ip != null) { if (testIp.equalsIgnoreCase(ip)) { trueOnce = true; } } - if (domain != null) - { + if (domain != null) { if (testIp.equalsIgnoreCase(domain)) { trueOnce = true; } @@ -737,10 +717,9 @@ public final class Settings { changes = true; } - if (!contains("settings.preventOtherCase")) - { - set("settings.preventOtherCase", false); - changes = true; + if (!contains("settings.preventOtherCase")) { + set("settings.preventOtherCase", false); + changes = true; } if (contains("Email.mailText")) { @@ -749,15 +728,14 @@ public final class Settings { } if (!contains("Security.stop.kickPlayersBeforeStopping")) { - set("Security.stop.kickPlayersBeforeStopping", true); - changes = true; + set("Security.stop.kickPlayersBeforeStopping", true); + changes = true; } if (!contains("Email.emailOauth2Token")) - set("Email.emailOauth2Token", ""); + set("Email.emailOauth2Token", ""); - if (!contains("Hook.sendPlayerTo")) - { + if (!contains("Hook.sendPlayerTo")) { set("Hooks.sendPlayerTo", ""); changes = true; } @@ -768,11 +746,21 @@ public final class Settings { } } + /** + * @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); } diff --git a/src/main/java/fr/xephi/authme/util/CollectionUtils.java b/src/main/java/fr/xephi/authme/util/CollectionUtils.java index 101ad968f..5c3eaa7f7 100644 --- a/src/main/java/fr/xephi/authme/util/CollectionUtils.java +++ b/src/main/java/fr/xephi/authme/util/CollectionUtils.java @@ -15,6 +15,8 @@ public final class CollectionUtils { /** * Get a range from a list based on start and count parameters in a safe way. * + * @param element + * @param list The List * @param start The start index * @param count The number of elements to add * @@ -34,6 +36,8 @@ public final class CollectionUtils { /** * Get all elements from a list starting from the given index. * + * @param element + * @param list The List * @param start The start index * * @return The sublist of all elements from index {@code start} and on; empty list @@ -46,6 +50,11 @@ public final class CollectionUtils { return getRange(list, start, list.size() - start); } + /** + * @param element + * @param coll Collection + * @return boolean Boolean + */ public static boolean isEmpty(Collection coll) { return coll == null || coll.isEmpty(); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ec382c7c9..69e954e36 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -45,120 +45,144 @@ commands: usage: /converter permissions: authme.admin.*: - description: Gives access to all authme admin commands - children: - authme.admin.reload: true - authme.admin.register: true - authme.admin.changepassword: true - authme.admin.unregister: true - authme.admin.purge: true - authme.seeOtherAccounts: true # This isn't a child of the admin section! Probably doesn't work. - authme.admin.lastlogin: true - authme.admin.getemail: true - authme.admin.chgemail: true - authme.admin.purgelastpos: true - authme.admin.switchantibot: true - authme.bypassantibot: true # This isn't a child of the admin section! Probably doesn't work. - authme.admin.getip: true - authme.admin.converter: true - authme.admin.resetposition: true - authme.admin.forcelogin: true - authme.register: - description: Register an account - default: true - authme.login: - description: Login into a account - default: true - authme.changepassword: - description: Change password of a account - default: true - authme.logout: - description: Logout - default: true - authme.email: - description: Email - default: true - authme.allow2accounts: - description: allow more accounts for same ip - default: false - authme.seeOtherAccounts: - description: display other accounts about a player when he logs in - default: false - authme.unregister: - description: unregister your account - default: true - authme.admin.reload: - description: AuthMe reload commands - default: op + description: Give access to all admin commands. + children: + authme.admin.accounts: true + authme.admin.changemail: true + authme.admin.changepassword: true + authme.admin.converter: true + authme.admin.firstspawn: true + authme.admin.forcelogin: true + authme.admin.getemail: true + authme.admin.getip: true + authme.admin.lastlogin: true + authme.admin.purge: true + authme.admin.purgebannedplayers: true + authme.admin.purgelastpos: true + authme.admin.register: true + authme.admin.reload: true + authme.admin.setfirstspawn: true + authme.admin.setspawn: true + authme.admin.spawn: true + authme.admin.switchantibot: true + authme.admin.unregister: true authme.admin.register: - description: AuthMe register command - default: op - authme.admin.changepassword: - description: AuthMe changepassword command + description: Administrator command to register a new user. default: op authme.admin.unregister: - description: AuthMe unregister command - default: op - authme.admin.purge: - description: AuthMe unregister command - default: op - authme.admin.lastlogin: - description: Get last login date about a player - default: op - authme.admin.getemail: - description: Get last email about a player - default: op - authme.admin.chgemail: - description: Change a player email - default: op - authme.admin.accounts: - description: Display Players Accounts - default: op - authme.captcha: - description: Captcha - default: true - authme.admin.setspawn: - description: Set the AuthMe spawn point - default: op - authme.admin.spawn: - description: Teleport to AuthMe spawn point - default: op - authme.vip: - description: Allow vip slot when the server is full - default: op - authme.admin.purgebannedplayers: - description: Purge banned players - default: op - authme.bypassforcesurvival: - description: Bypass all ForceSurvival features - default: false - authme.admin.purgelastpos: - description: Purge last pos of players - default: op - authme.admin.switchantibot: - description: Switch AntiBot mode on/off - default: op - authme.bypassantibot: - description: Bypass the AntiBot check - default: op - authme.admin.setfirstspawn: - description: Set the AuthMe First Spawn Point - default: op - authme.admin.firstspawn: - description: Teleport to AuthMe First Spawn Point - default: op - authme.admin.getip: - description: Get IP from a player ( fake and real ) - default: op - authme.admin.converter: - description: Allow /converter command - default: op - authme.admin.resetposition: - description: Reset last position for a player + description: Administrator command to unregister an existing user. default: op authme.admin.forcelogin: - description: Force login for that player + description: Administrator command to force-login an existing user. default: op - authme.canbeforced: - description: Can this player be forced to login + authme.admin.changepassword: + description: Administrator command to change the password of a user. + default: op + authme.admin.lastlogin: + description: Administrator command to see the last login date and time of a user. + default: op + authme.admin.accounts: + description: Administrator command to see all accounts associated with a user. + default: op + authme.admin.getemail: + description: Administrator command to get the email address of a user, if set. + default: op + authme.admin.changemail: + description: Administrator command to set or change the email address of a user. + default: op + authme.admin.getip: + description: Administrator command to get the last known IP of a user. + default: op + authme.admin.spawn: + description: Administrator command to teleport to the AuthMe spawn. + default: op + authme.admin.setspawn: + description: Administrator command to set the AuthMe spawn. + default: op + authme.admin.firstspawn: + description: Administrator command to teleport to the first AuthMe spawn. + default: op + authme.admin.setfirstspawn: + description: Administrator command to set the first AuthMe spawn. + default: op + authme.admin.purge: + description: Administrator command to purge old user data. + default: op + authme.admin.purgelastpos: + description: Administrator command to purge the last position of a user. + default: op + authme.admin.purgebannedplayers: + description: Administrator command to purge all data associated with banned players. + default: op + authme.admin.switchantibot: + description: Administrator command to toggle the AntiBot protection status. + default: op + authme.admin.converter: + description: Administrator command to convert old or other data to AuthMe data. + default: op + authme.admin.reload: + description: Administrator command to reload the plugin configuration. + default: op + authme.player.*: + description: Permission to use all player (non-admin) commands. + children: + authme.player.allow2accounts: true + authme.player.bypassantibot: true + authme.player.bypassforcesurvival: true + authme.player.canbeforced: true + authme.player.captcha: true + authme.player.changepassword: true + authme.player.email.add: true + authme.player.email.change: true + authme.player.email.recover: true + authme.player.login: true + authme.player.logout: true + authme.player.register: true + authme.player.seeotheraccounts: true + authme.player.unregister: true + authme.player.vip: true + authme.player.bypassantibot: + description: Permission node to bypass AntiBot protection. + default: false + authme.player.vip: + description: Permission node to identify VIP users. + default: false + authme.player.login: + description: Command permission to login. default: true + authme.player.logout: + description: Command permission to logout. + default: true + authme.player.register: + description: Command permission to register. + default: true + authme.player.unregister: + description: Command permission to unregister. + default: true + authme.player.changepassword: + description: Command permission to change the password. + default: true + authme.player.email.add: + description: Command permission to add an email address. + default: false + authme.player.email.change: + description: Command permission to change the email address. + default: false + authme.player.email.recover: + description: Command permission to recover an account using it's email address. + default: false + authme.player.captcha: + description: Command permission to use captcha. + default: false + authme.player.canbeforced: + description: Permission for users a login can be forced to. + default: false + authme.player.bypassforcesurvival: + description: Permission for users to bypass force-survival mode. + default: false + authme.player.allow2accounts: + description: Permission for users to allow two accounts. + default: false + authme.player.seeotheraccounts: + description: Permission for user to see other accounts. + default: false diff --git a/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java b/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java index 9acc3c25e..ef78c5fda 100644 --- a/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java +++ b/src/test/java/fr/xephi/authme/security/crypts/AbstractEncryptionMethodTest.java @@ -142,30 +142,44 @@ public abstract class AbstractEncryptionMethodTest { return method.comparePassword(password, hashes.get(password), USERNAME); } - // @org.junit.Test public void a() { AbstractEncryptionMethodTest.generateTest(); } - // TODO #364: Remove this method + /** + * Generates a test class for a given encryption method. Simply create a test class and run the following code, + * replacing {@code XXX} with the actual class: + *

    + * @org.junit.Test public void generate() { AbstractEncryptionMethodTest.generateTest(new XXX()); } + *

    + * The output is the entire test class. + * + * @param method The method to create a test class for + */ static void generateTest(EncryptionMethod method) { String className = method.getClass().getSimpleName(); + // Create javadoc and "public class extends" and the constructor call "super(new Class()," System.out.println("/**\n * Test for {@link " + className + "}.\n */"); System.out.println("public class " + className + "Test extends AbstractEncryptionMethodTest {"); System.out.println("\n\tpublic " + className + "Test() {"); System.out.println("\t\tsuper(new " + className + "(),"); + // Iterate through the GIVEN_PASSWORDS and generate a hash so we can always check it later String delim = ", "; for (String password : GIVEN_PASSWORDS) { if (password.equals(GIVEN_PASSWORDS[GIVEN_PASSWORDS.length - 1])) { delim = "); "; } + // Encr. method uses separate salt, so we need to call the constructor that takes HashedPassword instances if (method.hasSeparateSalt()) { HashedPassword hashedPassword = method.computeHash(password, USERNAME); System.out.println(String.format("\t\tnew HashedPassword(\"%s\", \"%s\")%s// %s", hashedPassword.getHash(), hashedPassword.getSalt(), delim, password)); } else { + // Encryption method doesn't have separate salt, so simply pass the generated hash to the constructor System.out.println("\t\t\"" + method.computeHash(password, USERNAME).getHash() + "\"" + delim + "// " + password); } } + + // Close the constructor and class declarations System.out.println("\t}"); System.out.println("\n}"); } diff --git a/src/tools/docs/hash_algorithms.md b/src/tools/docs/hash_algorithms.md new file mode 100644 index 000000000..60a011b4c --- /dev/null +++ b/src/tools/docs/hash_algorithms.md @@ -0,0 +1,78 @@ + + + +## Hash Algorithms +AuthMe supports the following hash algorithms for storing your passwords safely. + + +Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate? +--------- | -------------- | ----------- | ----- | --- | --------- | ------ | --------- +BCRYPT | Recommended | 60 | | | Text | | +BCRYPT2Y | Recommended | 60 | | | Text | 22 | +CRAZYCRYPT1 | Do not use | 128 | | | Username | | +DOUBLEMD5 | Do not use | 32 | | | None | | +IPB3 | Acceptable | 32 | | | Text | 5 | Y +JOOMLA | Recommended | 65 | | | Text | 32 | +MD5 | Do not use | 32 | | | None | | +MD5VB | Acceptable | 56 | | | Text | 16 | +MYBB | Acceptable | 32 | | | Text | 8 | Y +PBKDF2 | Does not work | 330 | | | Text | 12 | +PBKDF2DJANGO | Acceptable | 77 | Y | | Text | 12 | +PHPBB | Acceptable | 34 | | | Text | 16 | +PHPFUSION | Do not use | 64 | Y | | | | Y +ROYALAUTH | Do not use | 128 | | | None | | +SALTED2MD5 | Acceptable | 32 | | | Text | | Y +SALTEDSHA512 | Recommended | 128 | | | | | Y +SHA1 | Do not use | 40 | | | None | | +SHA256 | Recommended | 86 | | | Text | 16 | +SHA512 | Do not use | 128 | | | None | | +SMF | Do not use | 40 | | | Username | | +WBB3 | Acceptable | 40 | | | Text | 40 | Y +WBB4 | Does not work | 60 | | | Text | 8 | +WHIRLPOOL | Do not use | 128 | | | None | | +WORDPRESS | Do not use | 34 | | | Text | 9 | +XAUTH | Recommended | 140 | | | Text | 12 | +CUSTOM | | | | | | | | + + + +### Columns +#### Algorithm +The algorithm is the hashing algorithm used to store passwords with. Default is SHA256 and is recommended. +You can change the hashing algorithm in the config.yml: under `security`, locate `passwordHash`. + +#### Recommendation +The recommendation lists our usage recommendation in terms of how secure it is (not how _well_ the algorithm works!). +- Recommended: The hash algorithm appears to be cryptographically secure and is one we recommend. +- Acceptable: There are safer algorithms that can be chosen but using the algorithm is generally OK. +- Do not use: Hash algorithm isn't sufficiently secure. Use only if required to hook into another system. +- Does not work: The algorithm does not work properly; do not use. + +#### Hash Length +The length of the hashes the algorithm produces. Note that the hash length is not (primarily) indicative of +whether an algorithm is secure or not. + +#### ASCII +If denoted with a **y**, means that the algorithm is restricted to ASCII characters only, i.e. it will simply ignore +"special characters" such as `ÿ` or `Â`. Note that we do not recommend the use of "special characters" in passwords. + +#### Salt Columns +Before hashing, a _salt_ may be appended to the password to make the hash more secure. The following columns describe +the salt the algorithm uses. + + +##### Salt Type +We do not recommend the usage +of any algorithm that doesn't use a randomly generated text as salt. This "salt type" column indicates what type of +salt the algorithm uses: +- Text: randomly generated text (see also the following column, "Length") +- Username: the salt is constructed from the username (bad) +- None: the algorithm uses no salt (bad) + +##### Length +If applicable (salt type is "Text"), indicates the length of the generated salt. The longer the better. +If this column is empty when the salt type is "Text", it typically means the salt length can be defined in config.yml. + +##### Separate +If denoted with a **y**, it means that the salt is stored in a separate column in the database. This is neither good +or bad. diff --git a/src/tools/hashmethods/EncryptionMethodInfoGatherer.java b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java new file mode 100644 index 000000000..07c588ea5 --- /dev/null +++ b/src/tools/hashmethods/EncryptionMethodInfoGatherer.java @@ -0,0 +1,135 @@ +package hashmethods; + +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.security.crypts.EncryptionMethod; +import fr.xephi.authme.security.crypts.HexSaltedMethod; +import fr.xephi.authme.security.crypts.description.AsciiRestricted; +import fr.xephi.authme.security.crypts.description.HasSalt; +import fr.xephi.authme.security.crypts.description.Recommendation; + +import java.lang.annotation.Annotation; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Set; + +import static com.google.common.collect.Sets.newHashSet; + +/** + * Gathers information on {@link fr.xephi.authme.security.crypts.EncryptionMethod} implementations based on + * the annotations in {@link fr.xephi.authme.security.crypts.description}. + */ +public class EncryptionMethodInfoGatherer { + + @SuppressWarnings("unchecked") + private final static Set> RELEVANT_ANNOTATIONS = + newHashSet(HasSalt.class, Recommendation.class, AsciiRestricted.class); + + private Map descriptions; + + public EncryptionMethodInfoGatherer() { + descriptions = new LinkedHashMap<>(); + constructDescriptions(); + } + + public Map getDescriptions() { + return descriptions; + } + + private void constructDescriptions() { + for (HashAlgorithm algorithm : HashAlgorithm.values()) { + Class methodClazz = algorithm.getClazz(); + if (!HashAlgorithm.CUSTOM.equals(algorithm) && !methodClazz.isAnnotationPresent(Deprecated.class)) { + MethodDescription description = createDescription(methodClazz); + descriptions.put(algorithm, description); + } + } + } + + private static MethodDescription createDescription(Class clazz) { + EncryptionMethod method = instantiateMethod(clazz); + MethodDescription description = new MethodDescription(clazz); + description.setHashLength(method.computeHash("test", "user").getHash().length()); + description.setHasSeparateSalt(method.hasSeparateSalt()); + + Map, Annotation> annotationMap = gatherAnnotations(clazz); + if (annotationMap.containsKey(HasSalt.class)) { + setSaltInformation(description, returnTyped(annotationMap, HasSalt.class), method); + } + if (annotationMap.containsKey(Recommendation.class)) { + description.setUsage(returnTyped(annotationMap, Recommendation.class).value()); + } + if (annotationMap.containsKey(AsciiRestricted.class)) { + description.setAsciiRestricted(true); + } + return description; + } + + private static Map, Annotation> gatherAnnotations(Class methodClass) { + // Note ljacqu 20151231: The map could be Map, Annotation> and it has the constraint + // that for a key Class, the value is of type T. We write a simple "Class" for brevity. + Map, Annotation> collection = new HashMap<>(); + Class currentMethodClass = methodClass; + while (currentMethodClass != null) { + getRelevantAnnotations(currentMethodClass, collection); + currentMethodClass = getSuperClass(currentMethodClass); + } + return collection; + } + + // Parameters could be Class; Map, Annotation> + // but the constraint doesn't have any technical relevance, so just clutters the code + private static void getRelevantAnnotations(Class methodClass, Map, Annotation> collection) { + for (Annotation annotation : methodClass.getAnnotations()) { + if (RELEVANT_ANNOTATIONS.contains(annotation.annotationType()) + && !collection.containsKey(annotation.annotationType())) { + collection.put(annotation.annotationType(), annotation); + } + } + } + + /** + * Returns the super class of the given encryption method if it is also of EncryptionMethod type. + * (Anything beyond EncryptionMethod is not of interest.) + */ + private static Class getSuperClass(Class methodClass) { + Class zuper = methodClass.getSuperclass(); + if (EncryptionMethod.class.isAssignableFrom(zuper)) { + return zuper; + } + return null; + } + + /** + * Set the salt information for the given encryption method and the found {@link HasSalt} annotation. + * Also gets the salt length from {@link HexSaltedMethod#getSaltLength()} for such instances. + * + * @param description The description to update + * @param hasSalt The associated HasSalt annotation + * @param method The encryption method + */ + private static void setSaltInformation(MethodDescription description, HasSalt hasSalt, EncryptionMethod method) { + description.setSaltType(hasSalt.value()); + if (hasSalt.length() != 0) { + description.setSaltLength(hasSalt.length()); + } else if (method instanceof HexSaltedMethod) { + int saltLength = ((HexSaltedMethod) method).getSaltLength(); + description.setSaltLength(saltLength); + } + } + + private static EncryptionMethod instantiateMethod(Class clazz) { + try { + return clazz.newInstance(); + } catch (InstantiationException | IllegalAccessException e) { + throw new RuntimeException("Could not instantiate " + clazz, e); + } + } + + // Convenience method for retrieving an annotation in a typed fashion. + // We know implicitly that the key of the map always corresponds to the type of the value + private static T returnTyped(Map, Annotation> map, Class key) { + return key.cast(map.get(key)); + } + +} diff --git a/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java new file mode 100644 index 000000000..5213d6b7d --- /dev/null +++ b/src/tools/hashmethods/HashAlgorithmsDescriptionTask.java @@ -0,0 +1,100 @@ +package hashmethods; + +import fr.xephi.authme.security.HashAlgorithm; +import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.WrapperMock; +import utils.ANewMap; +import utils.FileUtils; +import utils.TagReplacer; +import utils.ToolTask; +import utils.ToolsConstants; + +import java.util.Map; +import java.util.Scanner; + +/** + * Task for generating the markdown page describing the AuthMe hash algorithms. + * + * @see {@link fr.xephi.authme.security.HashAlgorithm} + */ +public class HashAlgorithmsDescriptionTask implements ToolTask { + + private static final String CUR_FOLDER = ToolsConstants.TOOLS_SOURCE_ROOT + "hashmethods/"; + private static final String OUTPUT_FILE = ToolsConstants.DOCS_FOLDER + "hash_algorithms.md"; + + @Override + public void execute(Scanner scanner) { + // Unfortunately, we need the Wrapper to be around to work with Settings, and certain encryption methods + // directly read from the Settings file + WrapperMock.createInstance(); + Settings.bCryptLog2Rounds = 8; + Settings.saltLength = 8; + + // Gather info and construct a row for each method + EncryptionMethodInfoGatherer infoGatherer = new EncryptionMethodInfoGatherer(); + Map descriptions = infoGatherer.getDescriptions(); + final String methodRows = constructMethodRows(descriptions); + + // Write to the docs file + Map tags = ANewMap.with("method_rows", methodRows).build(); + FileUtils.generateFileFromTemplate(CUR_FOLDER + "hash_algorithms.tpl.md", OUTPUT_FILE, tags); + } + + private static String constructMethodRows(Map descriptions) { + final String rowTemplate = FileUtils.readFromFile(CUR_FOLDER + "hash_algorithms_row.tpl.md"); + StringBuilder result = new StringBuilder(); + for (Map.Entry entry : descriptions.entrySet()) { + MethodDescription description = entry.getValue(); + Map tags = ANewMap + .with("name", asString(entry.getKey())) + .and("recommendation", asString(description.getUsage())) + .and("hash_length", asString(description.getHashLength())) + .and("ascii_restricted", asString(description.isAsciiRestricted())) + .and("salt_type", asString(description.getSaltType())) + .and("salt_length", asString(description.getSaltLength())) + .and("separate_salt", asString(description.hasSeparateSalt())) + .build(); + result.append(TagReplacer.applyReplacements(rowTemplate, tags)); + } + return result.toString(); + } + + @Override + public String getTaskName() { + return "describeHashAlgos"; + } + + // ---- + // String representations + // ---- + private static String asString(boolean value) { + return value ? "Y" : ""; + } + + private static String asString(int value) { + return String.valueOf(value); + } + + private static String asString(Integer value) { + if (value == null) { + return ""; + } + return String.valueOf(value); + } + + private static String asString(HashAlgorithm value) { + return value.toString(); + } + + private static > String asString(E value) { + if (value == null) { + return ""; + } + // Get the enum name and replace something like "DO_NOT_USE" to "Do not use" + String enumName = value.toString().replace("_", " "); + return enumName.length() > 2 + ? enumName.substring(0, 1) + enumName.substring(1).toLowerCase() + : enumName; + } + +} diff --git a/src/tools/hashmethods/MethodDescription.java b/src/tools/hashmethods/MethodDescription.java new file mode 100644 index 000000000..45aaf448e --- /dev/null +++ b/src/tools/hashmethods/MethodDescription.java @@ -0,0 +1,85 @@ +package hashmethods; + +import fr.xephi.authme.security.crypts.EncryptionMethod; +import fr.xephi.authme.security.crypts.description.SaltType; +import fr.xephi.authme.security.crypts.description.Usage; + +/** + * Description of a {@link EncryptionMethod}. + */ +public class MethodDescription { + + /** The implementation class the description belongs to. */ + private final Class method; + /** The type of the salt that is used. */ + private SaltType saltType; + /** The length of the salt for SaltType.TEXT salts. */ + private Integer saltLength; + /** The usage recommendation. */ + private Usage usage; + /** Whether or not the encryption method is restricted to ASCII characters for proper functioning. */ + private boolean asciiRestricted; + /** Whether or not the encryption method requires its salt stored separately. */ + private boolean hasSeparateSalt; + /** The length of the hash output, based on a test hash (i.e. assumes same length for all hashes.) */ + private int hashLength; + + public MethodDescription(Class method) { + this.method = method; + } + + + // Trivial getters and setters + public Class getMethod() { + return method; + } + + public SaltType getSaltType() { + return saltType; + } + + public void setSaltType(SaltType saltType) { + this.saltType = saltType; + } + + public Integer getSaltLength() { + return saltLength; + } + + public void setSaltLength(int saltLength) { + this.saltLength = saltLength; + } + + public Usage getUsage() { + return usage; + } + + public void setUsage(Usage usage) { + this.usage = usage; + } + + public boolean isAsciiRestricted() { + return asciiRestricted; + } + + public void setAsciiRestricted(boolean asciiRestricted) { + this.asciiRestricted = asciiRestricted; + } + + public boolean hasSeparateSalt() { + return hasSeparateSalt; + } + + public void setHasSeparateSalt(boolean hasSeparateSalt) { + this.hasSeparateSalt = hasSeparateSalt; + } + + public int getHashLength() { + return hashLength; + } + + public void setHashLength(int hashLength) { + this.hashLength = hashLength; + } + +} diff --git a/src/tools/hashmethods/hash_algorithms.tpl.md b/src/tools/hashmethods/hash_algorithms.tpl.md new file mode 100644 index 000000000..b466eeebd --- /dev/null +++ b/src/tools/hashmethods/hash_algorithms.tpl.md @@ -0,0 +1,53 @@ + + + +## Hash Algorithms +AuthMe supports the following hash algorithms for storing your passwords safely. + + +Algorithm | Recommendation | Hash length | ASCII | | Salt type | Length | Separate? +--------- | -------------- | ----------- | ----- | --- | --------- | ------ | --------- +{method_rows}CUSTOM | | | | | | | | + + + +### Columns +#### Algorithm +The algorithm is the hashing algorithm used to store passwords with. Default is SHA256 and is recommended. +You can change the hashing algorithm in the config.yml: under `security`, locate `passwordHash`. + +#### Recommendation +The recommendation lists our usage recommendation in terms of how secure it is (not how _well_ the algorithm works!). +- Recommended: The hash algorithm appears to be cryptographically secure and is one we recommend. +- Acceptable: There are safer algorithms that can be chosen but using the algorithm is generally OK. +- Do not use: Hash algorithm isn't sufficiently secure. Use only if required to hook into another system. +- Does not work: The algorithm does not work properly; do not use. + +#### Hash Length +The length of the hashes the algorithm produces. Note that the hash length is not (primarily) indicative of +whether an algorithm is secure or not. + +#### ASCII +If denoted with a **y**, means that the algorithm is restricted to ASCII characters only, i.e. it will simply ignore +"special characters" such as `ÿ` or `Â`. Note that we do not recommend the use of "special characters" in passwords. + +#### Salt Columns +Before hashing, a _salt_ may be appended to the password to make the hash more secure. The following columns describe +the salt the algorithm uses. + + +##### Salt Type +We do not recommend the usage +of any algorithm that doesn't use a randomly generated text as salt. This "salt type" column indicates what type of +salt the algorithm uses: +- Text: randomly generated text (see also the following column, "Length") +- Username: the salt is constructed from the username (bad) +- None: the algorithm uses no salt (bad) + +##### Length +If applicable (salt type is "Text"), indicates the length of the generated salt. The longer the better. +If this column is empty when the salt type is "Text", it typically means the salt length can be defined in config.yml. + +##### Separate +If denoted with a **y**, it means that the salt is stored in a separate column in the database. This is neither good +or bad. diff --git a/src/tools/hashmethods/hash_algorithms_row.tpl.md b/src/tools/hashmethods/hash_algorithms_row.tpl.md new file mode 100644 index 000000000..411d11271 --- /dev/null +++ b/src/tools/hashmethods/hash_algorithms_row.tpl.md @@ -0,0 +1 @@ +{name} | {recommendation} | {hash_length} | {ascii_restricted} | | {salt_type} | {salt_length} | {separate_salt}