diff --git a/README.md b/README.md
index ff0b7f4dd..5f82e5241 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ McStats: http://mcstats.org/plugin/AuthMe
#####Running Requirements:
>- Java 1.7 (should work also with Java 1.8)
->- Spigot or CraftBukkit (1.7.10 or 1.8.X)
+>- Spigot or CraftBukkit (1.7.10, 1.8.X or 1.9-pre1)
>- ProtocolLib (optional, required by the protectInventory feature)
diff --git a/pom.xml b/pom.xml
index e5d70cd19..82dfd0b40 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,7 +61,7 @@
1.7
- 1.8.8-R0.1-SNAPSHOT
+ 1.9-pre1-SNAPSHOT
@@ -305,10 +305,10 @@
https://hub.spigotmc.org/nexus/content/repositories/snapshots
-
+
ess-repo
- http://ci.drtshock.net/plugin/repository/everything
+ http://repo.ess3.net/content/groups/essentials
@@ -376,6 +376,19 @@
compile
true
+
+
+ org.xerial
+ sqlite-jdbc
+ 3.8.11.2
+ test
+
+
+ com.h2database
+ h2
+ 1.4.191
+ test
+
@@ -651,16 +664,20 @@
true
-
+
net.ess3
- EssentialsX
- 2.0.1-SNAPSHOT
+ Essentials
+ 2.13-SNAPSHOT
provided
- org.spigotmc
- spigot-api
+ org.bukkit
+ bukkit
+
+
+ org.bukkit
+ craftbukkit
true
diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java
index 56580cf91..622ceafe4 100644
--- a/src/main/java/fr/xephi/authme/AuthMe.java
+++ b/src/main/java/fr/xephi/authme/AuthMe.java
@@ -64,7 +64,6 @@ import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
-import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@@ -76,6 +75,7 @@ import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.sql.SQLException;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
@@ -104,15 +104,14 @@ public class AuthMe extends JavaPlugin {
// Private Instances
private static AuthMe plugin;
private static Server server;
- private Management management;
- private CommandHandler commandHandler = null;
- private PermissionsManager permsMan = null;
- private NewSetting newSettings;
- private Messages messages;
- private JsonCache playerBackup;
- private PasswordSecurity passwordSecurity;
- private DataSource database;
-
+ /*
+ * Maps and stuff
+ * TODO: Clean up and Move into a manager
+ */
+ public final ConcurrentHashMap sessions = new ConcurrentHashMap<>();
+ public final ConcurrentHashMap captcha = new ConcurrentHashMap<>();
+ public final ConcurrentHashMap cap = new ConcurrentHashMap<>();
+ public final ConcurrentHashMap realIp = new ConcurrentHashMap<>();
/*
* Public Instances
* TODO #432: Encapsulation
@@ -122,7 +121,6 @@ public class AuthMe extends JavaPlugin {
public DataManager dataManager;
public OtherAccounts otherAccounts;
public Location essentialsSpawn;
-
/*
* Plugin Hooks
* TODO: Move into modules
@@ -133,15 +131,14 @@ public class AuthMe extends JavaPlugin {
public AuthMeInventoryPacketAdapter inventoryProtector;
public AuthMeTabCompletePacketAdapter tabComplete;
public AuthMeTablistPacketAdapter tablistHider;
-
- /*
- * Maps and stuff
- * TODO: Clean up and Move into a manager
- */
- public final ConcurrentHashMap sessions = new ConcurrentHashMap<>();
- public final ConcurrentHashMap captcha = new ConcurrentHashMap<>();
- public final ConcurrentHashMap cap = new ConcurrentHashMap<>();
- public final ConcurrentHashMap realIp = new ConcurrentHashMap<>();
+ private Management management;
+ private CommandHandler commandHandler = null;
+ private PermissionsManager permsMan = null;
+ private NewSetting newSettings;
+ private Messages messages;
+ private JsonCache playerBackup;
+ private PasswordSecurity passwordSecurity;
+ private DataSource database;
/**
* Get the plugin's instance.
@@ -494,11 +491,41 @@ public class AuthMe extends JavaPlugin {
if (newSettings != null) {
new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP);
}
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ List pendingTasks = new ArrayList<>();
+ for (BukkitTask pendingTask : getServer().getScheduler().getPendingTasks()) {
+ if (pendingTask.getOwner().equals(plugin) && !pendingTask.isSync()) {
+ pendingTasks.add(pendingTask.getTaskId());
+ }
+ }
+ ConsoleLogger.info("Waiting for " + pendingTasks.size() + " tasks to finish");
+ int progress = 0;
+ for (int taskId : pendingTasks) {
+ int maxTries = 5;
+ while (getServer().getScheduler().isCurrentlyRunning(taskId)) {
+ if (maxTries <= 0) {
+ ConsoleLogger.info("Async task " + taskId + " times out after to many tries");
+ break;
+ }
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ignored) {
+ }
+ maxTries--;
+ }
+
+ progress++;
+ ConsoleLogger.info("Progress: " + progress + " / " + pendingTasks.size());
+ }
+ if (database != null) {
+ database.close();
+ }
+ }
+ }, "AuthMe-DataSource#close").start();
// Close the database
- if (database != null) {
- database.close();
- }
// Disabled correctly
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " disabled!");
@@ -518,6 +545,7 @@ public class AuthMe extends JavaPlugin {
* Sets up the data source.
*
* @param settings The settings instance
+ *
* @see AuthMe#database
*/
public void setupDatabase(NewSetting settings) throws ClassNotFoundException, SQLException {
@@ -653,6 +681,7 @@ public class AuthMe extends JavaPlugin {
ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
Settings.protectInventoryBeforeLogInEnabled = false;
newSettings.setProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN, false);
+ newSettings.save();
}
return;
}
@@ -664,13 +693,19 @@ public class AuthMe extends JavaPlugin {
inventoryProtector.unregister();
inventoryProtector = null;
}
- if (tabComplete == null && newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN)) {
+ if (newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN) && tabComplete == null) {
tabComplete = new AuthMeTabCompletePacketAdapter(this);
tabComplete.register();
+ } else if (tabComplete != null) {
+ tabComplete.unregister();
+ tabComplete = null;
}
- if (tablistHider == null && newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN)) {
+ if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) {
tablistHider = new AuthMeTablistPacketAdapter(this);
tablistHider.register();
+ } else if (tablistHider != null) {
+ tablistHider.unregister();
+ tablistHider = null;
}
}
@@ -737,61 +772,9 @@ public class AuthMe extends JavaPlugin {
}
// Return the spawn location of a player
+ @Deprecated
public Location getSpawnLocation(Player player) {
- World world = player.getWorld();
- String[] spawnPriority = Settings.spawnPriority.split(",");
- Location spawnLoc = world.getSpawnLocation();
- for (int i = spawnPriority.length - 1; i >= 0; i--) {
- String s = spawnPriority[i];
- if (s.equalsIgnoreCase("default") && getDefaultSpawn(world) != null)
- spawnLoc = getDefaultSpawn(world);
- if (s.equalsIgnoreCase("multiverse") && getMultiverseSpawn(world) != null)
- spawnLoc = getMultiverseSpawn(world);
- if (s.equalsIgnoreCase("essentials") && getEssentialsSpawn() != null)
- spawnLoc = getEssentialsSpawn();
- if (s.equalsIgnoreCase("authme") && getAuthMeSpawn(player) != null)
- spawnLoc = getAuthMeSpawn(player);
- }
- if (spawnLoc == null) {
- spawnLoc = world.getSpawnLocation();
- }
- return spawnLoc;
- }
-
- // Return the default spawn point of a world
- private Location getDefaultSpawn(World world) {
- return world.getSpawnLocation();
- }
-
- // Return the multiverse spawn point of a world
- private Location getMultiverseSpawn(World world) {
- if (multiverse != null && Settings.multiverse) {
- try {
- return multiverse.getMVWorldManager().getMVWorld(world).getSpawnLocation();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- return null;
- }
-
- // Return the essentials spawn point
- private Location getEssentialsSpawn() {
- if (essentialsSpawn != null) {
- return essentialsSpawn;
- }
- return null;
- }
-
- // Return the AuthMe spawn point
- private Location getAuthMeSpawn(Player player) {
- if ((!database.isAuthAvailable(player.getName().toLowerCase()) || !player.hasPlayedBefore())
- && (Spawn.getInstance().getFirstSpawn() != null)) {
- return Spawn.getInstance().getFirstSpawn();
- } else if (Spawn.getInstance().getSpawn() != null) {
- return Spawn.getInstance().getSpawn();
- }
- return player.getWorld().getSpawnLocation();
+ return Spawn.getInstance().getSpawnLocation(player);
}
private void scheduleRecallEmailTask() {
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 41672c0c9..c2bb4f704 100644
--- a/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java
+++ b/src/main/java/fr/xephi/authme/cache/auth/PlayerAuth.java
@@ -1,12 +1,11 @@
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;
-
/**
*/
@@ -85,20 +84,6 @@ public class PlayerAuth {
this(nickname, new HashedPassword(hash), -1, ip, lastLogin, 0, 0, 0, "world", email, realName);
}
- /**
- * Constructor for PlayerAuth.
- *
- * @param nickname String
- * @param hash String
- * @param salt String
- * @param ip String
- * @param lastLogin long
- * @param realName String
- */
- public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, String realName) {
- this(nickname, new HashedPassword(hash, salt), -1, ip, lastLogin, 0, 0, 0, "world", "your@email.com", realName);
- }
-
/**
* Constructor for PlayerAuth.
*
@@ -118,44 +103,6 @@ public class PlayerAuth {
this(nickname, new HashedPassword(hash), -1, ip, lastLogin, x, y, z, world, email, realName);
}
- /**
- * Constructor for PlayerAuth.
- *
- * @param nickname String
- * @param hash String
- * @param salt String
- * @param ip String
- * @param lastLogin long
- * @param x double
- * @param y double
- * @param z double
- * @param world String
- * @param email String
- * @param realName String
- */
- public PlayerAuth(String nickname, String hash, String salt, String ip, long lastLogin, double x, double y,
- double z, String world, String email, String realName) {
- this(nickname, new HashedPassword(hash, salt), -1, ip, lastLogin,
- x, y, z, world, email, realName);
- }
-
- /**
- * Constructor for PlayerAuth.
- *
- * @param nickname String
- * @param hash String
- * @param salt String
- * @param groupId int
- * @param ip String
- * @param lastLogin long
- * @param realName String
- */
- public PlayerAuth(String nickname, String hash, String salt, int groupId, String ip,
- long lastLogin, String realName) {
- this(nickname, new HashedPassword(hash, salt), groupId, ip, lastLogin,
- 0, 0, 0, "world", "your@email.com", realName);
- }
-
/**
* Constructor for PlayerAuth.
*
@@ -171,8 +118,8 @@ public class PlayerAuth {
* @param email String
* @param realName String
*/
- public PlayerAuth(String nickname, HashedPassword password, int groupId, String ip, long lastLogin,
- double x, double y, double z, String world, String email, String realName) {
+ private PlayerAuth(String nickname, HashedPassword password, int groupId, String ip, long lastLogin,
+ double x, double y, double z, String world, String email, String realName) {
this.nickname = nickname.toLowerCase();
this.password = password;
this.ip = ip;
diff --git a/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java b/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java
deleted file mode 100644
index bf5e7389b..000000000
--- a/src/main/java/fr/xephi/authme/cache/backup/DataFileCache.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package fr.xephi.authme.cache.backup;
-
-/**
- */
-public class DataFileCache {
-
- private final String group;
- private final boolean operator;
-
- /**
- * Constructor for DataFileCache.
- *
- * @param group String
- * @param operator boolean
- */
- public DataFileCache(String group, boolean operator) {
- this.group = group;
- this.operator = operator;
- }
-
- /**
- * Method getGroup.
- *
- * @return String
- */
- public String getGroup() {
- return group;
- }
-
- /**
- * Method getOperator.
- *
- * @return boolean
- */
- public boolean getOperator() {
- return operator;
- }
-}
diff --git a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java
index 8e43241f3..177ccce56 100644
--- a/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java
+++ b/src/main/java/fr/xephi/authme/cache/backup/JsonCache.java
@@ -2,7 +2,14 @@ package fr.xephi.authme.cache.backup;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
-import com.google.gson.*;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.JsonDeserializationContext;
+import com.google.gson.JsonDeserializer;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player;
@@ -11,8 +18,6 @@ import java.io.File;
import java.io.IOException;
import java.lang.reflect.Type;
-/**
- */
public class JsonCache {
private final Gson gson;
@@ -24,31 +29,19 @@ public class JsonCache {
ConsoleLogger.showError("Failed to create cache directory.");
}
gson = new GsonBuilder()
- .registerTypeAdapter(DataFileCache.class, new PlayerDataSerializer())
- .registerTypeAdapter(DataFileCache.class, new PlayerDataDeserializer())
+ .registerTypeAdapter(PlayerData.class, new PlayerDataSerializer())
+ .registerTypeAdapter(PlayerData.class, new PlayerDataDeserializer())
.setPrettyPrinting()
.create();
}
- /**
- * Method createCache.
- *
- * @param player Player
- * @param playerData DataFileCache
- */
- public void createCache(Player player, DataFileCache playerData) {
+ public void createCache(Player player, PlayerData playerData) {
if (player == null) {
return;
}
- String path;
- try {
- path = player.getUniqueId().toString();
- } catch (Exception | Error e) {
- path = player.getName().toLowerCase();
- }
-
- File file = new File(cacheDir, path + File.separator + "cache.json");
+ String name = player.getName().toLowerCase();
+ File file = new File(cacheDir, name + File.separator + "cache.json");
if (file.exists()) {
return;
}
@@ -61,52 +54,29 @@ public class JsonCache {
Files.touch(file);
Files.write(data, file, Charsets.UTF_8);
} catch (IOException e) {
- e.printStackTrace();
+ ConsoleLogger.writeStackTrace(e);
}
}
- /**
- * Method readCache.
- *
- * @param player Player
- *
- * @return DataFileCache
- */
- public DataFileCache readCache(Player player) {
- String path;
- try {
- path = player.getUniqueId().toString();
- } catch (Exception | Error e) {
- path = player.getName().toLowerCase();
- }
-
- File file = new File(cacheDir, path + File.separator + "cache.json");
+ public PlayerData readCache(Player player) {
+ String name = player.getName().toLowerCase();
+ File file = new File(cacheDir, name + File.separator + "cache.json");
if (!file.exists()) {
return null;
}
try {
String str = Files.toString(file, Charsets.UTF_8);
- return gson.fromJson(str, DataFileCache.class);
- } catch (Exception e) {
- e.printStackTrace();
+ return gson.fromJson(str, PlayerData.class);
+ } catch (IOException e) {
+ ConsoleLogger.writeStackTrace(e);
return null;
}
}
- /**
- * Method removeCache.
- *
- * @param player Player
- */
public void removeCache(Player player) {
- String path;
- try {
- path = player.getUniqueId().toString();
- } catch (Exception | Error e) {
- path = player.getName().toLowerCase();
- }
- File file = new File(cacheDir, path);
+ String name = player.getName().toLowerCase();
+ File file = new File(cacheDir, name);
if (file.exists()) {
purgeDirectory(file);
if (!file.delete()) {
@@ -115,75 +85,47 @@ public class JsonCache {
}
}
- /**
- * Method doesCacheExist.
- *
- * @param player Player
- *
- * @return boolean
- */
public boolean doesCacheExist(Player player) {
- String path;
- try {
- path = player.getUniqueId().toString();
- } catch (Exception | Error e) {
- path = player.getName().toLowerCase();
- }
- File file = new File(cacheDir, path + File.separator + "cache.json");
+ String name = player.getName().toLowerCase();
+ File file = new File(cacheDir, name + File.separator + "cache.json");
return file.exists();
}
- /**
- */
- private static class PlayerDataDeserializer implements JsonDeserializer {
- /**
- * Method deserialize.
- *
- * @param jsonElement JsonElement
- * @param type Type
- * @param jsonDeserializationContext JsonDeserializationContext
- *
- * @return DataFileCache * @throws JsonParseException * @see com.google.gson.JsonDeserializer#deserialize(JsonElement, Type, JsonDeserializationContext)
- */
+ private class PlayerDataDeserializer implements JsonDeserializer {
@Override
- public DataFileCache deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
+ public PlayerData deserialize(JsonElement jsonElement, Type type,
+ JsonDeserializationContext context) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
if (jsonObject == null) {
return null;
}
- JsonElement e;
String group = null;
boolean operator = false;
+ boolean fly = false;
+ JsonElement e;
if ((e = jsonObject.get("group")) != null) {
group = e.getAsString();
}
if ((e = jsonObject.get("operator")) != null) {
operator = e.getAsBoolean();
}
+ if ((e = jsonObject.get("fly")) != null) {
+ fly = e.getAsBoolean();
+ }
- return new DataFileCache(group, operator);
+ return new PlayerData(group, operator, fly);
}
}
- /**
- */
- private class PlayerDataSerializer implements JsonSerializer {
- /**
- * Method serialize.
- *
- * @param dataFileCache DataFileCache
- * @param type Type
- * @param jsonSerializationContext JsonSerializationContext
- *
- * @return JsonElement
- */
+ private class PlayerDataSerializer implements JsonSerializer {
@Override
- public JsonElement serialize(DataFileCache dataFileCache, Type type, JsonSerializationContext jsonSerializationContext) {
+ public JsonElement serialize(PlayerData playerData, Type type,
+ JsonSerializationContext context) {
JsonObject jsonObject = new JsonObject();
- jsonObject.addProperty("group", dataFileCache.getGroup());
- jsonObject.addProperty("operator", dataFileCache.getOperator());
-
+ jsonObject.addProperty("group", playerData.getGroup());
+ jsonObject.addProperty("operator", playerData.getOperator());
+ jsonObject.addProperty("fly", playerData.isFlyEnabled());
return jsonObject;
}
}
diff --git a/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java b/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java
new file mode 100644
index 000000000..a41b8aa95
--- /dev/null
+++ b/src/main/java/fr/xephi/authme/cache/backup/PlayerData.java
@@ -0,0 +1,26 @@
+package fr.xephi.authme.cache.backup;
+
+public class PlayerData {
+
+ private final String group;
+ private final boolean operator;
+ private final boolean flyEnabled;
+
+ public PlayerData(String group, boolean operator, boolean flyEnabled) {
+ this.group = group;
+ this.operator = operator;
+ this.flyEnabled = flyEnabled;
+ }
+
+ public String getGroup() {
+ return group;
+ }
+
+ public boolean getOperator() {
+ return operator;
+ }
+
+ public boolean isFlyEnabled() {
+ return flyEnabled;
+ }
+}
diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java
index 083c962de..2679df641 100644
--- a/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java
+++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboCache.java
@@ -1,9 +1,8 @@
package fr.xephi.authme.cache.limbo;
import fr.xephi.authme.AuthMe;
-import fr.xephi.authme.ConsoleLogger;
-import fr.xephi.authme.cache.backup.DataFileCache;
import fr.xephi.authme.cache.backup.JsonCache;
+import fr.xephi.authme.cache.backup.PlayerData;
import fr.xephi.authme.permission.PermissionsManager;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -19,7 +18,7 @@ public class LimboCache {
private volatile static LimboCache singleton;
public final ConcurrentHashMap cache;
public final AuthMe plugin;
- private final JsonCache playerData;
+ private final JsonCache jsonCache;
/**
* Constructor for LimboCache.
@@ -29,7 +28,7 @@ public class LimboCache {
private LimboCache(AuthMe plugin) {
this.plugin = plugin;
this.cache = new ConcurrentHashMap<>();
- this.playerData = new JsonCache();
+ this.jsonCache = new JsonCache();
}
/**
@@ -52,44 +51,28 @@ public class LimboCache {
public void addLimboPlayer(Player player) {
String name = player.getName().toLowerCase();
Location loc = player.getLocation();
- boolean operator = false;
+ boolean operator = player.isOp();
+ boolean flyEnabled = player.getAllowFlight();
String playerGroup = "";
+ PermissionsManager permsMan = plugin.getPermissionsManager();
+ if (permsMan.hasGroupSupport()) {
+ playerGroup = permsMan.getPrimaryGroup(player);
+ }
- // Get the permissions manager, and make sure it's valid
- PermissionsManager permsMan = this.plugin.getPermissionsManager();
- if (permsMan == null)
- ConsoleLogger.showError("Unable to access permissions manager!");
- assert permsMan != null;
-
- if (playerData.doesCacheExist(player)) {
- DataFileCache cache = playerData.readCache(player);
+ if (jsonCache.doesCacheExist(player)) {
+ PlayerData cache = jsonCache.readCache(player);
if (cache != null) {
playerGroup = cache.getGroup();
operator = cache.getOperator();
+ flyEnabled = cache.isFlyEnabled();
}
- } else {
- operator = player.isOp();
-
- // Check whether groups are supported
- if (permsMan.hasGroupSupport())
- playerGroup = permsMan.getPrimaryGroup(player);
}
if (player.isDead()) {
loc = plugin.getSpawnLocation(player);
}
- cache.put(name, new LimboPlayer(name, loc, operator, playerGroup));
- }
-
- /**
- * Method addLimboPlayer.
- *
- * @param player Player
- * @param group String
- */
- public void addLimboPlayer(Player player, String group) {
- cache.put(player.getName().toLowerCase(), new LimboPlayer(player.getName().toLowerCase(), group));
+ cache.put(name, new LimboPlayer(name, loc, operator, playerGroup, flyEnabled));
}
/**
@@ -99,7 +82,11 @@ public class LimboCache {
*/
public void deleteLimboPlayer(String name) {
checkNotNull(name);
- cache.remove(name.toLowerCase());
+ name = name.toLowerCase();
+ if (cache.containsKey(name)) {
+ cache.get(name).clearTask();
+ cache.remove(name);
+ }
}
/**
diff --git a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java
index f61c62469..917a22bc1 100644
--- a/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java
+++ b/src/main/java/fr/xephi/authme/cache/limbo/LimboPlayer.java
@@ -8,37 +8,20 @@ import org.bukkit.scheduler.BukkitTask;
public class LimboPlayer {
private final String name;
+ private final boolean fly;
private Location loc = null;
private BukkitTask timeoutTaskId = null;
private BukkitTask messageTaskId = null;
private boolean operator = false;
- private String group = "";
+ private String group;
- /**
- * Constructor for LimboPlayer.
- *
- * @param name String
- * @param loc Location
- * @param operator boolean
- * @param group String
- */
- public LimboPlayer(String name, Location loc,
- boolean operator, String group) {
+ public LimboPlayer(String name, Location loc, boolean operator,
+ String group, boolean fly) {
this.name = name;
this.loc = loc;
this.operator = operator;
this.group = group;
- }
-
- /**
- * Constructor for LimboPlayer.
- *
- * @param name String
- * @param group String
- */
- public LimboPlayer(String name, String group) {
- this.name = name;
- this.group = group;
+ this.fly = fly;
}
/**
@@ -77,11 +60,10 @@ public class LimboPlayer {
return group;
}
- /**
- * Method getTimeoutTaskId.
- *
- * @return BukkitTask
- */
+ public boolean isFly() {
+ return fly;
+ }
+
public BukkitTask getTimeoutTaskId() {
return timeoutTaskId;
}
@@ -121,7 +103,6 @@ public class LimboPlayer {
/**
* Method clearTask.
- *
*/
public void clearTask() {
if (messageTaskId != null) {
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
index 3dce54e17..0c7adf2ff 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/ReloadCommand.java
@@ -5,6 +5,7 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
+import fr.xephi.authme.settings.Spawn;
import org.bukkit.command.CommandSender;
import java.util.List;
@@ -20,6 +21,7 @@ public class ReloadCommand implements ExecutableCommand {
try {
commandService.getSettings().reload();
commandService.reloadMessages(commandService.getSettings().getMessagesFile());
+ Spawn.reload();
// TODO #432: We should not reload only certain plugin entities but actually reinitialize all elements,
// i.e. here in the future we might not have setupDatabase() but Authme.onEnable(), maybe after
// a call to some destructor method
diff --git a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
index dc5cd4713..9ed65b0bc 100644
--- a/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
+++ b/src/main/java/fr/xephi/authme/command/executable/authme/UnregisterAdminCommand.java
@@ -1,14 +1,5 @@
package fr.xephi.authme.command.executable.authme;
-import java.util.List;
-
-import org.bukkit.command.CommandSender;
-import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffect;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitScheduler;
-import org.bukkit.scheduler.BukkitTask;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
@@ -20,6 +11,14 @@ import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.task.MessageTask;
import fr.xephi.authme.task.TimeoutTask;
import fr.xephi.authme.util.Utils;
+import org.bukkit.command.CommandSender;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scheduler.BukkitTask;
+
+import java.util.List;
/**
* Admin command to unregister a player.
@@ -55,19 +54,20 @@ public class UnregisterAdminCommand implements ExecutableCommand {
if (target != null && target.isOnline()) {
Utils.teleportToSpawn(target);
LimboCache.getInstance().addLimboPlayer(target);
- int delay = Settings.getRegistrationTimeout * 20;
+ int timeOut = Settings.getRegistrationTimeout * 20;
int interval = Settings.getWarnMessageInterval;
BukkitScheduler scheduler = sender.getServer().getScheduler();
- if (delay != 0) {
- BukkitTask id = scheduler.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, playerNameLowerCase, target), delay);
+ if (timeOut != 0) {
+ BukkitTask id = scheduler.runTaskLater(plugin, new TimeoutTask(plugin, playerNameLowerCase, target), timeOut);
LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setTimeoutTaskId(id);
}
LimboCache.getInstance().getLimboPlayer(playerNameLowerCase).setMessageTaskId(
- scheduler.runTaskAsynchronously(plugin,
- new MessageTask(plugin, playerNameLowerCase, commandService.retrieveMessage(MessageKey.REGISTER_MESSAGE), interval)));
+ scheduler.runTask(
+ plugin, new MessageTask(plugin, playerNameLowerCase, MessageKey.REGISTER_MESSAGE, interval)
+ )
+ );
if (Settings.applyBlindEffect) {
- target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS,
- Settings.getRegistrationTimeout * 20, 2));
+ target.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2));
}
commandService.send(target, MessageKey.UNREGISTERED_SUCCESS);
}
diff --git a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
index 4d0d44365..ad02c99f2 100644
--- a/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/CacheDataSource.java
@@ -4,14 +4,19 @@ import com.google.common.base.Optional;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
-import com.google.common.cache.RemovalListener;
-import com.google.common.cache.RemovalNotification;
+import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.ListeningExecutorService;
+import com.google.common.util.concurrent.MoreExecutors;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+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;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.Callable;
+import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
@@ -20,6 +25,7 @@ public class CacheDataSource implements DataSource {
private final DataSource source;
private final LoadingCache> cachedAuths;
+ private final ListeningExecutorService executorService;
/**
* Constructor for CacheDataSource.
@@ -27,25 +33,35 @@ public class CacheDataSource implements DataSource {
* @param src DataSource
*/
public CacheDataSource(DataSource src) {
- this.source = src;
- this.cachedAuths = CacheBuilder.newBuilder()
- .expireAfterWrite(8, TimeUnit.MINUTES)
- .removalListener(new RemovalListener>() {
+ source = src;
+ executorService = MoreExecutors.listeningDecorator(
+ Executors.newCachedThreadPool(new ThreadFactoryBuilder()
+ .setDaemon(true)
+ .setNameFormat("AuthMe-CacheLoader")
+ .build())
+ );
+ cachedAuths = CacheBuilder.newBuilder()
+ .refreshAfterWrite(8, TimeUnit.MINUTES)
+ .build(new CacheLoader>() {
@Override
- public void onRemoval(RemovalNotification> removalNotification) {
- String name = removalNotification.getKey();
- if (PlayerCache.getInstance().isAuthenticated(name)) {
- cachedAuths.getUnchecked(name);
- }
+ public Optional load(String key) {
+ return Optional.fromNullable(source.getAuth(key));
}
- })
- .build(
- new CacheLoader>() {
- @Override
- public Optional load(String key) {
- return Optional.fromNullable(source.getAuth(key));
- }
- });
+
+ @Override
+ public ListenableFuture> reload(final String key, Optional oldValue) {
+ return executorService.submit(new Callable>() {
+ @Override
+ public Optional call() {
+ return load(key);
+ }
+ });
+ }
+ });
+ }
+
+ public LoadingCache> getCachedAuths() {
+ return cachedAuths;
}
@Override
@@ -137,6 +153,13 @@ public class CacheDataSource implements DataSource {
@Override
public synchronized void close() {
source.close();
+ cachedAuths.invalidateAll();
+ executorService.shutdown();
+ try {
+ executorService.awaitTermination(5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ ConsoleLogger.writeStackTrace(e);
+ }
}
@Override
@@ -160,8 +183,8 @@ public class CacheDataSource implements DataSource {
}
@Override
- public synchronized List getAllAuthsByEmail(final String email) {
- return source.getAllAuthsByEmail(email);
+ public synchronized int countAuthsByEmail(final String email) {
+ return source.countAuthsByEmail(email);
}
@Override
@@ -201,12 +224,6 @@ public class CacheDataSource implements DataSource {
return source.getAccountsRegistered();
}
- @Override
- public void updateName(final String oldOne, final String newOne) { // unused method
- source.updateName(oldOne, newOne);
- cachedAuths.invalidate(oldOne);
- }
-
@Override
public boolean updateRealName(String user, String realName) {
boolean result = source.updateRealName(user, realName);
diff --git a/src/main/java/fr/xephi/authme/datasource/DataSource.java b/src/main/java/fr/xephi/authme/datasource/DataSource.java
index 4009586c2..6e3bc09b4 100644
--- a/src/main/java/fr/xephi/authme/datasource/DataSource.java
+++ b/src/main/java/fr/xephi/authme/datasource/DataSource.java
@@ -101,12 +101,12 @@ public interface DataSource {
List getAllAuthsByIp(String ip);
/**
- * Return all usernames associated with the given email address.
+ * Return the number of accounts associated with the given email address.
*
* @param email The email address to look up
- * @return Users using the given email address
+ * @return Number of accounts using the given email address
*/
- List getAllAuthsByEmail(String email);
+ int countAuthsByEmail(String email);
/**
* Update the email of the PlayerAuth in the data source.
@@ -169,14 +169,6 @@ public interface DataSource {
*/
int getAccountsRegistered();
- /**
- * Method updateName.
- *
- * @param oldOne String
- * @param newOne String
- */
- void updateName(String oldOne, String newOne);
-
boolean updateRealName(String user, String realName);
boolean updateIp(String user, String ip);
diff --git a/src/main/java/fr/xephi/authme/datasource/FlatFile.java b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
index 9bab76e14..c52d8e738 100644
--- a/src/main/java/fr/xephi/authme/datasource/FlatFile.java
+++ b/src/main/java/fr/xephi/authme/datasource/FlatFile.java
@@ -487,25 +487,21 @@ public class FlatFile implements DataSource {
}
@Override
- public List getAllAuthsByEmail(String email) {
+ public int countAuthsByEmail(String email) {
BufferedReader br = null;
- List countEmail = new ArrayList<>();
+ int countEmail = 0;
try {
br = new BufferedReader(new FileReader(source));
String line;
while ((line = br.readLine()) != null) {
String[] args = line.split(":");
if (args.length > 8 && args[8].equals(email)) {
- countEmail.add(args[0]);
+ ++countEmail;
}
}
return countEmail;
- } catch (FileNotFoundException ex) {
- ConsoleLogger.showError(ex.getMessage());
- return new ArrayList<>();
} catch (IOException ex) {
ConsoleLogger.showError(ex.getMessage());
- return new ArrayList<>();
} finally {
if (br != null) {
try {
@@ -514,6 +510,7 @@ public class FlatFile implements DataSource {
}
}
}
+ return 0;
}
@Override
@@ -602,14 +599,6 @@ public class FlatFile implements DataSource {
return result;
}
- @Override
- public void updateName(String oldOne, String newOne) {
- PlayerAuth auth = this.getAuth(oldOne);
- auth.setNickname(newOne);
- this.saveAuth(auth);
- this.removeAuth(oldOne);
- }
-
@Override
public boolean updateRealName(String user, String realName) {
return false;
diff --git a/src/main/java/fr/xephi/authme/datasource/MySQL.java b/src/main/java/fr/xephi/authme/datasource/MySQL.java
index a429d1814..1ab37d5ec 100644
--- a/src/main/java/fr/xephi/authme/datasource/MySQL.java
+++ b/src/main/java/fr/xephi/authme/datasource/MySQL.java
@@ -1,5 +1,6 @@
package fr.xephi.authme.datasource;
+import com.google.common.annotations.VisibleForTesting;
import com.zaxxer.hikari.HikariDataSource;
import com.zaxxer.hikari.pool.HikariPool.PoolInitializationException;
import fr.xephi.authme.AuthMe;
@@ -22,7 +23,6 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
-import java.sql.Timestamp;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;
@@ -82,6 +82,20 @@ public class MySQL implements DataSource {
}
}
+ @VisibleForTesting
+ MySQL(NewSetting settings, HikariDataSource hikariDataSource) {
+ this.host = settings.getProperty(DatabaseSettings.MYSQL_HOST);
+ this.port = settings.getProperty(DatabaseSettings.MYSQL_PORT);
+ this.username = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
+ this.password = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
+ this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
+ this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
+ this.columnOthers = settings.getProperty(HooksSettings.MYSQL_OTHER_USERNAME_COLS);
+ this.col = new Columns(settings);
+ this.hashAlgorithm = settings.getProperty(SecuritySettings.PASSWORD_HASH);
+ ds = hikariDataSource;
+ }
+
private synchronized void setConnectionArguments() throws RuntimeException {
ds = new HikariDataSource();
ds.setPoolName("AuthMeMYSQLPool");
@@ -131,7 +145,7 @@ public class MySQL implements DataSource {
+ col.REAL_NAME + " VARCHAR(255) NOT NULL,"
+ col.PASSWORD + " VARCHAR(255) NOT NULL,"
+ col.IP + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1',"
- + col.LAST_LOGIN + " TIMESTAMP NOT NULL DEFAULT current_timestamp,"
+ + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0,"
+ col.LASTLOC_X + " DOUBLE NOT NULL DEFAULT '0.0',"
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0',"
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0',"
@@ -182,9 +196,9 @@ public class MySQL implements DataSource {
rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
if (!rs.next()) {
st.executeUpdate("ALTER TABLE " + tableName
- + " ADD COLUMN " + col.LAST_LOGIN + " TIMESTAMP NOT NULL DEFAULT current_timestamp;");
+ + " ADD COLUMN " + col.LAST_LOGIN + " BIGINT NOT NULL DEFAULT 0;");
} else {
- migrateLastLoginColumnToTimestamp(con, rs);
+ migrateLastLoginColumnToBigInt(con, rs);
}
rs.close();
@@ -234,66 +248,72 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean isAuthAvailable(String user) {
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
+ ResultSet rs = null;
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user.toLowerCase());
- ResultSet rs = pst.executeQuery();
+ rs = pst.executeQuery();
return rs.next();
} catch (SQLException ex) {
logSqlException(ex);
+ } finally {
+ close(rs);
}
return false;
}
@Override
public HashedPassword getPassword(String user) {
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.PASSWORD + "," + col.SALT + " FROM " + tableName
- + " WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT " + col.PASSWORD + "," + col.SALT + " FROM " + tableName
+ + " WHERE " + col.NAME + "=?;";
+ ResultSet rs = null;
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user.toLowerCase());
- ResultSet rs = pst.executeQuery();
+ rs = pst.executeQuery();
if (rs.next()) {
return new HashedPassword(rs.getString(col.PASSWORD),
!col.SALT.isEmpty() ? rs.getString(col.SALT) : null);
}
} catch (SQLException ex) {
logSqlException(ex);
+ } finally {
+ close(rs);
}
return null;
}
@Override
public synchronized PlayerAuth getAuth(String user) {
- PlayerAuth pAuth;
- try (Connection con = getConnection()) {
- String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;";
+ PlayerAuth auth;
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user.toLowerCase());
- ResultSet rs = pst.executeQuery();
- if (!rs.next()) {
- return null;
+ int id;
+ try (ResultSet rs = pst.executeQuery()) {
+ if (!rs.next()) {
+ return null;
+ }
+ id = rs.getInt(col.ID);
+ auth = buildAuthFromResultSet(rs);
}
- int id = rs.getInt(col.ID);
- pAuth = buildAuthFromResultSet(rs);
- rs.close();
- pst.close();
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
- pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;");
- pst.setInt(1, id);
- rs = pst.executeQuery();
- if (rs.next()) {
- Blob blob = rs.getBlob("data");
- byte[] bytes = blob.getBytes(1, (int) blob.length());
- pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
+ try (PreparedStatement pst2 = con.prepareStatement(
+ "SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;")) {
+ pst2.setInt(1, id);
+ try (ResultSet rs = pst2.executeQuery()) {
+ if (rs.next()) {
+ Blob blob = rs.getBlob("data");
+ byte[] bytes = blob.getBytes(1, (int) blob.length());
+ auth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
+ }
+ }
}
}
+ return auth;
} catch (SQLException ex) {
logSqlException(ex);
- return null;
}
- return pAuth;
+ return null;
}
@Override
@@ -314,7 +334,7 @@ public class MySQL implements DataSource {
pst.setString(1, auth.getNickname());
pst.setString(2, auth.getPassword().getHash());
pst.setString(3, auth.getIp());
- pst.setTimestamp(4, new Timestamp(auth.getLastLogin()));
+ pst.setLong(4, auth.getLastLogin());
pst.setString(5, auth.getRealName());
pst.setString(6, auth.getEmail());
if (useSalt) {
@@ -566,7 +586,7 @@ public class MySQL implements DataSource {
+ col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getIp());
- pst.setTimestamp(2, new Timestamp(auth.getLastLogin()));
+ pst.setLong(2, auth.getLastLogin());
pst.setString(3, auth.getRealName());
pst.setString(4, auth.getNickname());
pst.executeUpdate();
@@ -580,20 +600,19 @@ public class MySQL implements DataSource {
@Override
public synchronized List autoPurgeDatabase(long until) {
List list = new ArrayList<>();
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- PreparedStatement st = con.prepareStatement(sql);
- st.setLong(1, until);
- ResultSet rs = st.executeQuery();
- while (rs.next()) {
- list.add(rs.getString(col.NAME));
+ String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
+ String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
+ try (Connection con = getConnection();
+ PreparedStatement selectPst = con.prepareStatement(select);
+ PreparedStatement deletePst = con.prepareStatement(delete)) {
+ selectPst.setLong(1, until);
+ try (ResultSet rs = selectPst.executeQuery()) {
+ while (rs.next()) {
+ list.add(rs.getString(col.NAME));
+ }
}
- rs.close();
- sql = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + ";";
- st = con.prepareStatement(sql);
- st.setLong(1, until);
- st.executeUpdate();
- st.close();
+ deletePst.setLong(1, until);
+ deletePst.executeUpdate();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -634,18 +653,16 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean updateQuitLoc(PlayerAuth auth) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName
- + " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?"
- + " WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName
+ + " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?"
+ + " WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setDouble(1, auth.getQuitLocX());
pst.setDouble(2, auth.getQuitLocY());
pst.setDouble(3, auth.getQuitLocZ());
pst.setString(4, auth.getWorld());
pst.setString(5, auth.getNickname());
pst.executeUpdate();
- pst.close();
return true;
} catch (SQLException ex) {
logSqlException(ex);
@@ -655,13 +672,11 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean updateEmail(PlayerAuth auth) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, auth.getEmail());
pst.setString(2, auth.getNickname());
pst.executeUpdate();
- pst.close();
return true;
} catch (SQLException ex) {
logSqlException(ex);
@@ -690,16 +705,14 @@ public class MySQL implements DataSource {
@Override
public synchronized List getAllAuthsByIp(String ip) {
List result = new ArrayList<>();
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
- ResultSet rs = pst.executeQuery();
- while (rs.next()) {
- result.add(rs.getString(col.NAME));
+ try (ResultSet rs = pst.executeQuery()) {
+ while (rs.next()) {
+ result.add(rs.getString(col.NAME));
+ }
}
- rs.close();
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -707,33 +720,29 @@ public class MySQL implements DataSource {
}
@Override
- public synchronized List getAllAuthsByEmail(String email) {
- List countEmail = new ArrayList<>();
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.EMAIL + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ public synchronized int countAuthsByEmail(String email) {
+ String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, email);
- ResultSet rs = pst.executeQuery();
- while (rs.next()) {
- countEmail.add(rs.getString(col.NAME));
+ try (ResultSet rs = pst.executeQuery()) {
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
}
- rs.close();
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
- return countEmail;
+ return 0;
}
@Override
public synchronized void purgeBanned(List banned) {
- try (Connection con = getConnection()) {
- PreparedStatement pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;");
+ String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
for (String name : banned) {
pst.setString(1, name);
pst.executeUpdate();
}
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -746,28 +755,25 @@ public class MySQL implements DataSource {
@Override
public boolean isLogged(String user) {
- boolean isLogged = false;
- try (Connection con = getConnection()) {
- String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user);
- ResultSet rs = pst.executeQuery();
- isLogged = rs.next() && (rs.getInt(col.IS_LOGGED) == 1);
+ try (ResultSet rs = pst.executeQuery()) {
+ return rs.next() && (rs.getInt(col.IS_LOGGED) == 1);
+ }
} catch (SQLException ex) {
logSqlException(ex);
}
- return isLogged;
+ return false;
}
@Override
public void setLogged(String user) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setInt(1, 1);
pst.setString(2, user.toLowerCase());
pst.executeUpdate();
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -775,13 +781,11 @@ public class MySQL implements DataSource {
@Override
public void setUnlogged(String user) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setInt(1, 0);
pst.setString(2, user.toLowerCase());
pst.executeUpdate();
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -789,13 +793,11 @@ public class MySQL implements DataSource {
@Override
public void purgeLogged() {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setInt(1, 0);
pst.setInt(2, 1);
pst.executeUpdate();
- pst.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -804,38 +806,23 @@ public class MySQL implements DataSource {
@Override
public int getAccountsRegistered() {
int result = 0;
- try (Connection con = getConnection()) {
- Statement st = con.createStatement();
- ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM " + tableName);
+ String sql = "SELECT COUNT(*) FROM " + tableName;
+ try (Connection con = getConnection();
+ Statement st = con.createStatement();
+ ResultSet rs = st.executeQuery(sql)) {
if (rs.next()) {
result = rs.getInt(1);
}
- rs.close();
- st.close();
} catch (SQLException ex) {
logSqlException(ex);
}
return result;
}
- @Override
- public void updateName(String oldOne, String newOne) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.NAME + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
- pst.setString(1, newOne);
- pst.setString(2, oldOne);
- pst.executeUpdate();
- } catch (SQLException ex) {
- logSqlException(ex);
- }
- }
-
@Override
public boolean updateRealName(String user, String realName) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, realName);
pst.setString(2, user);
pst.executeUpdate();
@@ -848,9 +835,8 @@ public class MySQL implements DataSource {
@Override
public boolean updateIp(String user, String ip) {
- try (Connection con = getConnection()) {
- String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
+ try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
pst.setString(2, user);
pst.executeUpdate();
@@ -867,23 +853,23 @@ public class MySQL implements DataSource {
try (Connection con = getConnection()) {
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName);
- PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;");
while (rs.next()) {
PlayerAuth pAuth = buildAuthFromResultSet(rs);
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
- int id = rs.getInt(col.ID);
- pst.setInt(1, id);
- ResultSet rs2 = pst.executeQuery();
- if (rs2.next()) {
- Blob blob = rs2.getBlob("data");
- byte[] bytes = blob.getBytes(1, (int) blob.length());
- pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
+ try (PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;")) {
+ int id = rs.getInt(col.ID);
+ pst.setInt(1, id);
+ ResultSet rs2 = pst.executeQuery();
+ if (rs2.next()) {
+ Blob blob = rs2.getBlob("data");
+ byte[] bytes = blob.getBytes(1, (int) blob.length());
+ pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
+ }
+ rs2.close();
}
- rs2.close();
}
auths.add(pAuth);
}
- pst.close();
rs.close();
st.close();
} catch (SQLException ex) {
@@ -922,12 +908,12 @@ public class MySQL implements DataSource {
@Override
public synchronized boolean isEmailStored(String email) {
- String sql = "SELECT 1 FROM " + tableName + " WHERE " + col.EMAIL + " = ?";
- try (Connection con = ds.getConnection()) {
- PreparedStatement pst = con.prepareStatement(sql);
+ String sql = "SELECT 1 FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)";
+ try (Connection con = ds.getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, email);
- ResultSet rs = pst.executeQuery();
- return rs.next();
+ try (ResultSet rs = pst.executeQuery()) {
+ return rs.next();
+ }
} catch (SQLException e) {
logSqlException(e);
}
@@ -941,7 +927,7 @@ public class MySQL implements DataSource {
.name(row.getString(col.NAME))
.realName(row.getString(col.REAL_NAME))
.password(row.getString(col.PASSWORD), salt)
- .lastLogin(safeGetTimestamp(row))
+ .lastLogin(row.getLong(col.LAST_LOGIN))
.ip(row.getString(col.IP))
.locWorld(row.getString(col.LASTLOC_WORLD))
.locX(row.getDouble(col.LASTLOC_X))
@@ -953,24 +939,15 @@ public class MySQL implements DataSource {
}
/**
- * Retrieve the last login timestamp in a safe way.
+ * Check if the lastlogin column is of type timestamp and, if so, revert it to the bigint format.
*
- * @param row The ResultSet to read
- * @return The timestamp (as number of milliseconds since 1970-01-01 00:00:00 GMT)
+ * @param con Connection to the database
+ * @param rs ResultSet containing meta data for the lastlogin column
*/
- private long safeGetTimestamp(ResultSet row) {
- try {
- return row.getTimestamp(col.LAST_LOGIN).getTime();
- } catch (SQLException e) {
- ConsoleLogger.logException("Could not get timestamp from resultSet. Defaulting to current time", e);
- }
- return System.currentTimeMillis();
- }
-
- private void migrateLastLoginColumnToTimestamp(Connection con, ResultSet rs) throws SQLException {
+ private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException {
final int columnType = rs.getInt("DATA_TYPE");
- if (columnType == Types.BIGINT) {
- ConsoleLogger.info("Migrating lastlogin column from bigint to timestamp");
+ if (columnType == Types.TIMESTAMP) {
+ ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
final String lastLoginOld = col.LAST_LOGIN + "_old";
// Rename lastlogin to lastlogin_old
@@ -981,12 +958,12 @@ public class MySQL implements DataSource {
// Create lastlogin column
sql = String.format("ALTER TABLE %s ADD COLUMN %s "
- + "TIMESTAMP NOT NULL DEFAULT current_timestamp AFTER %s",
+ + "BIGINT NOT NULL DEFAULT 0 AFTER %s",
tableName, col.LAST_LOGIN, col.IP);
con.prepareStatement(sql).execute();
// Set values of lastlogin based on lastlogin_old
- sql = String.format("UPDATE %s SET %s = FROM_UNIXTIME(%s)",
+ sql = String.format("UPDATE %s SET %s = UNIX_TIMESTAMP(%s)",
tableName, col.LAST_LOGIN, lastLoginOld);
con.prepareStatement(sql).execute();
@@ -994,7 +971,7 @@ public class MySQL implements DataSource {
sql = String.format("ALTER TABLE %s DROP COLUMN %s",
tableName, lastLoginOld);
con.prepareStatement(sql).execute();
- ConsoleLogger.info("Finished migration of lastlogin (bigint to timestamp)");
+ ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
}
}
@@ -1002,4 +979,14 @@ public class MySQL implements DataSource {
ConsoleLogger.logException("Error during SQL operation:", e);
}
+ private static void close(ResultSet rs) {
+ if (rs != null) {
+ try {
+ rs.close();
+ } catch (SQLException e) {
+ ConsoleLogger.logException("Could not close ResultSet", e);
+ }
+ }
+ }
+
}
diff --git a/src/main/java/fr/xephi/authme/datasource/SQLite.java b/src/main/java/fr/xephi/authme/datasource/SQLite.java
index 081e386cf..d0c39e154 100644
--- a/src/main/java/fr/xephi/authme/datasource/SQLite.java
+++ b/src/main/java/fr/xephi/authme/datasource/SQLite.java
@@ -1,5 +1,6 @@
package fr.xephi.authme.datasource;
+import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
@@ -46,6 +47,14 @@ public class SQLite implements DataSource {
}
}
+ @VisibleForTesting
+ SQLite(NewSetting settings, Connection connection) {
+ this.database = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
+ this.tableName = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
+ this.col = new Columns(settings);
+ this.con = connection;
+ }
+
private synchronized void connect() throws ClassNotFoundException, SQLException {
Class.forName("org.sqlite.JDBC");
ConsoleLogger.info("SQLite driver loaded");
@@ -341,7 +350,8 @@ public class SQLite implements DataSource {
@Override
public synchronized void close() {
try {
- con.close();
+ if (con != null && !con.isClosed())
+ con.close();
} catch (SQLException ex) {
logSqlException(ex);
}
@@ -394,25 +404,19 @@ public class SQLite implements DataSource {
}
@Override
- public List getAllAuthsByEmail(String email) {
- PreparedStatement pst = null;
- ResultSet rs = null;
- List countEmail = new ArrayList<>();
- try {
- pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + col.EMAIL + "=?;");
+ public int countAuthsByEmail(String email) {
+ String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE " + col.EMAIL + " = ? COLLATE NOCASE;";
+ try (PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, email);
- rs = pst.executeQuery();
- while (rs.next()) {
- countEmail.add(rs.getString(col.NAME));
+ try (ResultSet rs = pst.executeQuery()) {
+ if (rs.next()) {
+ return rs.getInt(1);
+ }
}
- return countEmail;
} catch (SQLException ex) {
logSqlException(ex);
- } finally {
- close(rs);
- close(pst);
}
- return new ArrayList<>();
+ return 0;
}
@Override
@@ -519,21 +523,6 @@ public class SQLite implements DataSource {
return 0;
}
- @Override
- public void updateName(String oldOne, String newOne) {
- PreparedStatement pst = null;
- try {
- pst = con.prepareStatement("UPDATE " + tableName + " SET " + col.NAME + "=? WHERE " + col.NAME + "=?;");
- pst.setString(1, newOne);
- pst.setString(2, oldOne);
- pst.executeUpdate();
- } catch (SQLException ex) {
- logSqlException(ex);
- } finally {
- close(pst);
- }
- }
-
@Override
public boolean updateRealName(String user, String realName) {
String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
index 56918026c..d563f33c0 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMePlayerListener.java
@@ -17,7 +17,6 @@ import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.GeoLiteAPI;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
-import org.bukkit.ChatColor;
import org.bukkit.GameMode;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@@ -243,9 +242,7 @@ public class AuthMePlayerListener implements Listener {
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());
+ event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CASE, realName, event.getName()));
return;
}
if (realName.isEmpty() || realName.equals("Player")) {
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
index 5d080ef65..54cce57a9 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerListener.java
@@ -81,6 +81,8 @@ public class AuthMeServerListener implements Listener {
}
if (pluginName.equalsIgnoreCase("ProtocolLib")) {
plugin.inventoryProtector = null;
+ plugin.tablistHider = null;
+ plugin.tabComplete = null;
ConsoleLogger.showError("ProtocolLib has been disabled, unhook packet inventory protection!");
}
}
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
index 3bb083592..ad3402d6e 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeTabCompletePacketAdapter.java
@@ -6,32 +6,27 @@ import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
- public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
- super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
- }
+ public AuthMeTabCompletePacketAdapter(AuthMe plugin) {
+ super(plugin, ListenerPriority.NORMAL, PacketType.Play.Client.TAB_COMPLETE);
+ }
- @Override
- public void onPacketReceiving(PacketEvent event)
- {
- if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) {
- try
- {
- if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
- event.setCancelled(true);
- }
+ @Override
+ public void onPacketReceiving(PacketEvent event) {
+ if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) {
+ try {
+ if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
+ event.setCancelled(true);
+ }
+ } catch (FieldAccessException e) {
+ ConsoleLogger.showError("Couldn't access field.");
+ }
}
- catch (FieldAccessException e)
- {
- ConsoleLogger.showError("Couldn't access field.");
- }
- }
}
public void register() {
diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
index ea8effd00..d85a5c5e9 100644
--- a/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
+++ b/src/main/java/fr/xephi/authme/listener/AuthMeTablistPacketAdapter.java
@@ -6,32 +6,27 @@ import com.comphenix.protocol.events.ListenerPriority;
import com.comphenix.protocol.events.PacketAdapter;
import com.comphenix.protocol.events.PacketEvent;
import com.comphenix.protocol.reflect.FieldAccessException;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerCache;
public class AuthMeTablistPacketAdapter extends PacketAdapter {
- public AuthMeTablistPacketAdapter(AuthMe plugin) {
- super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
- }
+ public AuthMeTablistPacketAdapter(AuthMe plugin) {
+ super(plugin, ListenerPriority.NORMAL, PacketType.Play.Server.PLAYER_INFO);
+ }
- @Override
- public void onPacketSending(PacketEvent event)
- {
- if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
- try
- {
- if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
- event.setCancelled(true);
- }
+ @Override
+ public void onPacketSending(PacketEvent event) {
+ if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
+ try {
+ if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
+ event.setCancelled(true);
+ }
+ } catch (FieldAccessException e) {
+ ConsoleLogger.showError("Couldn't access field.");
+ }
}
- catch (FieldAccessException e)
- {
- ConsoleLogger.showError("Couldn't access field.");
- }
- }
}
public void register() {
diff --git a/src/main/java/fr/xephi/authme/output/MessageKey.java b/src/main/java/fr/xephi/authme/output/MessageKey.java
index d5e601207..45cdc0bef 100644
--- a/src/main/java/fr/xephi/authme/output/MessageKey.java
+++ b/src/main/java/fr/xephi/authme/output/MessageKey.java
@@ -127,7 +127,9 @@ public enum MessageKey {
TWO_FACTOR_CREATE("two_factor_create", "%code", "%url"),
- NOT_OWNER_ERROR("not_owner_error");
+ NOT_OWNER_ERROR("not_owner_error"),
+
+ INVALID_NAME_CASE("invalid_name_case", "%valid", "%invalid");
private String key;
private String[] tags;
diff --git a/src/main/java/fr/xephi/authme/output/Messages.java b/src/main/java/fr/xephi/authme/output/Messages.java
index 5afba4726..9ea87f448 100644
--- a/src/main/java/fr/xephi/authme/output/Messages.java
+++ b/src/main/java/fr/xephi/authme/output/Messages.java
@@ -55,17 +55,7 @@ public class Messages {
* @param replacements The replacements to apply for the tags
*/
public void send(CommandSender sender, MessageKey key, String... replacements) {
- String message = retrieveSingle(key);
- String[] tags = key.getTags();
- if (replacements.length == tags.length) {
- for (int i = 0; i < tags.length; ++i) {
- message = message.replace(tags[i], replacements[i]);
- }
- } else {
- ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
- send(sender, key);
- }
-
+ String message = retrieveSingle(key, replacements);
for (String line : message.split("\n")) {
sender.sendMessage(line);
}
@@ -99,6 +89,27 @@ public class Messages {
return StringUtils.join("\n", retrieve(key));
}
+ /**
+ * Retrieve the given message code with the given tag replacements. Note that this method
+ * logs an error if the number of supplied replacements doesn't correspond to the number of tags
+ * the message key contains.
+ *
+ * @param key The key of the message to send
+ * @param replacements The replacements to apply for the tags
+ */
+ public String retrieveSingle(MessageKey key, String... replacements) {
+ String message = retrieveSingle(key);
+ String[] tags = key.getTags();
+ if (replacements.length == tags.length) {
+ for (int i = 0; i < tags.length; ++i) {
+ message = message.replace(tags[i], replacements[i]);
+ }
+ } else {
+ ConsoleLogger.showError("Invalid number of replacements for message key '" + key + "'");
+ }
+ return message;
+ }
+
/**
* Reload the messages manager.
*
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 f738268ee..e1b6096bb 100644
--- a/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
+++ b/src/main/java/fr/xephi/authme/process/join/AsynchronousJoin.java
@@ -206,20 +206,20 @@ public class AsynchronousJoin {
int msgInterval = Settings.getWarnMessageInterval;
if (timeOut > 0) {
- BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), timeOut);
+ BukkitTask id = sched.runTaskLater(plugin, new TimeoutTask(plugin, name, player), timeOut);
LimboCache.getInstance().getLimboPlayer(name).setTimeoutTaskId(id);
}
- String[] msg;
+ MessageKey msg;
if (isAuthAvailable) {
- msg = m.retrieve(MessageKey.LOGIN_MESSAGE);
+ msg = MessageKey.LOGIN_MESSAGE;
} else {
msg = Settings.emailRegistration
- ? m.retrieve(MessageKey.REGISTER_EMAIL_MESSAGE)
- : m.retrieve(MessageKey.REGISTER_MESSAGE);
+ ? MessageKey.REGISTER_EMAIL_MESSAGE
+ : MessageKey.REGISTER_MESSAGE;
}
if (msgInterval > 0 && LimboCache.getInstance().getLimboPlayer(name) != null) {
- BukkitTask msgTask = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, msg, msgInterval));
+ BukkitTask msgTask = sched.runTask(plugin, new MessageTask(plugin, name, msg, msgInterval));
LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgTask);
}
}
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 09647dfff..fcc64ab0e 100644
--- a/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
+++ b/src/main/java/fr/xephi/authme/process/login/AsynchronousLogin.java
@@ -105,7 +105,7 @@ public class AsynchronousLogin {
} else {
msg = m.retrieve(MessageKey.REGISTER_MESSAGE);
}
- BukkitTask msgT = Bukkit.getScheduler().runTaskAsynchronously(plugin,
+ BukkitTask msgT = Bukkit.getScheduler().runTask(plugin,
new MessageTask(plugin, name, msg, settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL)));
LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT);
}
diff --git a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java
index 5a8133b79..64c300ef0 100644
--- a/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java
+++ b/src/main/java/fr/xephi/authme/process/logout/ProcessSyncronousPlayerLogout.java
@@ -74,21 +74,24 @@ public class ProcessSyncronousPlayerLogout implements Runnable {
int interval = Settings.getWarnMessageInterval;
BukkitScheduler sched = player.getServer().getScheduler();
if (timeOut != 0) {
- BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), timeOut);
+ BukkitTask id = sched.runTaskLater(plugin, new TimeoutTask(plugin, name, player), timeOut);
LimboCache.getInstance().getLimboPlayer(name).setTimeoutTaskId(id);
}
- BukkitTask msgT = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.retrieve(MessageKey.LOGIN_MESSAGE), interval));
+ BukkitTask msgT = sched.runTask(plugin, new MessageTask(plugin, name, MessageKey.LOGIN_MESSAGE, interval));
LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT);
- if (player.isInsideVehicle() && player.getVehicle() != null)
+ if (player.isInsideVehicle() && player.getVehicle() != null) {
player.getVehicle().eject();
- if (Settings.applyBlindEffect)
- player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2));
+ }
+ if (Settings.applyBlindEffect) {
+ player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeOut, 2));
+ }
player.setOp(false);
restoreSpeedEffect();
// Player is now logout... Time to fire event !
Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player));
- if (Settings.bungee)
+ if (Settings.bungee) {
sendBungeeMessage();
+ }
m.send(player, MessageKey.LOGOUT_SUCCESS);
ConsoleLogger.info(player.getName() + " logged out");
}
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 00b477440..7f716e7e6 100644
--- a/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
+++ b/src/main/java/fr/xephi/authme/process/quit/AsynchronousQuit.java
@@ -5,34 +5,26 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer;
+import fr.xephi.authme.datasource.CacheDataSource;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
-/**
- */
public class AsynchronousQuit {
- protected final AuthMe plugin;
- protected final DataSource database;
- protected final Player player;
+ private final AuthMe plugin;
+ private final DataSource database;
+ private final Player player;
private final String name;
private boolean isOp = false;
private boolean needToChange = false;
private boolean isKick = false;
- /**
- * Constructor for AsynchronousQuit.
- *
- * @param p Player
- * @param plugin AuthMe
- * @param database DataSource
- * @param isKick boolean
- */
public AsynchronousQuit(Player p, AuthMe plugin, DataSource database,
boolean isKick) {
this.player = p;
@@ -43,9 +35,7 @@ public class AsynchronousQuit {
}
public void process() {
- if (player == null)
- return;
- if (Utils.isUnrestricted(player)) {
+ if (player == null || Utils.isUnrestricted(player)) {
return;
}
@@ -54,7 +44,9 @@ public class AsynchronousQuit {
if (PlayerCache.getInstance().isAuthenticated(name)) {
if (Settings.isSaveQuitLocationEnabled) {
Location loc = player.getLocation();
- PlayerAuth auth = new PlayerAuth(name, loc.getX(), loc.getY(), loc.getZ(), loc.getWorld().getName(), player.getName());
+ PlayerAuth auth = PlayerAuth.builder()
+ .name(name).location(loc)
+ .realName(player.getName()).build();
database.updateQuitLoc(auth);
}
PlayerAuth auth = new PlayerAuth(name, ip, System.currentTimeMillis(), player.getName());
@@ -63,14 +55,11 @@ public class AsynchronousQuit {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name);
if (limbo != null) {
- if (limbo.getGroup() != null && !limbo.getGroup().isEmpty())
+ if (!StringUtils.isEmpty(limbo.getGroup())) {
Utils.addNormal(player, limbo.getGroup());
+ }
needToChange = true;
isOp = limbo.getOperator();
- if (limbo.getTimeoutTaskId() != null)
- limbo.getTimeoutTaskId().cancel();
- if (limbo.getMessageTaskId() != null)
- limbo.getMessageTaskId().cancel();
LimboCache.getInstance().deleteLimboPlayer(name);
}
if (Settings.isSessionsEnabled && !isKick) {
@@ -100,12 +89,15 @@ public class AsynchronousQuit {
if (plugin.isEnabled()) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerQuit(plugin, player, isOp, needToChange));
}
+ // remove player from cache
+ if (database instanceof CacheDataSource) {
+ ((CacheDataSource) database).getCachedAuths().invalidate(name);
+ }
}
private void postLogout() {
PlayerCache.getInstance().removePlayer(name);
- if (database.isLogged(name))
- database.setUnlogged(name);
+ database.setUnlogged(name);
plugin.sessions.remove(name);
}
}
diff --git a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
index ac9215105..e17c511da 100644
--- a/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/AsyncRegister.java
@@ -98,7 +98,7 @@ public class AsyncRegister {
private void emailRegister() {
if (Settings.getmaxRegPerEmail > 0
&& !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
- && database.getAllAuthsByEmail(email).size() >= Settings.getmaxRegPerEmail) {
+ && database.countAuthsByEmail(email) >= Settings.getmaxRegPerEmail) {
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
return;
}
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
index 4d8dcf9e9..47264c0f1 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncEmailRegister.java
@@ -52,14 +52,13 @@ public class ProcessSyncEmailRegister implements Runnable {
int msgInterval = Settings.getWarnMessageInterval;
BukkitScheduler sched = plugin.getServer().getScheduler();
- if (time != 0 && limbo != null) {
- limbo.getTimeoutTaskId().cancel();
- BukkitTask id = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), time);
- limbo.setTimeoutTaskId(id);
- }
+
if (limbo != null) {
- limbo.getMessageTaskId().cancel();
- BukkitTask nwMsg = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, m.retrieve(MessageKey.LOGIN_MESSAGE), msgInterval));
+ if (time != 0) {
+ BukkitTask id = sched.runTaskLater(plugin, new TimeoutTask(plugin, name, player), time);
+ limbo.setTimeoutTaskId(id);
+ }
+ BukkitTask nwMsg = sched.runTask(plugin, new MessageTask(plugin, name, m.retrieve(MessageKey.LOGIN_MESSAGE), msgInterval));
limbo.setMessageTaskId(nwMsg);
}
diff --git a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
index 60f5bc187..9f9f8919a 100644
--- a/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
+++ b/src/main/java/fr/xephi/authme/process/register/ProcessSyncPasswordRegister.java
@@ -1,16 +1,7 @@
package fr.xephi.authme.process.register;
-import fr.xephi.authme.settings.NewSetting;
-import fr.xephi.authme.settings.properties.HooksSettings;
-import org.bukkit.Bukkit;
-import org.bukkit.entity.Player;
-import org.bukkit.potion.PotionEffectType;
-import org.bukkit.scheduler.BukkitScheduler;
-import org.bukkit.scheduler.BukkitTask;
-
import com.google.common.io.ByteArrayDataOutput;
import com.google.common.io.ByteStreams;
-
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.limbo.LimboCache;
@@ -19,10 +10,17 @@ import fr.xephi.authme.events.LoginEvent;
import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
+import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
+import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.task.MessageTask;
import fr.xephi.authme.task.TimeoutTask;
import fr.xephi.authme.util.Utils;
+import org.bukkit.Bukkit;
+import org.bukkit.entity.Player;
+import org.bukkit.potion.PotionEffectType;
+import org.bukkit.scheduler.BukkitScheduler;
+import org.bukkit.scheduler.BukkitTask;
/**
*/
@@ -37,8 +35,8 @@ public class ProcessSyncPasswordRegister implements Runnable {
/**
* Constructor for ProcessSyncPasswordRegister.
*
- * @param player Player
- * @param plugin AuthMe
+ * @param player Player
+ * @param plugin AuthMe
* @param settings The plugin settings
*/
public ProcessSyncPasswordRegister(Player player, AuthMe plugin, NewSetting settings) {
@@ -77,11 +75,10 @@ public class ProcessSyncPasswordRegister implements Runnable {
BukkitScheduler sched = plugin.getServer().getScheduler();
BukkitTask task;
if (delay != 0) {
- task = sched.runTaskLaterAsynchronously(plugin, new TimeoutTask(plugin, name, player), delay);
+ task = sched.runTaskLater(plugin, new TimeoutTask(plugin, name, player), delay);
cache.getLimboPlayer(name).setTimeoutTaskId(task);
}
- task = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name,
- m.retrieve(MessageKey.LOGIN_MESSAGE), interval));
+ task = sched.runTask(plugin, new MessageTask(plugin, name, MessageKey.LOGIN_MESSAGE, interval));
cache.getLimboPlayer(name).setMessageTaskId(task);
if (player.isInsideVehicle() && player.getVehicle() != null) {
player.getVehicle().eject();
@@ -158,7 +155,7 @@ public class ProcessSyncPasswordRegister implements Runnable {
// Register is now finished; we can force all commands
forceCommands();
-
+
sendTo();
}
diff --git a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
index 58c176941..7da80c390 100644
--- a/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
+++ b/src/main/java/fr/xephi/authme/process/unregister/AsynchronousUnregister.java
@@ -73,12 +73,11 @@ public class AsynchronousUnregister {
int interval = Settings.getWarnMessageInterval;
BukkitScheduler scheduler = plugin.getServer().getScheduler();
if (timeOut != 0) {
- BukkitTask id = scheduler.runTaskLaterAsynchronously(plugin,
- new TimeoutTask(plugin, name, player), timeOut);
+ BukkitTask id = scheduler.runTaskLater(plugin, new TimeoutTask(plugin, name, player), timeOut);
limboPlayer.setTimeoutTaskId(id);
}
- limboPlayer.setMessageTaskId(scheduler.runTaskAsynchronously(plugin,
- new MessageTask(plugin, name, m.retrieve(MessageKey.REGISTER_MESSAGE), interval)));
+ limboPlayer.setMessageTaskId(scheduler.runTask(plugin,
+ new MessageTask(plugin, name, MessageKey.REGISTER_MESSAGE, interval)));
m.send(player, MessageKey.UNREGISTERED_SUCCESS);
ConsoleLogger.info(player.getDisplayName() + " unregistered himself");
return;
diff --git a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java
index ee1645257..3defffe44 100644
--- a/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java
+++ b/src/main/java/fr/xephi/authme/settings/CustomConfiguration.java
@@ -82,4 +82,13 @@ public abstract class CustomConfiguration extends YamlConfiguration {
}
return false;
}
+
+ public boolean containsAll(String... paths) {
+ for (String path : paths) {
+ if (!contains(path)) {
+ return false;
+ }
+ }
+ return true;
+ }
}
diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java
index 7ba3b3b18..53a8560cf 100644
--- a/src/main/java/fr/xephi/authme/settings/Settings.java
+++ b/src/main/java/fr/xephi/authme/settings/Settings.java
@@ -5,6 +5,7 @@ import fr.xephi.authme.datasource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.DatabaseSettings;
+import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
@@ -144,8 +145,6 @@ public final class Settings {
denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN);
- plugin.checkProtocolLib();
-
passwordMaxLength = load(SecuritySettings.MAX_PASSWORD_LENGTH);
backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
@@ -176,7 +175,7 @@ public final class Settings {
emailRegistration = configFile.getBoolean("settings.registration.enableEmailRegistrationSystem", false);
saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8);
getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1);
- multiverse = configFile.getBoolean("Hooks.multiverse", true);
+ multiverse = load(HooksSettings.MULTIVERSE);
bungee = configFile.getBoolean("Hooks.bungeecord", false);
getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds");
banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false);
@@ -213,7 +212,7 @@ public final class Settings {
broadcastWelcomeMessage = configFile.getBoolean("settings.broadcastWelcomeMessage", false);
forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false);
forceRegLogin = configFile.getBoolean("settings.registration.forceLoginAfterRegister", false);
- spawnPriority = configFile.getString("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default");
+ spawnPriority = load(RestrictionSettings.SPAWN_PRIORITY);
getMaxLoginPerIp = configFile.getInt("settings.restrictions.maxLoginPerIp", 0);
getMaxJoinPerIp = configFile.getInt("settings.restrictions.maxJoinPerIp", 0);
checkVeryGames = configFile.getBoolean("VeryGames.enableIpCheck", false);
diff --git a/src/main/java/fr/xephi/authme/settings/Spawn.java b/src/main/java/fr/xephi/authme/settings/Spawn.java
index 4c20b2960..e891e47fb 100644
--- a/src/main/java/fr/xephi/authme/settings/Spawn.java
+++ b/src/main/java/fr/xephi/authme/settings/Spawn.java
@@ -1,7 +1,13 @@
package fr.xephi.authme.settings;
+import com.onarandombox.MultiverseCore.api.MVWorldManager;
+import fr.xephi.authme.AuthMe;
+import fr.xephi.authme.cache.auth.PlayerCache;
+import fr.xephi.authme.util.StringUtils;
import org.bukkit.Bukkit;
import org.bukkit.Location;
+import org.bukkit.World;
+import org.bukkit.entity.Player;
import java.io.File;
@@ -12,13 +18,17 @@ import java.io.File;
public class Spawn extends CustomConfiguration {
private static Spawn spawn;
+ private static String[] spawnPriority;
- public Spawn() {
- super(new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "spawn.yml"));
- spawn = this;
+ private Spawn() {
+ super(new File(Settings.PLUGIN_FOLDER, "spawn.yml"));
load();
save();
- saveDefault();
+ spawnPriority = Settings.spawnPriority.split(",");
+ }
+
+ public static void reload() {
+ spawn = new Spawn();
}
/**
@@ -33,111 +43,106 @@ public class Spawn extends CustomConfiguration {
return spawn;
}
- private void saveDefault() {
- if (!contains("spawn")) {
- set("spawn.world", "");
- set("spawn.x", "");
- set("spawn.y", "");
- set("spawn.z", "");
- set("spawn.yaw", "");
- set("spawn.pitch", "");
- save();
- }
- if (!contains("firstspawn")) {
- set("firstspawn.world", "");
- set("firstspawn.x", "");
- set("firstspawn.y", "");
- set("firstspawn.z", "");
- set("firstspawn.yaw", "");
- set("firstspawn.pitch", "");
- save();
- }
- }
-
- /**
- * Method setSpawn.
- *
- * @param location Location
- *
- * @return boolean
- */
public boolean setSpawn(Location location) {
- try {
- set("spawn.world", location.getWorld().getName());
- set("spawn.x", location.getX());
- set("spawn.y", location.getY());
- set("spawn.z", location.getZ());
- set("spawn.yaw", location.getYaw());
- set("spawn.pitch", location.getPitch());
- save();
- return true;
- } catch (NullPointerException npe) {
+ if (location == null || location.getWorld() == null) {
return false;
}
+ set("spawn.world", location.getWorld().getName());
+ set("spawn.x", location.getX());
+ set("spawn.y", location.getY());
+ set("spawn.z", location.getZ());
+ set("spawn.yaw", location.getYaw());
+ set("spawn.pitch", location.getPitch());
+ save();
+ return true;
}
- /**
- * Method setFirstSpawn.
- *
- * @param location Location
- *
- * @return boolean
- */
public boolean setFirstSpawn(Location location) {
- try {
- set("firstspawn.world", location.getWorld().getName());
- set("firstspawn.x", location.getX());
- set("firstspawn.y", location.getY());
- set("firstspawn.z", location.getZ());
- set("firstspawn.yaw", location.getYaw());
- set("firstspawn.pitch", location.getPitch());
- save();
- return true;
- } catch (NullPointerException npe) {
+ if (location == null || location.getWorld() == null) {
return false;
}
+ set("firstspawn.world", location.getWorld().getName());
+ set("firstspawn.x", location.getX());
+ set("firstspawn.y", location.getY());
+ set("firstspawn.z", location.getZ());
+ set("firstspawn.yaw", location.getYaw());
+ set("firstspawn.pitch", location.getPitch());
+ save();
+ return true;
}
- /**
- * Method getLocation.
- *
- * @return Location
- */
- @Deprecated
- public Location getLocation() {
- return getSpawn();
- }
-
- /**
- * Method getSpawn.
- *
- * @return Location
- */
public Location getSpawn() {
- try {
- if (this.getString("spawn.world").isEmpty() || this.getString("spawn.world").equals(""))
- return null;
- Location location = new Location(Bukkit.getWorld(this.getString("spawn.world")), this.getDouble("spawn.x"), this.getDouble("spawn.y"), this.getDouble("spawn.z"), Float.parseFloat(this.getString("spawn.yaw")), Float.parseFloat(this.getString("spawn.pitch")));
- return location;
- } catch (NullPointerException | NumberFormatException npe) {
- return null;
+ if (containsAll("spawn.world", "spawn.x", "spawn.y", "spawn.z", "spawn.yaw", "spawn.pitch")) {
+ String worldName = getString("spawn.world");
+ World world = Bukkit.getWorld(worldName);
+ if (!StringUtils.isEmpty(worldName) && world != null) {
+ return new Location(
+ world, getDouble("spawn.x"), getDouble("spawn.y"), getDouble("spawn.z"),
+ Float.parseFloat(getString("spawn.yaw")), Float.parseFloat(getString("spawn.pitch"))
+ );
+ }
}
+ return null;
}
- /**
- * Method getFirstSpawn.
- *
- * @return Location
- */
public Location getFirstSpawn() {
- try {
- if (this.getString("firstspawn.world").isEmpty() || this.getString("firstspawn.world").equals(""))
- return null;
- Location location = new Location(Bukkit.getWorld(this.getString("firstspawn.world")), this.getDouble("firstspawn.x"), this.getDouble("firstspawn.y"), this.getDouble("firstspawn.z"), Float.parseFloat(this.getString("firstspawn.yaw")), Float.parseFloat(this.getString("firstspawn.pitch")));
- return location;
- } catch (NullPointerException | NumberFormatException npe) {
- return null;
+ if (containsAll("firstspawn.world", "firstspawn.x", "firstspawn.y",
+ "firstspawn.z", "firstspawn.yaw", "firstspawn.pitch")) {
+ String worldName = getString("firstspawn.world");
+ World world = Bukkit.getWorld(worldName);
+ if (!StringUtils.isEmpty(worldName) && world != null) {
+ return new Location(
+ world, getDouble("firstspawn.x"), getDouble("firstspawn.y"), getDouble("firstspawn.z"),
+ Float.parseFloat(getString("firstspawn.yaw")), Float.parseFloat(getString("firstspawn.pitch"))
+ );
+ }
}
+ return null;
}
+ // Return the spawn location of a player
+ public Location getSpawnLocation(Player player) {
+ AuthMe plugin = AuthMe.getInstance();
+ if (plugin == null || player == null || player.getWorld() == null) {
+ return null;
+ }
+
+ World world = player.getWorld();
+ Location spawnLoc = null;
+ for (String priority : spawnPriority) {
+ switch (priority.toLowerCase()) {
+ case "default":
+ if (world.getSpawnLocation() != null) {
+ spawnLoc = world.getSpawnLocation();
+ }
+ break;
+ case "multiverse":
+ if (Settings.multiverse && plugin.multiverse != null) {
+ MVWorldManager manager = plugin.multiverse.getMVWorldManager();
+ if (manager.isMVWorld(world)) {
+ spawnLoc = manager.getMVWorld(world).getSpawnLocation();
+ }
+ }
+ break;
+ case "essentials":
+ spawnLoc = plugin.essentialsSpawn;
+ break;
+ case "authme":
+ String playerNameLower = player.getName().toLowerCase();
+ if (PlayerCache.getInstance().isAuthenticated(playerNameLower)) {
+ spawnLoc = getSpawn();
+ } else if ((getFirstSpawn() != null) && (!player.hasPlayedBefore() ||
+ (!plugin.getDataSource().isAuthAvailable(playerNameLower)))) {
+ spawnLoc = getFirstSpawn();
+ } else {
+ spawnLoc = getSpawn();
+ }
+ break;
+ }
+ if (spawnLoc != null) {
+ return spawnLoc;
+ }
+ }
+ return world.getSpawnLocation(); // return default location
+ }
}
diff --git a/src/main/java/fr/xephi/authme/task/MessageTask.java b/src/main/java/fr/xephi/authme/task/MessageTask.java
index cfaa7d4a4..92310f376 100644
--- a/src/main/java/fr/xephi/authme/task/MessageTask.java
+++ b/src/main/java/fr/xephi/authme/task/MessageTask.java
@@ -3,6 +3,7 @@ package fr.xephi.authme.task;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.cache.limbo.LimboCache;
+import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitTask;
@@ -24,32 +25,31 @@ public class MessageTask implements Runnable {
* @param strings String[]
* @param interval int
*/
- public MessageTask(AuthMe plugin, String name, String[] strings,
- int interval) {
+ public MessageTask(AuthMe plugin, String name, String[] strings, int interval) {
this.plugin = plugin;
this.name = name;
this.msg = strings;
this.interval = interval;
}
- /**
- * Method run.
- *
- * @see java.lang.Runnable#run()
- */
+ public MessageTask(AuthMe plugin, String name, MessageKey messageKey, int interval) {
+ this(plugin, name, plugin.getMessages().retrieve(messageKey), interval);
+ }
+
@Override
public void run() {
- if (PlayerCache.getInstance().isAuthenticated(name))
+ if (PlayerCache.getInstance().isAuthenticated(name)) {
return;
+ }
for (Player player : Utils.getOnlinePlayers()) {
- if (player.getName().toLowerCase().equals(name)) {
+ if (player.getName().equalsIgnoreCase(name)) {
for (String ms : msg) {
player.sendMessage(ms);
}
- BukkitTask late = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, this, interval * 20);
+ BukkitTask nextTask = plugin.getServer().getScheduler().runTaskLater(plugin, this, interval * 20);
if (LimboCache.getInstance().hasLimboPlayer(name)) {
- LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(late);
+ LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(nextTask);
}
return;
}
diff --git a/src/main/java/fr/xephi/authme/task/TimeoutTask.java b/src/main/java/fr/xephi/authme/task/TimeoutTask.java
index eedf08755..b304632d5 100644
--- a/src/main/java/fr/xephi/authme/task/TimeoutTask.java
+++ b/src/main/java/fr/xephi/authme/task/TimeoutTask.java
@@ -4,14 +4,10 @@ import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
-import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
-/**
- */
public class TimeoutTask implements Runnable {
- private final AuthMe plugin;
private final String name;
private final Messages m;
private final Player player;
@@ -25,38 +21,14 @@ public class TimeoutTask implements Runnable {
*/
public TimeoutTask(AuthMe plugin, String name, Player player) {
this.m = plugin.getMessages();
- this.plugin = plugin;
this.name = name;
this.player = player;
}
- /**
- * Method getName.
- *
- * @return String
- */
- public String getName() {
- return name;
- }
-
- /**
- * Method run.
- *
- * @see java.lang.Runnable#run()
- */
@Override
public void run() {
- if (PlayerCache.getInstance().isAuthenticated(name)) {
- return;
+ if (!PlayerCache.getInstance().isAuthenticated(name)) {
+ player.kickPlayer(m.retrieveSingle(MessageKey.LOGIN_TIMEOUT_ERROR));
}
-
- Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
- @Override
- public void run() {
- if (player.isOnline()) {
- player.kickPlayer(m.retrieveSingle(MessageKey.LOGIN_TIMEOUT_ERROR));
- }
- }
- });
}
}
diff --git a/src/main/resources/messages/messages_bg.yml b/src/main/resources/messages/messages_bg.yml
index 4370c00b7..94e32f38f 100644
--- a/src/main/resources/messages/messages_bg.yml
+++ b/src/main/resources/messages/messages_bg.yml
@@ -58,6 +58,7 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключ
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO invalid_session: '&cYour IP has been changed and your session data has expired!'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_br.yml b/src/main/resources/messages/messages_br.yml
index dfaab23dd..246627773 100644
--- a/src/main/resources/messages/messages_br.yml
+++ b/src/main/resources/messages/messages_br.yml
@@ -44,7 +44,7 @@ usage_captcha: '&3Para logar você deve resolver o captcha, por favor use o coma
wrong_captcha: '&cCaptcha inválido, por favor escreva "/captcha THE_CAPTCHA"'
valid_captcha: '&2Código do captcha correto!'
kick_forvip: '&3Um vip entrou no servidor!'
-kick_fullserver: '&4Servidor esta cheio! Para entrar mesmo cheio compre vip no site www.site.com.br'
+kick_fullserver: '&4Servidor esta cheio, tente outra vez mais tarde'
usage_email_add: '&cUse: /email add '
usage_email_change: '&cUse: /email change '
usage_email_recovery: '&cUse: /email recovery '
@@ -56,10 +56,10 @@ email_confirm: '&cPor favor confirme o email!'
email_changed: '&2Email mudado com sucesso!'
email_send: '&2Email de recuperação enviado com sucesso! !'
email_exists: '&cUm email de recuperação já foi enviado! Você pode reenviar outro usando o comando:'
-country_banned: '&4Seu país foi banido do servidor! Your country is banned from this server!'
+country_banned: '&4Seu país foi banido do servidor!'
antibot_auto_enabled: '&4[AntiBotService] AntiBot ativado devido ao grande número de conexões!'
antibot_auto_disabled: '&2[AntiBotService] AntiBot desativado após %m minutos!'
-# TODO two_factor_create: Missing tag %url
-two_factor_create: '&2Seu código secreto é %code'
-# TODO email_already_used: '&4The email address is already being used'
-# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
+two_factor_create: '&2Seu código secreto é %code. Você pode escanear ele daqui %url'
+email_already_used: '&4Este endereço de email já está em uso'
+not_owner_error: 'Você não é o dono desta conta. Por favor, tente outro nome!'
+invalid_name_case: 'Você deve entrar usando %valid, não %invalid.'
diff --git a/src/main/resources/messages/messages_cz.yml b/src/main/resources/messages/messages_cz.yml
index d56a6d423..580a12bc8 100644
--- a/src/main/resources/messages/messages_cz.yml
+++ b/src/main/resources/messages/messages_cz.yml
@@ -58,5 +58,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod automaticky ukoncen po %m minutach,
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_de.yml b/src/main/resources/messages/messages_de.yml
index eb62ce309..942460ac0 100644
--- a/src/main/resources/messages/messages_de.yml
+++ b/src/main/resources/messages/messages_de.yml
@@ -60,4 +60,5 @@ kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du di
# TODO two_factor_create: Missing tag %url
two_factor_create: '&2Dein geheimer Code ist %code'
# TODO email_already_used: '&4The email address is already being used'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_en.yml b/src/main/resources/messages/messages_en.yml
index 0b7c96bfb..64aa90993 100644
--- a/src/main/resources/messages/messages_en.yml
+++ b/src/main/resources/messages/messages_en.yml
@@ -60,3 +60,4 @@ antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m mi
email_already_used: '&4The email address is already being used'
two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
not_owner_error: 'You are not the owner of this account. Please try another name!'
+invalid_name_case: 'You should join using username %valid, not %invalid.'
diff --git a/src/main/resources/messages/messages_es.yml b/src/main/resources/messages/messages_es.yml
index 6fd0dbc19..df415952a 100644
--- a/src/main/resources/messages/messages_es.yml
+++ b/src/main/resources/messages/messages_es.yml
@@ -59,5 +59,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automáticamente luego d
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_eu.yml b/src/main/resources/messages/messages_eu.yml
index bddf751d7..b490aeebf 100644
--- a/src/main/resources/messages/messages_eu.yml
+++ b/src/main/resources/messages/messages_eu.yml
@@ -52,6 +52,7 @@ country_banned: '[AuthMe] Zure herrialdea blokeatuta dago zerbitzari honetan'
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
# TODO invalid_session: '&cYour IP has been changed and your session data has expired!'
# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
diff --git a/src/main/resources/messages/messages_fi.yml b/src/main/resources/messages/messages_fi.yml
index 2e26e512d..80e6cd4fd 100644
--- a/src/main/resources/messages/messages_fi.yml
+++ b/src/main/resources/messages/messages_fi.yml
@@ -55,6 +55,7 @@ email_send: '[AuthMe] Palautus sähköposti lähetetty!'
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO country_banned: '&4Your country is banned from this server!'
# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
diff --git a/src/main/resources/messages/messages_fr.yml b/src/main/resources/messages/messages_fr.yml
index 31a944714..153cceb47 100644
--- a/src/main/resources/messages/messages_fr.yml
+++ b/src/main/resources/messages/messages_fr.yml
@@ -61,4 +61,5 @@ email_exists: '&cUn email de restauration a déjà été envoyé ! Vous pouvez l
# TODO two_factor_create: Missing tag %url
two_factor_create: '&2Votre code secret est %code'
# TODO email_already_used: '&4The email address is already being used'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_gl.yml b/src/main/resources/messages/messages_gl.yml
index 3dfeb88d3..1562e3a31 100644
--- a/src/main/resources/messages/messages_gl.yml
+++ b/src/main/resources/messages/messages_gl.yml
@@ -60,5 +60,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod desactivouse automáticamente despo
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_hu.yml b/src/main/resources/messages/messages_hu.yml
index 504364546..b3f228825 100644
--- a/src/main/resources/messages/messages_hu.yml
+++ b/src/main/resources/messages/messages_hu.yml
@@ -58,5 +58,6 @@ antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt a nagy számú
antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m múlva!'
kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérünk várj pár másodpercet a csatlakozáshoz.'
# TODO email_already_used: '&4The email address is already being used'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_id.yml b/src/main/resources/messages/messages_id.yml
index 528357560..24e6a35b7 100644
--- a/src/main/resources/messages/messages_id.yml
+++ b/src/main/resources/messages/messages_id.yml
@@ -55,6 +55,7 @@ antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak
antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!'
# TODO email_already_used: '&4The email address is already being used'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO country_banned: '&4Your country is banned from this server!'
# TODO usage_unreg: '&cUsage: /unregister '
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
diff --git a/src/main/resources/messages/messages_it.yml b/src/main/resources/messages/messages_it.yml
index abc943fc4..e7c77c898 100644
--- a/src/main/resources/messages/messages_it.yml
+++ b/src/main/resources/messages/messages_it.yml
@@ -60,4 +60,5 @@ antibot_auto_disabled: "Il servizio di AntiBot è stato automaticamente disabili
kick_antibot: 'Il servizio di AntiBot è attualmente attivo! Devi aspettare qualche minuto prima di poter entrare nel server.'
two_factor_create: '&2Il tuo codice segreto è: &f%code&n&2Puoi anche scannerizzare il codice QR da qui: &f%url'
# TODO email_already_used: '&4The email address is already being used'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_ko.yml b/src/main/resources/messages/messages_ko.yml
index 32ad61663..ab1223095 100644
--- a/src/main/resources/messages/messages_ko.yml
+++ b/src/main/resources/messages/messages_ko.yml
@@ -61,5 +61,6 @@ antibot_auto_disabled: '[AuthMe] 봇차단모드가 %m 분 후에 자동적으
# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...'
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_lt.yml b/src/main/resources/messages/messages_lt.yml
index a432b62a9..fce26d1be 100644
--- a/src/main/resources/messages/messages_lt.yml
+++ b/src/main/resources/messages/messages_lt.yml
@@ -46,6 +46,7 @@ kick_fullserver: '&cServeris yra pilnas, Atsiprasome.'
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO new_email_invalid: '&cInvalid new email, try again!'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!'
# TODO usage_email_recovery: '&cUsage: /email recovery '
# TODO email_confirm: '&cPlease confirm your email address!'
diff --git a/src/main/resources/messages/messages_nl.yml b/src/main/resources/messages/messages_nl.yml
index bf662ce7c..a3159e488 100644
--- a/src/main/resources/messages/messages_nl.yml
+++ b/src/main/resources/messages/messages_nl.yml
@@ -59,5 +59,6 @@ kick_antibot: 'AntiBot is aangezet! Wacht alsjeblieft enkele minuten voor je met
two_factor_create: '&2Je geheime code is %code'
# TODO email_already_used: '&4The email address is already being used'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO reg_email_msg: '&3Please, register to the server with the command "/register "'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_pl.yml b/src/main/resources/messages/messages_pl.yml
index 506995bd5..c6cba56f4 100644
--- a/src/main/resources/messages/messages_pl.yml
+++ b/src/main/resources/messages/messages_pl.yml
@@ -55,6 +55,7 @@ email_send: '[AuthMe] Email z odzyskaniem wyslany!'
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO country_banned: '&4Your country is banned from this server!'
# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
diff --git a/src/main/resources/messages/messages_pt.yml b/src/main/resources/messages/messages_pt.yml
index 5b11aea6b..64428a525 100644
--- a/src/main/resources/messages/messages_pt.yml
+++ b/src/main/resources/messages/messages_pt.yml
@@ -59,5 +59,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod desactivado automaticamente após %m
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_ru.yml b/src/main/resources/messages/messages_ru.yml
index 3c34794e9..2b9dd640b 100644
--- a/src/main/resources/messages/messages_ru.yml
+++ b/src/main/resources/messages/messages_ru.yml
@@ -58,5 +58,6 @@ antibot_auto_disabled: '&a[AuthMe] AntiBot-режим автоматичски
# TODO email_already_used: '&4The email address is already being used'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_sk.yml b/src/main/resources/messages/messages_sk.yml
index 1366e2a95..77433f62c 100644
--- a/src/main/resources/messages/messages_sk.yml
+++ b/src/main/resources/messages/messages_sk.yml
@@ -38,28 +38,29 @@ name_len: '&cTvoje meno je velmi krátke alebo dlhé'
regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX'
add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"'
recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery '
-# TODO email_already_used: '&4The email address is already being used'
-# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...'
# TODO usage_email_change: '&cUsage: /email change '
-# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
+# TODO password_error_nick: '&cYou can''t use your name as password, please choose another one...'
+# TODO email_already_used: '&4The email address is already being used'
# TODO new_email_invalid: '&cInvalid new email, try again!'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
-# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!'
-# TODO email_confirm: '&cPlease confirm your email address!'
-# TODO usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "'
-# TODO usage_email_recovery: '&cUsage: /email recovery '
-# TODO email_changed: '&2Email address changed correctly!'
# TODO old_email_invalid: '&cInvalid old email, try again!'
+# TODO email_changed: '&2Email address changed correctly!'
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
-# TODO kick_fullserver: '&4The server is full, try again later!'
-# TODO email_added: '&2Email address successfully added to your account!'
-# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
# TODO country_banned: '&4Your country is banned from this server!'
-# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
-# TODO email_invalid: '&cInvalid email address, try again!'
-# TODO kick_forvip: '&3A VIP player has joined the server when it was full!'
# TODO usage_email_add: '&cUsage: /email add '
# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
# TODO valid_captcha: '&2Captcha code solved correctly!'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
+# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
+# TODO email_send: '&2Recovery email sent successfully! Please check your email inbox!'
+# TODO usage_email_recovery: '&cUsage: /email recovery '
+# TODO usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha "'
+# TODO email_confirm: '&cPlease confirm your email address!'
+# TODO kick_fullserver: '&4The server is full, try again later!'
+# TODO email_added: '&2Email address successfully added to your account!'
+# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO kick_forvip: '&3A VIP player has joined the server when it was full!'
+# TODO email_invalid: '&cInvalid email address, try again!'
+# TODO antibot_auto_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_tr.yml b/src/main/resources/messages/messages_tr.yml
index b3603929a..0e118de04 100644
--- a/src/main/resources/messages/messages_tr.yml
+++ b/src/main/resources/messages/messages_tr.yml
@@ -58,5 +58,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMode %m dakika sonra otomatik olarak isg
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_uk.yml b/src/main/resources/messages/messages_uk.yml
index 6c5db173f..df5710f93 100644
--- a/src/main/resources/messages/messages_uk.yml
+++ b/src/main/resources/messages/messages_uk.yml
@@ -59,5 +59,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично вимкну
# TODO email_already_used: '&4The email address is already being used'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_vn.yml b/src/main/resources/messages/messages_vn.yml
index 2df8588af..262b7b73b 100644
--- a/src/main/resources/messages/messages_vn.yml
+++ b/src/main/resources/messages/messages_vn.yml
@@ -59,5 +59,6 @@ antibot_auto_disabled: '[AuthMe] AntiBot tự huỷ kích hoạt sau %m phút, h
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_zhcn.yml b/src/main/resources/messages/messages_zhcn.yml
index d1f71209b..3c7fa1a23 100644
--- a/src/main/resources/messages/messages_zhcn.yml
+++ b/src/main/resources/messages/messages_zhcn.yml
@@ -63,5 +63,6 @@ antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程序檢查到不
# TODO email_already_used: '&4The email address is already being used'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
# TODO email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_zhhk.yml b/src/main/resources/messages/messages_zhhk.yml
index e18f4109c..2eacb1f62 100644
--- a/src/main/resources/messages/messages_zhhk.yml
+++ b/src/main/resources/messages/messages_zhhk.yml
@@ -63,4 +63,5 @@ email_already_used: '&4邮箱已被使用'
kick_antibot: '[AuthMe] 防机器人程序已启用 !请稍等几分钟後才再次进入服务器'
email_exists: '&c恢复邮件已发送 ! 你可以丢弃它然後使用以下的指令来发送新的邮件:'
two_factor_create: '&2你的代码是 %code,你可以使用 %url 来扫描'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/main/resources/messages/messages_zhtw.yml b/src/main/resources/messages/messages_zhtw.yml
index 61ed5d88a..d31431f4b 100644
--- a/src/main/resources/messages/messages_zhtw.yml
+++ b/src/main/resources/messages/messages_zhtw.yml
@@ -63,5 +63,6 @@ antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!'
antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉'
# TODO email_already_used: '&4The email address is already being used'
# TODO kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
+# TODO invalid_name_case: 'You should join using username %valid, not %invalid.'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
\ No newline at end of file
diff --git a/src/test/java/fr/xephi/authme/TestHelper.java b/src/test/java/fr/xephi/authme/TestHelper.java
index a7a60865f..06ff06a4b 100644
--- a/src/test/java/fr/xephi/authme/TestHelper.java
+++ b/src/test/java/fr/xephi/authme/TestHelper.java
@@ -2,6 +2,8 @@ package fr.xephi.authme;
import java.io.File;
import java.net.URL;
+import java.nio.file.Path;
+import java.nio.file.Paths;
/**
* AuthMe test utilities.
@@ -18,11 +20,31 @@ public final class TestHelper {
* @return The project file
*/
public static File getJarFile(String path) {
+ URL url = getUrlOrThrow(path);
+ return new File(url.getFile());
+ }
+
+ /**
+ * Return a {@link Path} to a file in the JAR's resources (main or test).
+ *
+ * @param path The absolute path to the file
+ * @return The Path object to the file
+ */
+ public static Path getJarPath(String path) {
+ String sqlFilePath = getUrlOrThrow(path).getPath();
+ // Windows preprends the path with a '/' or '\', which Paths cannot handle
+ String appropriatePath = System.getProperty("os.name").contains("indow")
+ ? sqlFilePath.substring(1)
+ : sqlFilePath;
+ return Paths.get(appropriatePath);
+ }
+
+ private static URL getUrlOrThrow(String path) {
URL url = TestHelper.class.getResource(path);
if (url == null) {
throw new IllegalStateException("File '" + path + "' could not be loaded");
}
- return new File(url.getFile());
+ return url;
}
}
diff --git a/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java
new file mode 100644
index 000000000..abe1d5212
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/datasource/AbstractDataSourceIntegrationTest.java
@@ -0,0 +1,295 @@
+package fr.xephi.authme.datasource;
+
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.security.crypts.HashedPassword;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static fr.xephi.authme.datasource.AuthMeMatchers.equalToHash;
+import static fr.xephi.authme.datasource.AuthMeMatchers.hasAuthBasicData;
+import static fr.xephi.authme.datasource.AuthMeMatchers.hasAuthLocation;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assume.assumeThat;
+
+/**
+ * Abstract class for data source integration tests.
+ */
+public abstract class AbstractDataSourceIntegrationTest {
+
+ protected abstract DataSource getDataSource();
+
+ @Test
+ public void shouldReturnIfAuthIsAvailableOrNot() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ boolean isBobbyAvailable = dataSource.isAuthAvailable("bobby");
+ boolean isChrisAvailable = dataSource.isAuthAvailable("chris");
+ boolean isUserAvailable = dataSource.isAuthAvailable("USER");
+
+ // then
+ assertThat(isBobbyAvailable, equalTo(true));
+ assertThat(isChrisAvailable, equalTo(false));
+ assertThat(isUserAvailable, equalTo(true));
+ }
+
+ @Test
+ public void shouldReturnPassword() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ HashedPassword bobbyPassword = dataSource.getPassword("bobby");
+ HashedPassword invalidPassword = dataSource.getPassword("doesNotExist");
+ HashedPassword userPassword = dataSource.getPassword("user");
+
+ // then
+ assertThat(bobbyPassword, equalToHash("$SHA$11aa0706173d7272$dbba966"));
+ assertThat(invalidPassword, nullValue());
+ assertThat(userPassword, equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"));
+ }
+
+ @Test
+ public void shouldGetAuth() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ PlayerAuth invalidAuth = dataSource.getAuth("notInDB");
+ PlayerAuth bobbyAuth = dataSource.getAuth("Bobby");
+ PlayerAuth userAuth = dataSource.getAuth("user");
+
+ // then
+ assertThat(invalidAuth, nullValue());
+
+ assertThat(bobbyAuth, hasAuthBasicData("bobby", "Bobby", "your@email.com", "123.45.67.89"));
+ assertThat(bobbyAuth, hasAuthLocation(1.05, 2.1, 4.2, "world"));
+ assertThat(bobbyAuth.getLastLogin(), equalTo(1449136800L));
+ assertThat(bobbyAuth.getPassword(), equalToHash("$SHA$11aa0706173d7272$dbba966"));
+
+ assertThat(userAuth, hasAuthBasicData("user", "user", "user@example.org", "34.56.78.90"));
+ assertThat(userAuth, hasAuthLocation(124.1, 76.3, -127.8, "nether"));
+ assertThat(userAuth.getLastLogin(), equalTo(1453242857L));
+ assertThat(userAuth.getPassword(), equalToHash("b28c32f624a4eb161d6adc9acb5bfc5b", "f750ba32"));
+ }
+
+ @Test
+ public void shouldFindIfEmailExists() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ boolean isUserMailPresent = dataSource.isEmailStored("user@example.org");
+ boolean isUserMailPresentCaseInsensitive = dataSource.isEmailStored("user@example.ORG");
+ boolean isInvalidMailPresent = dataSource.isEmailStored("not-in-database@example.com");
+
+ // then
+ assertThat(isUserMailPresent, equalTo(true));
+ assertThat(isUserMailPresentCaseInsensitive, equalTo(true));
+ assertThat(isInvalidMailPresent, equalTo(false));
+ }
+
+ @Test
+ public void shouldCountAuthsByEmail() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ int userMailCount = dataSource.countAuthsByEmail("user@example.ORG");
+ int invalidMailCount = dataSource.countAuthsByEmail("not.in.db@example.com");
+ boolean response = dataSource.saveAuth(
+ PlayerAuth.builder().name("Test").email("user@EXAMPLE.org").build());
+ int newUserCount = dataSource.countAuthsByEmail("user@Example.org");
+
+ // then
+ assertThat(userMailCount, equalTo(1));
+ assertThat(invalidMailCount, equalTo(0));
+ assertThat(response, equalTo(true));
+ assertThat(newUserCount, equalTo(2));
+ }
+
+ @Test
+ public void shouldReturnAllAuths() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ List authList = dataSource.getAllAuths();
+ boolean response = dataSource.saveAuth(
+ PlayerAuth.builder().name("Test").email("user@EXAMPLE.org").build());
+ List newAuthList = dataSource.getAllAuths();
+
+ // then
+ assertThat(response, equalTo(true));
+ assertThat(authList, hasSize(2));
+ assertThat(newAuthList, hasSize(3));
+ boolean hasBobby = false;
+ for (PlayerAuth auth : authList) {
+ if (auth.getNickname().equals("bobby")) {
+ hasBobby = true;
+ break;
+ }
+ }
+ assertThat(hasBobby, equalTo(true));
+ }
+
+ @Test
+ public void shouldUpdatePassword() {
+ // given
+ DataSource dataSource = getDataSource();
+ HashedPassword newHash = new HashedPassword("new_hash");
+
+ // when
+ boolean response1 = dataSource.updatePassword("user", newHash);
+ boolean response2 = dataSource.updatePassword("non-existent-name", new HashedPassword("sd"));
+
+ // then
+ assertThat(response1 && response2, equalTo(true));
+ assertThat(dataSource.getPassword("user"), equalToHash(newHash));
+ }
+
+ @Test
+ public void shouldRemovePlayerAuth() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ boolean response1 = dataSource.removeAuth("bobby");
+ boolean response2 = dataSource.removeAuth("does-not-exist");
+
+ // then
+ assertThat(response1 && response2, equalTo(true));
+ assertThat(dataSource.getAuth("bobby"), nullValue());
+ assertThat(dataSource.isAuthAvailable("bobby"), equalTo(false));
+ }
+
+ @Test
+ public void shouldUpdateSession() {
+ // given
+ DataSource dataSource = getDataSource();
+ PlayerAuth bobby = PlayerAuth.builder()
+ .name("bobby").realName("BOBBY").lastLogin(123L)
+ .ip("12.12.12.12").build();
+
+ // when
+ boolean response = dataSource.updateSession(bobby);
+
+ // then
+ assertThat(response, equalTo(true));
+ PlayerAuth result = dataSource.getAuth("bobby");
+ assertThat(result, hasAuthBasicData("bobby", "BOBBY", "your@email.com", "12.12.12.12"));
+ assertThat(result.getLastLogin(), equalTo(123L));
+ }
+
+ @Test
+ public void shouldUpdateLastLoc() {
+ // given
+ DataSource dataSource = getDataSource();
+ PlayerAuth user = PlayerAuth.builder()
+ .name("user").locX(143).locY(-42.12).locZ(29.47)
+ .locWorld("the_end").build();
+
+ // when
+ boolean response = dataSource.updateQuitLoc(user);
+
+ // then
+ assertThat(response, equalTo(true));
+ assertThat(dataSource.getAuth("user"), hasAuthLocation(143, -42.12, 29.47, "the_end"));
+ }
+
+ @Test
+ public void shouldDeletePlayers() {
+ // given
+ DataSource dataSource = getDataSource();
+ List playersToDelete = Arrays.asList("bobby", "doesNotExist");
+ assumeThat(dataSource.getAccountsRegistered(), equalTo(2));
+
+ // when
+ dataSource.purgeBanned(playersToDelete);
+
+ // then
+ assertThat(dataSource.getAccountsRegistered(), equalTo(1));
+ assertThat(dataSource.isAuthAvailable("bobby"), equalTo(false));
+ assertThat(dataSource.isAuthAvailable("user"), equalTo(true));
+ }
+
+ @Test
+ public void shouldUpdateEmail() {
+ // given
+ DataSource dataSource = getDataSource();
+ String email = "new-user@mail.tld";
+ PlayerAuth userAuth = PlayerAuth.builder().name("user").email(email).build();
+ PlayerAuth invalidAuth = PlayerAuth.builder().name("invalid").email("addr@example.com").build();
+
+ // when
+ boolean response1 = dataSource.updateEmail(userAuth);
+ boolean response2 = dataSource.updateEmail(invalidAuth);
+
+ // then
+ assertThat(response1 && response2, equalTo(true));
+ assertThat(dataSource.getAllAuths(), hasItem(hasAuthBasicData("user", "user", email, "34.56.78.90")));
+ }
+
+ @Test
+ public void shouldUpdateIp() {
+ // given
+ DataSource dataSource = getDataSource();
+ String ip = "250.230.67.73";
+
+ // when
+ boolean response1 = dataSource.updateIp("bobby", ip);
+ boolean response2 = dataSource.updateIp("bogus", "123.123.123.123");
+
+
+ // then
+ assertThat(response1 && response2, equalTo(true));
+ assertThat(dataSource.getAllAuths(), hasItem(hasAuthBasicData("bobby", "Bobby", "your@email.com", ip)));
+ }
+
+ @Test
+ public void shouldCountAuths() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ int initialCount = dataSource.getAccountsRegistered();
+ for (int i = 0; i < 4; ++i) {
+ dataSource.saveAuth(PlayerAuth.builder().name("test-" + i).build());
+ }
+ int endCount = dataSource.getAccountsRegistered();
+
+ // then
+ assertThat(initialCount, equalTo(2));
+ assertThat(endCount, equalTo(6));
+ }
+
+ @Test
+ public void shouldGetAllUsersByIp() {
+ // given
+ DataSource dataSource = getDataSource();
+
+ // when
+ List initialList = dataSource.getAllAuthsByIp("123.45.67.89");
+ List emptyList = dataSource.getAllAuthsByIp("8.8.8.8");
+ for (int i = 0; i < 3; ++i) {
+ dataSource.saveAuth(PlayerAuth.builder().name("test-" + i).ip("123.45.67.89").build());
+ }
+ List updatedList = dataSource.getAllAuthsByIp("123.45.67.89");
+
+ // then
+ assertThat(initialList, hasSize(1));
+ assertThat(initialList.get(0), equalTo("bobby"));
+ assertThat(emptyList, hasSize(0));
+ assertThat(updatedList, hasSize(4));
+ assertThat(updatedList, hasItem(equalTo("bobby")));
+ assertThat(updatedList, hasItem(equalTo("test-1")));
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java b/src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
new file mode 100644
index 000000000..798d5315b
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
@@ -0,0 +1,84 @@
+package fr.xephi.authme.datasource;
+
+import fr.xephi.authme.cache.auth.PlayerAuth;
+import fr.xephi.authme.security.crypts.HashedPassword;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.TypeSafeMatcher;
+
+import java.util.Objects;
+
+/**
+ * Custom matchers for AuthMe entities.
+ */
+public final class AuthMeMatchers {
+
+ private AuthMeMatchers() {
+ }
+
+ public static Matcher super HashedPassword> equalToHash(final String hash) {
+ return equalToHash(new HashedPassword(hash));
+ }
+
+ public static Matcher super HashedPassword> equalToHash(final String hash, final String salt) {
+ return equalToHash(new HashedPassword(hash, salt));
+ }
+
+ public static Matcher super HashedPassword> equalToHash(final HashedPassword hash) {
+ return new TypeSafeMatcher() {
+ @Override
+ public boolean matchesSafely(HashedPassword item) {
+ return Objects.equals(hash.getHash(), item.getHash())
+ && Objects.equals(hash.getSalt(), item.getSalt());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ String representation = "'" + hash.getHash() + "'";
+ if (hash.getSalt() != null) {
+ representation += ", '" + hash.getSalt() + "'";
+ }
+ description.appendValue("HashedPassword(" + representation + ")");
+ }
+ };
+ }
+
+ public static Matcher super PlayerAuth> hasAuthBasicData(final String name, final String realName,
+ final String email, final String ip) {
+ return new TypeSafeMatcher() {
+ @Override
+ public boolean matchesSafely(PlayerAuth item) {
+ return Objects.equals(name, item.getNickname())
+ && Objects.equals(realName, item.getRealName())
+ && Objects.equals(email, item.getEmail())
+ && Objects.equals(ip, item.getIp());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendValue(String.format("PlayerAuth with name %s, realname %s, email %s, ip %s",
+ name, realName, email, ip));
+ }
+ };
+ }
+
+ public static Matcher super PlayerAuth> hasAuthLocation(final double x, final double y, final double z,
+ final String world) {
+ return new TypeSafeMatcher() {
+ @Override
+ public boolean matchesSafely(PlayerAuth item) {
+ return Objects.equals(x, item.getQuitLocX())
+ && Objects.equals(y, item.getQuitLocY())
+ && Objects.equals(z, item.getQuitLocZ())
+ && Objects.equals(world, item.getWorld());
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendValue(String.format("PlayerAuth with quit location (x: %f, y: %f, z: %f, world: %s)",
+ x, y, z, world));
+ }
+ };
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java
new file mode 100644
index 000000000..586ca0ad1
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/datasource/MySqlIntegrationTest.java
@@ -0,0 +1,96 @@
+package fr.xephi.authme.datasource;
+
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import fr.xephi.authme.ConsoleLoggerTestInitializer;
+import fr.xephi.authme.TestHelper;
+import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.domain.Property;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Integration test for {@link MySQL}.
+ */
+public class MySqlIntegrationTest extends AbstractDataSourceIntegrationTest {
+
+ /** Mock of a settings instance. */
+ private static NewSetting settings;
+ /** SQL statement to execute before running a test. */
+ private static String sqlInitialize;
+ /** Connection to the H2 test database. */
+ private HikariDataSource hikariSource;
+
+ /**
+ * Set up the settings mock to return specific values for database settings and load {@link #sqlInitialize}.
+ */
+ @BeforeClass
+ public static void initializeSettings() throws IOException, ClassNotFoundException {
+ // Check that we have an H2 driver
+ Class.forName("org.h2.jdbcx.JdbcDataSource");
+
+ settings = mock(NewSetting.class);
+ when(settings.getProperty(any(Property.class))).thenAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ return ((Property) invocation.getArguments()[0]).getDefaultValue();
+ }
+ });
+ set(DatabaseSettings.MYSQL_DATABASE, "h2_test");
+ set(DatabaseSettings.MYSQL_TABLE, "authme");
+ set(DatabaseSettings.MYSQL_COL_SALT, "salt");
+ ConsoleLoggerTestInitializer.setupLogger();
+
+ Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql");
+ sqlInitialize = new String(Files.readAllBytes(sqlInitFile));
+ }
+
+ @Before
+ public void initializeConnectionAndTable() throws SQLException {
+ silentClose(hikariSource);
+ HikariConfig config = new HikariConfig();
+ config.setDataSourceClassName("org.h2.jdbcx.JdbcDataSource");
+ config.setConnectionTestQuery("VALUES 1");
+ config.addDataSourceProperty("URL", "jdbc:h2:mem:test");
+ config.addDataSourceProperty("user", "sa");
+ config.addDataSourceProperty("password", "sa");
+ HikariDataSource ds = new HikariDataSource(config);
+ Connection connection = ds.getConnection();
+
+ try (Statement st = connection.createStatement()) {
+ st.execute("DROP TABLE IF EXISTS authme");
+ st.execute(sqlInitialize);
+ }
+ hikariSource = ds;
+ }
+
+ @Override
+ protected DataSource getDataSource() {
+ return new MySQL(settings, hikariSource);
+ }
+
+ private static void set(Property property, T value) {
+ when(settings.getProperty(property)).thenReturn(value);
+ }
+
+ private static void silentClose(HikariDataSource con) {
+ if (con != null && !con.isClosed()) {
+ con.close();
+ }
+ }
+
+}
diff --git a/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java
new file mode 100644
index 000000000..715d2ce9b
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/datasource/SQLiteIntegrationTest.java
@@ -0,0 +1,96 @@
+package fr.xephi.authme.datasource;
+
+import fr.xephi.authme.ConsoleLoggerTestInitializer;
+import fr.xephi.authme.TestHelper;
+import fr.xephi.authme.settings.NewSetting;
+import fr.xephi.authme.settings.domain.Property;
+import fr.xephi.authme.settings.properties.DatabaseSettings;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import static org.mockito.Matchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+/**
+ * Integration test for {@link SQLite}.
+ */
+public class SQLiteIntegrationTest extends AbstractDataSourceIntegrationTest {
+
+ /** Mock of a settings instance. */
+ private static NewSetting settings;
+ /** Collection of SQL statements to execute for initialization of a test. */
+ private static String[] sqlInitialize;
+ /** Connection to the SQLite test database. */
+ private Connection con;
+
+ /**
+ * Set up the settings mock to return specific values for database settings and load {@link #sqlInitialize}.
+ */
+ @BeforeClass
+ public static void initializeSettings() throws IOException, ClassNotFoundException {
+ // Check that we have an implementation for SQLite
+ Class.forName("org.sqlite.JDBC");
+
+ settings = mock(NewSetting.class);
+ when(settings.getProperty(any(Property.class))).thenAnswer(new Answer() {
+ @Override
+ public Object answer(InvocationOnMock invocation) throws Throwable {
+ return ((Property) invocation.getArguments()[0]).getDefaultValue();
+ }
+ });
+ set(DatabaseSettings.MYSQL_DATABASE, "sqlite-test");
+ set(DatabaseSettings.MYSQL_TABLE, "authme");
+ set(DatabaseSettings.MYSQL_COL_SALT, "salt");
+ ConsoleLoggerTestInitializer.setupLogger();
+
+ Path sqlInitFile = TestHelper.getJarPath("/datasource-integration/sql-initialize.sql");
+ // Note ljacqu 20160221: It appears that we can only run one statement per Statement.execute() so we split
+ // the SQL file by ";\n" as to get the individual statements
+ sqlInitialize = new String(Files.readAllBytes(sqlInitFile)).split(";(\\r?)\\n");
+ }
+
+ @Before
+ public void initializeConnectionAndTable() throws SQLException {
+ silentClose(con);
+ Connection connection = DriverManager.getConnection("jdbc:sqlite::memory:");
+ try (Statement st = connection.createStatement()) {
+ st.execute("DROP TABLE IF EXISTS authme");
+ for (String statement : sqlInitialize) {
+ st.execute(statement);
+ }
+ }
+ con = connection;
+ }
+
+ @Override
+ protected DataSource getDataSource() {
+ return new SQLite(settings, con);
+ }
+
+ private static void set(Property property, T value) {
+ when(settings.getProperty(property)).thenReturn(value);
+ }
+
+ private static void silentClose(Connection con) {
+ if (con != null) {
+ try {
+ if (!con.isClosed()) {
+ con.close();
+ }
+ } catch (SQLException e) {
+ // silent
+ }
+ }
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
index 5ff79b9dd..399553657 100644
--- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
+++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
@@ -266,4 +266,16 @@ public class MessagesIntegrationTest {
assertThat(messages.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE),
equalTo("Message from default file"));
}
+
+ @Test
+ public void shouldRetrieveMessageWithReplacements() {
+ // given
+ MessageKey key = MessageKey.CAPTCHA_WRONG_ERROR;
+
+ // when
+ String result = messages.retrieveSingle(key, "24680");
+
+ // then
+ assertThat(result, equalTo("Use /captcha 24680 to solve the captcha"));
+ }
}
diff --git a/src/test/resources/datasource-integration/sql-initialize.sql b/src/test/resources/datasource-integration/sql-initialize.sql
new file mode 100644
index 000000000..5dea47d51
--- /dev/null
+++ b/src/test/resources/datasource-integration/sql-initialize.sql
@@ -0,0 +1,22 @@
+-- Important: separate SQL statements by ; followed directly by a newline. We split the file contents by ";\n"
+
+CREATE TABLE authme (
+ id INTEGER AUTO_INCREMENT,
+ username VARCHAR(255) NOT NULL UNIQUE,
+ password VARCHAR(255) NOT NULL,
+ ip VARCHAR(40) NOT NULL,
+ lastlogin BIGINT,
+ x DOUBLE NOT NULL DEFAULT '0.0',
+ y DOUBLE NOT NULL DEFAULT '0.0',
+ z DOUBLE NOT NULL DEFAULT '0.0',
+ world VARCHAR(255) NOT NULL DEFAULT 'world',
+ email VARCHAR(255) DEFAULT 'your@email.com',
+ isLogged INT DEFAULT '0', realname VARCHAR(255) NOT NULL DEFAULT 'Player',
+ salt varchar(255),
+ CONSTRAINT table_const_prim PRIMARY KEY (id)
+);
+
+INSERT INTO authme (id, username, password, ip, lastlogin, x, y, z, world, email, isLogged, realname, salt)
+VALUES (1,'bobby','$SHA$11aa0706173d7272$dbba966','123.45.67.89',1449136800,1.05,2.1,4.2,'world','your@email.com',0,'Bobby',NULL);
+INSERT INTO authme (id, username, password, ip, lastlogin, x, y, z, world, email, isLogged, realname, salt)
+VALUES (NULL,'user','b28c32f624a4eb161d6adc9acb5bfc5b','34.56.78.90',1453242857,124.1,76.3,-127.8,'nether','user@example.org',0,'user','f750ba32');