Merge pull request #564 from AuthMe-Team/master

DB Hotfix
This commit is contained in:
Gabriele C 2016-02-27 01:14:57 +01:00
commit 0e6d0c6d25
68 changed files with 1321 additions and 871 deletions

View File

@ -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)
<hr>

33
pom.xml
View File

@ -61,7 +61,7 @@
<javaVersion>1.7</javaVersion>
<!-- Change Bukkit Version HERE! -->
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
<bukkitVersion>1.9-pre1-SNAPSHOT</bukkitVersion>
</properties>
<profiles>
@ -305,10 +305,10 @@
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<!-- EssentialsX Repo -->
<!-- Essentials Repo -->
<repository>
<id>ess-repo</id>
<url>http://ci.drtshock.net/plugin/repository/everything</url>
<url>http://repo.ess3.net/content/groups/essentials</url>
</repository>
<!-- CombatTagPlus Repo -->
@ -376,6 +376,19 @@
<scope>compile</scope>
<optional>true</optional>
</dependency>
<!-- JDBC drivers for datasource integration tests -->
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.8.11.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.4.191</version>
<scope>test</scope>
</dependency>
<!-- Log4J Logger (required by the console filter) -->
<dependency>
@ -651,16 +664,20 @@
<optional>true</optional>
</dependency>
<!-- EssentialsX plugin, http://www.spigotmc.org/resources/essentialsx.9089/ -->
<!-- Essentials plugin -->
<dependency>
<groupId>net.ess3</groupId>
<artifactId>EssentialsX</artifactId>
<version>2.0.1-SNAPSHOT</version>
<artifactId>Essentials</artifactId>
<version>2.13-SNAPSHOT</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
</exclusion>
<exclusion>
<groupId>org.bukkit</groupId>
<artifactId>craftbukkit</artifactId>
</exclusion>
</exclusions>
<optional>true</optional>

View File

@ -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<String, BukkitTask> sessions = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, Integer> captcha = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, String> cap = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, String> 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<String, BukkitTask> sessions = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, Integer> captcha = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, String> cap = new ConcurrentHashMap<>();
public final ConcurrentHashMap<String, String> 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<Integer> 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--;
}
// Close the database
progress++;
ConsoleLogger.info("Progress: " + progress + " / " + pendingTasks.size());
}
if (database != null) {
database.close();
}
}
}, "AuthMe-DataSource#close").start();
// Close the database
// 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() {

View File

@ -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,7 +118,7 @@ public class PlayerAuth {
* @param email String
* @param realName String
*/
public PlayerAuth(String nickname, HashedPassword password, int groupId, String ip, long lastLogin,
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;

View File

@ -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;
}
}

View File

@ -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<DataFileCache> {
/**
* 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<PlayerData> {
@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<DataFileCache> {
/**
* Method serialize.
*
* @param dataFileCache DataFileCache
* @param type Type
* @param jsonSerializationContext JsonSerializationContext
*
* @return JsonElement
*/
private class PlayerDataSerializer implements JsonSerializer<PlayerData> {
@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;
}
}

View File

@ -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;
}
}

View File

@ -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<String, LimboPlayer> 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);
}
}
/**

View File

@ -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) {

View File

@ -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

View File

@ -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);
}

View File

@ -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<String, Optional<PlayerAuth>> cachedAuths;
private final ListeningExecutorService executorService;
/**
* Constructor for CacheDataSource.
@ -27,26 +33,36 @@ 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<String, Optional<PlayerAuth>>() {
@Override
public void onRemoval(RemovalNotification<String, Optional<PlayerAuth>> removalNotification) {
String name = removalNotification.getKey();
if (PlayerCache.getInstance().isAuthenticated(name)) {
cachedAuths.getUnchecked(name);
}
}
})
.build(
new CacheLoader<String, Optional<PlayerAuth>>() {
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<String, Optional<PlayerAuth>>() {
@Override
public Optional<PlayerAuth> load(String key) {
return Optional.fromNullable(source.getAuth(key));
}
@Override
public ListenableFuture<Optional<PlayerAuth>> reload(final String key, Optional<PlayerAuth> oldValue) {
return executorService.submit(new Callable<Optional<PlayerAuth>>() {
@Override
public Optional<PlayerAuth> call() {
return load(key);
}
});
}
});
}
public LoadingCache<String, Optional<PlayerAuth>> getCachedAuths() {
return cachedAuths;
}
@Override
public synchronized boolean isAuthAvailable(String user) {
@ -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<String> 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);

View File

@ -101,12 +101,12 @@ public interface DataSource {
List<String> 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<String> 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);

View File

@ -487,25 +487,21 @@ public class FlatFile implements DataSource {
}
@Override
public List<String> getAllAuthsByEmail(String email) {
public int countAuthsByEmail(String email) {
BufferedReader br = null;
List<String> 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;

View File

@ -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);
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);
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);
PlayerAuth auth;
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, user.toLowerCase());
ResultSet rs = pst.executeQuery();
int id;
try (ResultSet rs = pst.executeQuery()) {
if (!rs.next()) {
return null;
}
int id = rs.getInt(col.ID);
pAuth = buildAuthFromResultSet(rs);
rs.close();
pst.close();
id = rs.getInt(col.ID);
auth = buildAuthFromResultSet(rs);
}
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;");
pst.setInt(1, id);
rs = pst.executeQuery();
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());
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
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<String> autoPurgeDatabase(long until) {
List<String> 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();
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);
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);
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<String> getAllAuthsByIp(String ip) {
List<String> result = new ArrayList<>();
try (Connection con = getConnection()) {
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
PreparedStatement pst = con.prepareStatement(sql);
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
ResultSet rs = pst.executeQuery();
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<String> getAllAuthsByEmail(String email) {
List<String> 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<String> 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);
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);
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);
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);
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()) {
String sql = "SELECT COUNT(*) FROM " + tableName;
try (Connection con = getConnection();
Statement st = con.createStatement();
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM " + tableName);
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);
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);
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
pst.setString(1, ip);
pst.setString(2, user);
pst.executeUpdate();
@ -867,10 +853,10 @@ 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) {
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();
@ -881,9 +867,9 @@ public class MySQL implements DataSource {
}
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();
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);
}
}
}
}

View File

@ -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,6 +350,7 @@ public class SQLite implements DataSource {
@Override
public synchronized void close() {
try {
if (con != null && !con.isClosed())
con.close();
} catch (SQLException ex) {
logSqlException(ex);
@ -394,25 +404,19 @@ public class SQLite implements DataSource {
}
@Override
public List<String> getAllAuthsByEmail(String email) {
PreparedStatement pst = null;
ResultSet rs = null;
List<String> 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 + "=?;";

View File

@ -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")) {

View File

@ -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!");
}
}

View File

@ -6,7 +6,6 @@ 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;
@ -18,17 +17,13 @@ public class AuthMeTabCompletePacketAdapter extends PacketAdapter {
}
@Override
public void onPacketReceiving(PacketEvent event)
{
public void onPacketReceiving(PacketEvent event) {
if (event.getPacketType() == PacketType.Play.Client.TAB_COMPLETE) {
try
{
try {
if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
event.setCancelled(true);
}
}
catch (FieldAccessException e)
{
} catch (FieldAccessException e) {
ConsoleLogger.showError("Couldn't access field.");
}
}

View File

@ -6,7 +6,6 @@ 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;
@ -18,17 +17,13 @@ public class AuthMeTablistPacketAdapter extends PacketAdapter {
}
@Override
public void onPacketSending(PacketEvent event)
{
public void onPacketSending(PacketEvent event) {
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
try
{
try {
if (!PlayerCache.getInstance().isAuthenticated(event.getPlayer().getName().toLowerCase())) {
event.setCancelled(true);
}
}
catch (FieldAccessException e)
{
} catch (FieldAccessException e) {
ConsoleLogger.showError("Couldn't access field.");
}
}

View File

@ -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;

View File

@ -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.
*

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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");
}

View File

@ -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,11 +89,14 @@ 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);
plugin.sessions.remove(name);
}

View File

@ -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;
}

View File

@ -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);
if (limbo != null) {
if (time != 0) {
BukkitTask id = sched.runTaskLater(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));
BukkitTask nwMsg = sched.runTask(plugin, new MessageTask(plugin, name, m.retrieve(MessageKey.LOGIN_MESSAGE), msgInterval));
limbo.setMessageTaskId(nwMsg);
}

View File

@ -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;
/**
*/
@ -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();

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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);

View File

@ -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,36 +43,10 @@ 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 {
if (location == null || location.getWorld() == null) {
return false;
}
set("spawn.world", location.getWorld().getName());
set("spawn.x", location.getX());
set("spawn.y", location.getY());
@ -71,20 +55,12 @@ public class Spawn extends CustomConfiguration {
set("spawn.pitch", location.getPitch());
save();
return true;
} catch (NullPointerException npe) {
return false;
}
}
/**
* Method setFirstSpawn.
*
* @param location Location
*
* @return boolean
*/
public boolean setFirstSpawn(Location location) {
try {
if (location == null || location.getWorld() == null) {
return false;
}
set("firstspawn.world", location.getWorld().getName());
set("firstspawn.x", location.getX());
set("firstspawn.y", location.getY());
@ -93,51 +69,80 @@ public class Spawn extends CustomConfiguration {
set("firstspawn.pitch", location.getPitch());
save();
return true;
} catch (NullPointerException npe) {
return false;
}
}
/**
* 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
}
}

View File

@ -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;
}

View File

@ -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;
}
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
if (player.isOnline()) {
if (!PlayerCache.getInstance().isAuthenticated(name)) {
player.kickPlayer(m.retrieveSingle(MessageKey.LOGIN_TIMEOUT_ERROR));
}
}
});
}
}

View File

@ -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!'

View File

@ -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 <email> <email>'
usage_email_change: '&cUse: /email change <email antigo> <email novo>'
usage_email_recovery: '&cUse: /email recovery <email>'
@ -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!'
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.'

View File

@ -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!'

View File

@ -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!'

View File

@ -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.'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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 <password>'
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'

View File

@ -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!'

View File

@ -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!'

View File

@ -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 <Email>'
# TODO email_confirm: '&cPlease confirm your email address!'

View File

@ -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 <email> <confirmEmail>"'
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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 <tvojEmail>'
# 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 <oldEmail> <newEmail>'
# 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 <theCaptcha>"'
# TODO usage_email_recovery: '&cUsage: /email recovery <Email>'
# 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 <email> <confirmEmail>'
# 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 <Email>'
# TODO usage_captcha: '&3To login you have to solve a captcha code, please use the command "/captcha <theCaptcha>"'
# 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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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!'

View File

@ -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;
}
}

View File

@ -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<PlayerAuth> authList = dataSource.getAllAuths();
boolean response = dataSource.saveAuth(
PlayerAuth.builder().name("Test").email("user@EXAMPLE.org").build());
List<PlayerAuth> 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<String> 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<String> initialList = dataSource.getAllAuthsByIp("123.45.67.89");
List<String> 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<String> 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")));
}
}

View File

@ -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<HashedPassword>() {
@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<PlayerAuth>() {
@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<PlayerAuth>() {
@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));
}
};
}
}

View File

@ -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 <T> void set(Property<T> property, T value) {
when(settings.getProperty(property)).thenReturn(value);
}
private static void silentClose(HikariDataSource con) {
if (con != null && !con.isClosed()) {
con.close();
}
}
}

View File

@ -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 <T> void set(Property<T> 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
}
}
}
}

View File

@ -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"));
}
}

View File

@ -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');