mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-03 01:00:18 +01:00
Merge branch 'master' into db-improve
Conflicts: src/main/java/fr/xephi/authme/AuthMe.java
This commit is contained in:
commit
8324decfa1
@ -50,7 +50,7 @@ McStats: http://mcstats.org/plugin/AuthMe
|
|||||||
|
|
||||||
#####Running Requirements:
|
#####Running Requirements:
|
||||||
>- Java 1.7 (should work also with Java 1.8)
|
>- 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)
|
>- ProtocolLib (optional, required by the protectInventory feature)
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
15
pom.xml
15
pom.xml
@ -61,7 +61,7 @@
|
|||||||
<javaVersion>1.7</javaVersion>
|
<javaVersion>1.7</javaVersion>
|
||||||
|
|
||||||
<!-- Change Bukkit Version HERE! -->
|
<!-- Change Bukkit Version HERE! -->
|
||||||
<bukkitVersion>1.8.8-R0.1-SNAPSHOT</bukkitVersion>
|
<bukkitVersion>1.9-pre1-SNAPSHOT</bukkitVersion>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<profiles>
|
<profiles>
|
||||||
@ -376,6 +376,19 @@
|
|||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</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) -->
|
<!-- Log4J Logger (required by the console filter) -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -17,7 +17,6 @@ import fr.xephi.authme.command.CommandInitializer;
|
|||||||
import fr.xephi.authme.command.CommandMapper;
|
import fr.xephi.authme.command.CommandMapper;
|
||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.help.HelpProvider;
|
import fr.xephi.authme.command.help.HelpProvider;
|
||||||
import fr.xephi.authme.converter.ForceFlatToSqlite;
|
|
||||||
import fr.xephi.authme.datasource.CacheDataSource;
|
import fr.xephi.authme.datasource.CacheDataSource;
|
||||||
import fr.xephi.authme.datasource.DataSource;
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
import fr.xephi.authme.datasource.DataSourceType;
|
import fr.xephi.authme.datasource.DataSourceType;
|
||||||
@ -43,9 +42,8 @@ import fr.xephi.authme.output.Messages;
|
|||||||
import fr.xephi.authme.permission.PermissionsManager;
|
import fr.xephi.authme.permission.PermissionsManager;
|
||||||
import fr.xephi.authme.permission.PlayerStatePermission;
|
import fr.xephi.authme.permission.PlayerStatePermission;
|
||||||
import fr.xephi.authme.process.Management;
|
import fr.xephi.authme.process.Management;
|
||||||
import fr.xephi.authme.security.HashAlgorithm;
|
|
||||||
import fr.xephi.authme.security.PasswordSecurity;
|
import fr.xephi.authme.security.PasswordSecurity;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
import fr.xephi.authme.security.crypts.SHA256;
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.NewSetting;
|
||||||
import fr.xephi.authme.settings.OtherAccounts;
|
import fr.xephi.authme.settings.OtherAccounts;
|
||||||
import fr.xephi.authme.settings.Settings;
|
import fr.xephi.authme.settings.Settings;
|
||||||
@ -58,9 +56,9 @@ import fr.xephi.authme.settings.properties.RestrictionSettings;
|
|||||||
import fr.xephi.authme.settings.properties.SecuritySettings;
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
import fr.xephi.authme.util.CollectionUtils;
|
import fr.xephi.authme.util.CollectionUtils;
|
||||||
import fr.xephi.authme.util.GeoLiteAPI;
|
import fr.xephi.authme.util.GeoLiteAPI;
|
||||||
|
import fr.xephi.authme.util.MigrationService;
|
||||||
import fr.xephi.authme.util.StringUtils;
|
import fr.xephi.authme.util.StringUtils;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.Utils;
|
||||||
import fr.xephi.authme.util.Wrapper;
|
|
||||||
import net.minelink.ctplus.CombatTagPlus;
|
import net.minelink.ctplus.CombatTagPlus;
|
||||||
import org.apache.logging.log4j.LogManager;
|
import org.apache.logging.log4j.LogManager;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
@ -77,6 +75,7 @@ import org.bukkit.scheduler.BukkitTask;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.sql.SQLException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@ -106,27 +105,23 @@ public class AuthMe extends JavaPlugin {
|
|||||||
// Private Instances
|
// Private Instances
|
||||||
private static AuthMe plugin;
|
private static AuthMe plugin;
|
||||||
private static Server server;
|
private static Server server;
|
||||||
private static Wrapper wrapper = Wrapper.getInstance();
|
/*
|
||||||
private Management management;
|
* Maps and stuff
|
||||||
private CommandHandler commandHandler = null;
|
* TODO: Clean up and Move into a manager
|
||||||
private PermissionsManager permsMan = null;
|
*/
|
||||||
private NewSetting newSettings;
|
public final ConcurrentHashMap<String, BukkitTask> sessions = new ConcurrentHashMap<>();
|
||||||
private Messages messages;
|
public final ConcurrentHashMap<String, Integer> captcha = new ConcurrentHashMap<>();
|
||||||
private JsonCache playerBackup;
|
public final ConcurrentHashMap<String, String> cap = new ConcurrentHashMap<>();
|
||||||
private PasswordSecurity passwordSecurity;
|
public final ConcurrentHashMap<String, String> realIp = new ConcurrentHashMap<>();
|
||||||
private DataSource database;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Public Instances
|
* Public Instances
|
||||||
* TODO: Encapsulation
|
* TODO #432: Encapsulation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public NewAPI api;
|
public NewAPI api;
|
||||||
public SendMailSSL mail;
|
public SendMailSSL mail;
|
||||||
public DataManager dataManager;
|
public DataManager dataManager;
|
||||||
public OtherAccounts otherAccounts;
|
public OtherAccounts otherAccounts;
|
||||||
public Location essentialsSpawn;
|
public Location essentialsSpawn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Plugin Hooks
|
* Plugin Hooks
|
||||||
* TODO: Move into modules
|
* TODO: Move into modules
|
||||||
@ -137,15 +132,14 @@ public class AuthMe extends JavaPlugin {
|
|||||||
public AuthMeInventoryPacketAdapter inventoryProtector;
|
public AuthMeInventoryPacketAdapter inventoryProtector;
|
||||||
public AuthMeTabCompletePacketAdapter tabComplete;
|
public AuthMeTabCompletePacketAdapter tabComplete;
|
||||||
public AuthMeTablistPacketAdapter tablistHider;
|
public AuthMeTablistPacketAdapter tablistHider;
|
||||||
|
private Management management;
|
||||||
/*
|
private CommandHandler commandHandler = null;
|
||||||
* Maps and stuff
|
private PermissionsManager permsMan = null;
|
||||||
* TODO: Clean up and Move into a manager
|
private NewSetting newSettings;
|
||||||
*/
|
private Messages messages;
|
||||||
public final ConcurrentHashMap<String, BukkitTask> sessions = new ConcurrentHashMap<>();
|
private JsonCache playerBackup;
|
||||||
public final ConcurrentHashMap<String, Integer> captcha = new ConcurrentHashMap<>();
|
private PasswordSecurity passwordSecurity;
|
||||||
public final ConcurrentHashMap<String, String> cap = new ConcurrentHashMap<>();
|
private DataSource database;
|
||||||
public final ConcurrentHashMap<String, String> realIp = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the plugin's instance.
|
* Get the plugin's instance.
|
||||||
@ -247,7 +241,7 @@ public class AuthMe extends JavaPlugin {
|
|||||||
|
|
||||||
// Connect to the database and setup tables
|
// Connect to the database and setup tables
|
||||||
try {
|
try {
|
||||||
setupDatabase();
|
setupDatabase(newSettings);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
ConsoleLogger.logException("Fatal error occurred during database connection! "
|
ConsoleLogger.logException("Fatal error occurred during database connection! "
|
||||||
+ "Authme initialization aborted!", e);
|
+ "Authme initialization aborted!", e);
|
||||||
@ -255,6 +249,7 @@ public class AuthMe extends JavaPlugin {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MigrationService.changePlainTextToSha256(newSettings, database, new SHA256());
|
||||||
passwordSecurity = new PasswordSecurity(getDataSource(), newSettings.getProperty(SecuritySettings.PASSWORD_HASH),
|
passwordSecurity = new PasswordSecurity(getDataSource(), newSettings.getProperty(SecuritySettings.PASSWORD_HASH),
|
||||||
Bukkit.getPluginManager(), newSettings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH));
|
Bukkit.getPluginManager(), newSettings.getProperty(SecuritySettings.SUPPORT_OLD_PASSWORD_HASH));
|
||||||
|
|
||||||
@ -547,25 +542,42 @@ public class AuthMe extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setupDatabase() throws Exception {
|
/**
|
||||||
if (database != null)
|
* Sets up the data source.
|
||||||
database.close();
|
*
|
||||||
// Backend MYSQL - FILE - SQLITE - SQLITEHIKARI
|
* @param settings The settings instance
|
||||||
boolean isSQLite = false;
|
* @see AuthMe#database
|
||||||
switch (newSettings.getProperty(DatabaseSettings.BACKEND)) {
|
*/
|
||||||
case FILE:
|
public void setupDatabase(NewSetting settings) throws ClassNotFoundException, SQLException {
|
||||||
database = new FlatFile();
|
if (this.database != null) {
|
||||||
break;
|
this.database.close();
|
||||||
case MYSQL:
|
|
||||||
database = new MySQL(newSettings);
|
|
||||||
break;
|
|
||||||
case SQLITE:
|
|
||||||
database = new SQLite(newSettings);
|
|
||||||
isSQLite = true;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isSQLite) {
|
DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
|
||||||
|
DataSource dataSource;
|
||||||
|
switch (dataSourceType) {
|
||||||
|
case FILE:
|
||||||
|
dataSource = new FlatFile();
|
||||||
|
break;
|
||||||
|
case MYSQL:
|
||||||
|
dataSource = new MySQL(settings);
|
||||||
|
break;
|
||||||
|
case SQLITE:
|
||||||
|
dataSource = new SQLite(settings);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new UnsupportedOperationException("Unknown data source type '" + dataSourceType + "'");
|
||||||
|
}
|
||||||
|
|
||||||
|
DataSource convertedSource = MigrationService.convertFlatfileToSqlite(newSettings, dataSource);
|
||||||
|
dataSource = convertedSource == null ? dataSource : convertedSource;
|
||||||
|
|
||||||
|
if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) {
|
||||||
|
dataSource = new CacheDataSource(dataSource);
|
||||||
|
}
|
||||||
|
|
||||||
|
database = dataSource;
|
||||||
|
if (DataSourceType.SQLITE == dataSourceType) {
|
||||||
server.getScheduler().runTaskAsynchronously(this, new Runnable() {
|
server.getScheduler().runTaskAsynchronously(this, new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
@ -577,34 +589,6 @@ public class AuthMe extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Settings.getDataSource == DataSourceType.FILE) {
|
|
||||||
ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated, it will be changed " +
|
|
||||||
"to SQLite... Connection will be impossible until conversion is done!");
|
|
||||||
ForceFlatToSqlite converter = new ForceFlatToSqlite(database, newSettings);
|
|
||||||
DataSource source = converter.run();
|
|
||||||
if (source != null) {
|
|
||||||
database = source;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: Move this to another place maybe ?
|
|
||||||
if (HashAlgorithm.PLAINTEXT == newSettings.getProperty(SecuritySettings.PASSWORD_HASH)) {
|
|
||||||
ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated; " +
|
|
||||||
"it will be changed and hashed now to the AuthMe default hashing method");
|
|
||||||
for (PlayerAuth auth : database.getAllAuths()) {
|
|
||||||
HashedPassword hashedPassword = passwordSecurity.computeHash(
|
|
||||||
HashAlgorithm.SHA256, auth.getPassword().getHash(), auth.getNickname());
|
|
||||||
auth.setPassword(hashedPassword);
|
|
||||||
database.updatePassword(auth);
|
|
||||||
}
|
|
||||||
newSettings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256);
|
|
||||||
newSettings.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) {
|
|
||||||
database = new CacheDataSource(database);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -712,14 +696,14 @@ public class AuthMe extends JavaPlugin {
|
|||||||
if (newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN) && tabComplete == null) {
|
if (newSettings.getProperty(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN) && tabComplete == null) {
|
||||||
tabComplete = new AuthMeTabCompletePacketAdapter(this);
|
tabComplete = new AuthMeTabCompletePacketAdapter(this);
|
||||||
tabComplete.register();
|
tabComplete.register();
|
||||||
} else if (inventoryProtector != null) {
|
} else if (tabComplete != null) {
|
||||||
tabComplete.unregister();
|
tabComplete.unregister();
|
||||||
tabComplete = null;
|
tabComplete = null;
|
||||||
}
|
}
|
||||||
if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) {
|
if (newSettings.getProperty(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN) && tablistHider == null) {
|
||||||
tablistHider = new AuthMeTablistPacketAdapter(this);
|
tablistHider = new AuthMeTablistPacketAdapter(this);
|
||||||
tablistHider.register();
|
tablistHider.register();
|
||||||
} else if (inventoryProtector != null) {
|
} else if (tablistHider != null) {
|
||||||
tablistHider.unregister();
|
tablistHider.unregister();
|
||||||
tablistHider = null;
|
tablistHider = null;
|
||||||
}
|
}
|
||||||
@ -788,25 +772,9 @@ public class AuthMe extends JavaPlugin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return the spawn location of a player
|
// Return the spawn location of a player
|
||||||
|
@Deprecated
|
||||||
public Location getSpawnLocation(Player player) {
|
public Location getSpawnLocation(Player player) {
|
||||||
World world = player.getWorld();
|
return Spawn.getInstance().getSpawnLocation(player);
|
||||||
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
|
// Return the default spawn point of a world
|
||||||
@ -948,7 +916,7 @@ public class AuthMe extends JavaPlugin {
|
|||||||
String commandLabel, String[] args) {
|
String commandLabel, String[] args) {
|
||||||
// Make sure the command handler has been initialized
|
// Make sure the command handler has been initialized
|
||||||
if (commandHandler == null) {
|
if (commandHandler == null) {
|
||||||
wrapper.getLogger().severe("AuthMe command handler is not available");
|
getLogger().severe("AuthMe command handler is not available");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
package fr.xephi.authme.cache.auth;
|
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.Objects.firstNonNull;
|
||||||
import static com.google.common.base.Preconditions.checkNotNull;
|
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);
|
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.
|
* Constructor for PlayerAuth.
|
||||||
*
|
*
|
||||||
@ -118,44 +103,6 @@ public class PlayerAuth {
|
|||||||
this(nickname, new HashedPassword(hash), -1, ip, lastLogin, x, y, z, world, email, realName);
|
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.
|
* Constructor for PlayerAuth.
|
||||||
*
|
*
|
||||||
@ -171,8 +118,8 @@ public class PlayerAuth {
|
|||||||
* @param email String
|
* @param email String
|
||||||
* @param realName 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) {
|
double x, double y, double z, String world, String email, String realName) {
|
||||||
this.nickname = nickname.toLowerCase();
|
this.nickname = nickname.toLowerCase();
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.ip = ip;
|
this.ip = ip;
|
||||||
|
@ -5,6 +5,7 @@ import fr.xephi.authme.ConsoleLogger;
|
|||||||
import fr.xephi.authme.command.CommandService;
|
import fr.xephi.authme.command.CommandService;
|
||||||
import fr.xephi.authme.command.ExecutableCommand;
|
import fr.xephi.authme.command.ExecutableCommand;
|
||||||
import fr.xephi.authme.output.MessageKey;
|
import fr.xephi.authme.output.MessageKey;
|
||||||
|
import fr.xephi.authme.settings.Spawn;
|
||||||
import org.bukkit.command.CommandSender;
|
import org.bukkit.command.CommandSender;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -20,7 +21,11 @@ public class ReloadCommand implements ExecutableCommand {
|
|||||||
try {
|
try {
|
||||||
commandService.getSettings().reload();
|
commandService.getSettings().reload();
|
||||||
commandService.reloadMessages(commandService.getSettings().getMessagesFile());
|
commandService.reloadMessages(commandService.getSettings().getMessagesFile());
|
||||||
plugin.setupDatabase();
|
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
|
||||||
|
plugin.setupDatabase(commandService.getSettings());
|
||||||
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
|
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
|
||||||
|
@ -179,8 +179,8 @@ public class CacheDataSource implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<String> getAllAuthsByEmail(final String email) {
|
public synchronized int countAuthsByEmail(final String email) {
|
||||||
return source.getAllAuthsByEmail(email);
|
return source.countAuthsByEmail(email);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,7 +14,6 @@ public interface DataSource {
|
|||||||
* Return whether there is a record for the given username.
|
* Return whether there is a record for the given username.
|
||||||
*
|
*
|
||||||
* @param user The username to look up
|
* @param user The username to look up
|
||||||
*
|
|
||||||
* @return True if there is a record, false otherwise
|
* @return True if there is a record, false otherwise
|
||||||
*/
|
*/
|
||||||
boolean isAuthAvailable(String user);
|
boolean isAuthAvailable(String user);
|
||||||
@ -23,7 +22,6 @@ public interface DataSource {
|
|||||||
* Return the hashed password of the player.
|
* Return the hashed password of the player.
|
||||||
*
|
*
|
||||||
* @param user The user whose password should be retrieve
|
* @param user The user whose password should be retrieve
|
||||||
*
|
|
||||||
* @return The password hash of the player
|
* @return The password hash of the player
|
||||||
*/
|
*/
|
||||||
HashedPassword getPassword(String user);
|
HashedPassword getPassword(String user);
|
||||||
@ -32,7 +30,6 @@ public interface DataSource {
|
|||||||
* Retrieve the entire PlayerAuth object associated with the username.
|
* Retrieve the entire PlayerAuth object associated with the username.
|
||||||
*
|
*
|
||||||
* @param user The user to retrieve
|
* @param user The user to retrieve
|
||||||
*
|
|
||||||
* @return The PlayerAuth object for the given username
|
* @return The PlayerAuth object for the given username
|
||||||
*/
|
*/
|
||||||
PlayerAuth getAuth(String user);
|
PlayerAuth getAuth(String user);
|
||||||
@ -41,7 +38,6 @@ public interface DataSource {
|
|||||||
* Save a new PlayerAuth object.
|
* Save a new PlayerAuth object.
|
||||||
*
|
*
|
||||||
* @param auth The new PlayerAuth to persist
|
* @param auth The new PlayerAuth to persist
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean saveAuth(PlayerAuth auth);
|
boolean saveAuth(PlayerAuth auth);
|
||||||
@ -50,7 +46,6 @@ public interface DataSource {
|
|||||||
* Update the session of a record (IP, last login, real name).
|
* Update the session of a record (IP, last login, real name).
|
||||||
*
|
*
|
||||||
* @param auth The PlayerAuth object to update in the database
|
* @param auth The PlayerAuth object to update in the database
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean updateSession(PlayerAuth auth);
|
boolean updateSession(PlayerAuth auth);
|
||||||
@ -59,7 +54,6 @@ public interface DataSource {
|
|||||||
* Update the password of the given PlayerAuth object.
|
* Update the password of the given PlayerAuth object.
|
||||||
*
|
*
|
||||||
* @param auth The PlayerAuth whose password should be updated
|
* @param auth The PlayerAuth whose password should be updated
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean updatePassword(PlayerAuth auth);
|
boolean updatePassword(PlayerAuth auth);
|
||||||
@ -67,9 +61,8 @@ public interface DataSource {
|
|||||||
/**
|
/**
|
||||||
* Update the password of the given player.
|
* Update the password of the given player.
|
||||||
*
|
*
|
||||||
* @param user The user whose password should be updated
|
* @param user The user whose password should be updated
|
||||||
* @param password The new password
|
* @param password The new password
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean updatePassword(String user, HashedPassword password);
|
boolean updatePassword(String user, HashedPassword password);
|
||||||
@ -79,7 +72,6 @@ public interface DataSource {
|
|||||||
* the given time.
|
* the given time.
|
||||||
*
|
*
|
||||||
* @param until The minimum last login
|
* @param until The minimum last login
|
||||||
*
|
|
||||||
* @return The account names that have been removed
|
* @return The account names that have been removed
|
||||||
*/
|
*/
|
||||||
List<String> autoPurgeDatabase(long until);
|
List<String> autoPurgeDatabase(long until);
|
||||||
@ -88,7 +80,6 @@ public interface DataSource {
|
|||||||
* Remove a user record from the database.
|
* Remove a user record from the database.
|
||||||
*
|
*
|
||||||
* @param user The user to remove
|
* @param user The user to remove
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean removeAuth(String user);
|
boolean removeAuth(String user);
|
||||||
@ -97,7 +88,6 @@ public interface DataSource {
|
|||||||
* Update the quit location of a PlayerAuth.
|
* Update the quit location of a PlayerAuth.
|
||||||
*
|
*
|
||||||
* @param auth The entry whose quit location should be updated
|
* @param auth The entry whose quit location should be updated
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean updateQuitLoc(PlayerAuth auth);
|
boolean updateQuitLoc(PlayerAuth auth);
|
||||||
@ -106,25 +96,22 @@ public interface DataSource {
|
|||||||
* Return all usernames associated with the given IP address.
|
* Return all usernames associated with the given IP address.
|
||||||
*
|
*
|
||||||
* @param ip The IP address to look up
|
* @param ip The IP address to look up
|
||||||
*
|
|
||||||
* @return Usernames associated with the given IP address
|
* @return Usernames associated with the given IP address
|
||||||
*/
|
*/
|
||||||
List<String> getAllAuthsByIp(String ip);
|
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
|
* @param email The email address to look up
|
||||||
*
|
* @return Number of accounts using the given email address
|
||||||
* @return Users using the given email address
|
|
||||||
*/
|
*/
|
||||||
List<String> getAllAuthsByEmail(String email);
|
int countAuthsByEmail(String email);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the email of the PlayerAuth in the data source.
|
* Update the email of the PlayerAuth in the data source.
|
||||||
*
|
*
|
||||||
* @param auth The PlayerAuth whose email should be updated
|
* @param auth The PlayerAuth whose email should be updated
|
||||||
*
|
|
||||||
* @return True upon success, false upon failure
|
* @return True upon success, false upon failure
|
||||||
*/
|
*/
|
||||||
boolean updateEmail(PlayerAuth auth);
|
boolean updateEmail(PlayerAuth auth);
|
||||||
|
@ -7,6 +7,7 @@ public enum DataSourceType {
|
|||||||
|
|
||||||
MYSQL,
|
MYSQL,
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
FILE,
|
FILE,
|
||||||
|
|
||||||
SQLITE
|
SQLITE
|
||||||
|
@ -487,25 +487,21 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getAllAuthsByEmail(String email) {
|
public int countAuthsByEmail(String email) {
|
||||||
BufferedReader br = null;
|
BufferedReader br = null;
|
||||||
List<String> countEmail = new ArrayList<>();
|
int countEmail = 0;
|
||||||
try {
|
try {
|
||||||
br = new BufferedReader(new FileReader(source));
|
br = new BufferedReader(new FileReader(source));
|
||||||
String line;
|
String line;
|
||||||
while ((line = br.readLine()) != null) {
|
while ((line = br.readLine()) != null) {
|
||||||
String[] args = line.split(":");
|
String[] args = line.split(":");
|
||||||
if (args.length > 8 && args[8].equals(email)) {
|
if (args.length > 8 && args[8].equals(email)) {
|
||||||
countEmail.add(args[0]);
|
++countEmail;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return countEmail;
|
return countEmail;
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
|
||||||
return new ArrayList<>();
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ConsoleLogger.showError(ex.getMessage());
|
ConsoleLogger.showError(ex.getMessage());
|
||||||
return new ArrayList<>();
|
|
||||||
} finally {
|
} finally {
|
||||||
if (br != null) {
|
if (br != null) {
|
||||||
try {
|
try {
|
||||||
@ -514,6 +510,7 @@ public class FlatFile implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -22,7 +22,6 @@ import java.sql.PreparedStatement;
|
|||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.sql.Statement;
|
||||||
import java.sql.Timestamp;
|
|
||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -82,6 +81,19 @@ public class MySQL implements DataSource {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
private synchronized void setConnectionArguments() throws RuntimeException {
|
||||||
ds = new HikariDataSource();
|
ds = new HikariDataSource();
|
||||||
ds.setPoolName("AuthMeMYSQLPool");
|
ds.setPoolName("AuthMeMYSQLPool");
|
||||||
@ -131,7 +143,7 @@ public class MySQL implements DataSource {
|
|||||||
+ col.REAL_NAME + " VARCHAR(255) NOT NULL,"
|
+ col.REAL_NAME + " VARCHAR(255) NOT NULL,"
|
||||||
+ col.PASSWORD + " VARCHAR(255) NOT NULL,"
|
+ col.PASSWORD + " VARCHAR(255) NOT NULL,"
|
||||||
+ col.IP + " VARCHAR(40) NOT NULL DEFAULT '127.0.0.1',"
|
+ 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_X + " DOUBLE NOT NULL DEFAULT '0.0',"
|
||||||
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0',"
|
+ col.LASTLOC_Y + " DOUBLE NOT NULL DEFAULT '0.0',"
|
||||||
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0',"
|
+ col.LASTLOC_Z + " DOUBLE NOT NULL DEFAULT '0.0',"
|
||||||
@ -182,9 +194,9 @@ public class MySQL implements DataSource {
|
|||||||
rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
|
rs = md.getColumns(null, null, tableName, col.LAST_LOGIN);
|
||||||
if (!rs.next()) {
|
if (!rs.next()) {
|
||||||
st.executeUpdate("ALTER TABLE " + tableName
|
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 {
|
} else {
|
||||||
migrateLastLoginColumnToTimestamp(con, rs);
|
migrateLastLoginColumnToBigInt(con, rs);
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
|
|
||||||
@ -234,66 +246,72 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isAuthAvailable(String user) {
|
public synchronized boolean isAuthAvailable(String user) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
ResultSet rs = null;
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
pst.setString(1, user.toLowerCase());
|
pst.setString(1, user.toLowerCase());
|
||||||
ResultSet rs = pst.executeQuery();
|
rs = pst.executeQuery();
|
||||||
return rs.next();
|
return rs.next();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
|
} finally {
|
||||||
|
close(rs);
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HashedPassword getPassword(String user) {
|
public HashedPassword getPassword(String user) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "SELECT " + col.PASSWORD + "," + col.SALT + " FROM " + tableName
|
||||||
String sql = "SELECT " + col.PASSWORD + "," + col.SALT + " FROM " + tableName
|
+ " WHERE " + col.NAME + "=?;";
|
||||||
+ " WHERE " + col.NAME + "=?;";
|
ResultSet rs = null;
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
pst.setString(1, user.toLowerCase());
|
pst.setString(1, user.toLowerCase());
|
||||||
ResultSet rs = pst.executeQuery();
|
rs = pst.executeQuery();
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
return new HashedPassword(rs.getString(col.PASSWORD),
|
return new HashedPassword(rs.getString(col.PASSWORD),
|
||||||
!col.SALT.isEmpty() ? rs.getString(col.SALT) : null);
|
!col.SALT.isEmpty() ? rs.getString(col.SALT) : null);
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
|
} finally {
|
||||||
|
close(rs);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized PlayerAuth getAuth(String user) {
|
public synchronized PlayerAuth getAuth(String user) {
|
||||||
PlayerAuth pAuth;
|
String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
try (Connection con = getConnection()) {
|
PlayerAuth auth;
|
||||||
String sql = "SELECT * FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, user.toLowerCase());
|
pst.setString(1, user.toLowerCase());
|
||||||
ResultSet rs = pst.executeQuery();
|
int id;
|
||||||
if (!rs.next()) {
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
return null;
|
if (!rs.next()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
id = rs.getInt(col.ID);
|
||||||
|
auth = buildAuthFromResultSet(rs);
|
||||||
}
|
}
|
||||||
int id = rs.getInt(col.ID);
|
|
||||||
pAuth = buildAuthFromResultSet(rs);
|
|
||||||
rs.close();
|
|
||||||
pst.close();
|
|
||||||
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
|
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
|
||||||
pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;");
|
try (PreparedStatement pst2 = con.prepareStatement(
|
||||||
pst.setInt(1, id);
|
"SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;")) {
|
||||||
rs = pst.executeQuery();
|
pst2.setInt(1, id);
|
||||||
if (rs.next()) {
|
try (ResultSet rs = pst2.executeQuery()) {
|
||||||
Blob blob = rs.getBlob("data");
|
if (rs.next()) {
|
||||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
Blob blob = rs.getBlob("data");
|
||||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||||
|
auth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return auth;
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
return pAuth;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -314,7 +332,7 @@ public class MySQL implements DataSource {
|
|||||||
pst.setString(1, auth.getNickname());
|
pst.setString(1, auth.getNickname());
|
||||||
pst.setString(2, auth.getPassword().getHash());
|
pst.setString(2, auth.getPassword().getHash());
|
||||||
pst.setString(3, auth.getIp());
|
pst.setString(3, auth.getIp());
|
||||||
pst.setTimestamp(4, new Timestamp(auth.getLastLogin()));
|
pst.setLong(4, auth.getLastLogin());
|
||||||
pst.setString(5, auth.getRealName());
|
pst.setString(5, auth.getRealName());
|
||||||
pst.setString(6, auth.getEmail());
|
pst.setString(6, auth.getEmail());
|
||||||
if (useSalt) {
|
if (useSalt) {
|
||||||
@ -566,7 +584,7 @@ public class MySQL implements DataSource {
|
|||||||
+ col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
|
+ col.IP + "=?, " + col.LAST_LOGIN + "=?, " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
|
||||||
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
pst.setString(1, auth.getIp());
|
pst.setString(1, auth.getIp());
|
||||||
pst.setTimestamp(2, new Timestamp(auth.getLastLogin()));
|
pst.setLong(2, auth.getLastLogin());
|
||||||
pst.setString(3, auth.getRealName());
|
pst.setString(3, auth.getRealName());
|
||||||
pst.setString(4, auth.getNickname());
|
pst.setString(4, auth.getNickname());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
@ -580,20 +598,19 @@ public class MySQL implements DataSource {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized List<String> autoPurgeDatabase(long until) {
|
public synchronized List<String> autoPurgeDatabase(long until) {
|
||||||
List<String> list = new ArrayList<>();
|
List<String> list = new ArrayList<>();
|
||||||
try (Connection con = getConnection()) {
|
String select = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
String delete = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
||||||
PreparedStatement st = con.prepareStatement(sql);
|
try (Connection con = getConnection();
|
||||||
st.setLong(1, until);
|
PreparedStatement selectPst = con.prepareStatement(select);
|
||||||
ResultSet rs = st.executeQuery();
|
PreparedStatement deletePst = con.prepareStatement(delete)) {
|
||||||
while (rs.next()) {
|
selectPst.setLong(1, until);
|
||||||
list.add(rs.getString(col.NAME));
|
try (ResultSet rs = selectPst.executeQuery()) {
|
||||||
|
while (rs.next()) {
|
||||||
|
list.add(rs.getString(col.NAME));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rs.close();
|
deletePst.setLong(1, until);
|
||||||
sql = "DELETE FROM " + tableName + " WHERE " + col.LAST_LOGIN + "<?;";
|
deletePst.executeUpdate();
|
||||||
st = con.prepareStatement(sql);
|
|
||||||
st.setLong(1, until);
|
|
||||||
st.executeUpdate();
|
|
||||||
st.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -634,18 +651,16 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean updateQuitLoc(PlayerAuth auth) {
|
public synchronized boolean updateQuitLoc(PlayerAuth auth) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName
|
||||||
String sql = "UPDATE " + tableName
|
+ " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?"
|
||||||
+ " SET " + col.LASTLOC_X + " =?, " + col.LASTLOC_Y + "=?, " + col.LASTLOC_Z + "=?, " + col.LASTLOC_WORLD + "=?"
|
+ " WHERE " + col.NAME + "=?;";
|
||||||
+ " WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setDouble(1, auth.getQuitLocX());
|
pst.setDouble(1, auth.getQuitLocX());
|
||||||
pst.setDouble(2, auth.getQuitLocY());
|
pst.setDouble(2, auth.getQuitLocY());
|
||||||
pst.setDouble(3, auth.getQuitLocZ());
|
pst.setDouble(3, auth.getQuitLocZ());
|
||||||
pst.setString(4, auth.getWorld());
|
pst.setString(4, auth.getWorld());
|
||||||
pst.setString(5, auth.getNickname());
|
pst.setString(5, auth.getNickname());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
pst.close();
|
|
||||||
return true;
|
return true;
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
@ -655,13 +670,11 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean updateEmail(PlayerAuth auth) {
|
public synchronized boolean updateEmail(PlayerAuth auth) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.EMAIL + " =? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, auth.getEmail());
|
pst.setString(1, auth.getEmail());
|
||||||
pst.setString(2, auth.getNickname());
|
pst.setString(2, auth.getNickname());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
pst.close();
|
|
||||||
return true;
|
return true;
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
@ -690,16 +703,14 @@ public class MySQL implements DataSource {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized List<String> getAllAuthsByIp(String ip) {
|
public synchronized List<String> getAllAuthsByIp(String ip) {
|
||||||
List<String> result = new ArrayList<>();
|
List<String> result = new ArrayList<>();
|
||||||
try (Connection con = getConnection()) {
|
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
|
||||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.IP + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, ip);
|
pst.setString(1, ip);
|
||||||
ResultSet rs = pst.executeQuery();
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
result.add(rs.getString(col.NAME));
|
result.add(rs.getString(col.NAME));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -707,33 +718,29 @@ public class MySQL implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized List<String> getAllAuthsByEmail(String email) {
|
public synchronized int countAuthsByEmail(String email) {
|
||||||
List<String> countEmail = new ArrayList<>();
|
String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)";
|
||||||
try (Connection con = getConnection()) {
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
String sql = "SELECT " + col.NAME + " FROM " + tableName + " WHERE " + col.EMAIL + "=?;";
|
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, email);
|
pst.setString(1, email);
|
||||||
ResultSet rs = pst.executeQuery();
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
while (rs.next()) {
|
if (rs.next()) {
|
||||||
countEmail.add(rs.getString(col.NAME));
|
return rs.getInt(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
return countEmail;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized void purgeBanned(List<String> banned) {
|
public synchronized void purgeBanned(List<String> banned) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
PreparedStatement pst = con.prepareStatement("DELETE FROM " + tableName + " WHERE " + col.NAME + "=?;");
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
for (String name : banned) {
|
for (String name : banned) {
|
||||||
pst.setString(1, name);
|
pst.setString(1, name);
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
}
|
}
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -746,28 +753,25 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLogged(String user) {
|
public boolean isLogged(String user) {
|
||||||
boolean isLogged = false;
|
String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
||||||
try (Connection con = getConnection()) {
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
String sql = "SELECT " + col.IS_LOGGED + " FROM " + tableName + " WHERE " + col.NAME + "=?;";
|
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, user);
|
pst.setString(1, user);
|
||||||
ResultSet rs = pst.executeQuery();
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
isLogged = rs.next() && (rs.getInt(col.IS_LOGGED) == 1);
|
return rs.next() && (rs.getInt(col.IS_LOGGED) == 1);
|
||||||
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
return isLogged;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setLogged(String user) {
|
public void setLogged(String user) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setInt(1, 1);
|
pst.setInt(1, 1);
|
||||||
pst.setString(2, user.toLowerCase());
|
pst.setString(2, user.toLowerCase());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -775,13 +779,11 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUnlogged(String user) {
|
public void setUnlogged(String user) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setInt(1, 0);
|
pst.setInt(1, 0);
|
||||||
pst.setString(2, user.toLowerCase());
|
pst.setString(2, user.toLowerCase());
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -789,13 +791,11 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void purgeLogged() {
|
public void purgeLogged() {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IS_LOGGED + "=? WHERE " + col.IS_LOGGED + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setInt(1, 0);
|
pst.setInt(1, 0);
|
||||||
pst.setInt(2, 1);
|
pst.setInt(2, 1);
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
pst.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -804,14 +804,13 @@ public class MySQL implements DataSource {
|
|||||||
@Override
|
@Override
|
||||||
public int getAccountsRegistered() {
|
public int getAccountsRegistered() {
|
||||||
int result = 0;
|
int result = 0;
|
||||||
try (Connection con = getConnection()) {
|
String sql = "SELECT COUNT(*) FROM " + tableName;
|
||||||
Statement st = con.createStatement();
|
try (Connection con = getConnection();
|
||||||
ResultSet rs = st.executeQuery("SELECT COUNT(*) FROM " + tableName);
|
Statement st = con.createStatement();
|
||||||
|
ResultSet rs = st.executeQuery(sql)) {
|
||||||
if (rs.next()) {
|
if (rs.next()) {
|
||||||
result = rs.getInt(1);
|
result = rs.getInt(1);
|
||||||
}
|
}
|
||||||
rs.close();
|
|
||||||
st.close();
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -820,9 +819,8 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void updateName(String oldOne, String newOne) {
|
public void updateName(String oldOne, String newOne) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.NAME + "=? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.NAME + "=? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, newOne);
|
pst.setString(1, newOne);
|
||||||
pst.setString(2, oldOne);
|
pst.setString(2, oldOne);
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
@ -833,9 +831,8 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateRealName(String user, String realName) {
|
public boolean updateRealName(String user, String realName) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.REAL_NAME + "=? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, realName);
|
pst.setString(1, realName);
|
||||||
pst.setString(2, user);
|
pst.setString(2, user);
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
@ -848,9 +845,8 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean updateIp(String user, String ip) {
|
public boolean updateIp(String user, String ip) {
|
||||||
try (Connection con = getConnection()) {
|
String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
|
||||||
String sql = "UPDATE " + tableName + " SET " + col.IP + "=? WHERE " + col.NAME + "=?;";
|
try (Connection con = getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, ip);
|
pst.setString(1, ip);
|
||||||
pst.setString(2, user);
|
pst.setString(2, user);
|
||||||
pst.executeUpdate();
|
pst.executeUpdate();
|
||||||
@ -867,23 +863,23 @@ public class MySQL implements DataSource {
|
|||||||
try (Connection con = getConnection()) {
|
try (Connection con = getConnection()) {
|
||||||
Statement st = con.createStatement();
|
Statement st = con.createStatement();
|
||||||
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName);
|
ResultSet rs = st.executeQuery("SELECT * FROM " + tableName);
|
||||||
PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;");
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
PlayerAuth pAuth = buildAuthFromResultSet(rs);
|
PlayerAuth pAuth = buildAuthFromResultSet(rs);
|
||||||
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
|
if (hashAlgorithm == HashAlgorithm.XFBCRYPT) {
|
||||||
int id = rs.getInt(col.ID);
|
try (PreparedStatement pst = con.prepareStatement("SELECT data FROM xf_user_authenticate WHERE " + col.ID + "=?;")) {
|
||||||
pst.setInt(1, id);
|
int id = rs.getInt(col.ID);
|
||||||
ResultSet rs2 = pst.executeQuery();
|
pst.setInt(1, id);
|
||||||
if (rs2.next()) {
|
ResultSet rs2 = pst.executeQuery();
|
||||||
Blob blob = rs2.getBlob("data");
|
if (rs2.next()) {
|
||||||
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
Blob blob = rs2.getBlob("data");
|
||||||
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
byte[] bytes = blob.getBytes(1, (int) blob.length());
|
||||||
|
pAuth.setPassword(new HashedPassword(XFBCRYPT.getHashFromBlob(bytes)));
|
||||||
|
}
|
||||||
|
rs2.close();
|
||||||
}
|
}
|
||||||
rs2.close();
|
|
||||||
}
|
}
|
||||||
auths.add(pAuth);
|
auths.add(pAuth);
|
||||||
}
|
}
|
||||||
pst.close();
|
|
||||||
rs.close();
|
rs.close();
|
||||||
st.close();
|
st.close();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@ -922,12 +918,12 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean isEmailStored(String email) {
|
public synchronized boolean isEmailStored(String email) {
|
||||||
String sql = "SELECT 1 FROM " + tableName + " WHERE " + col.EMAIL + " = ?";
|
String sql = "SELECT 1 FROM " + tableName + " WHERE UPPER(" + col.EMAIL + ") = UPPER(?)";
|
||||||
try (Connection con = ds.getConnection()) {
|
try (Connection con = ds.getConnection(); PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
PreparedStatement pst = con.prepareStatement(sql);
|
|
||||||
pst.setString(1, email);
|
pst.setString(1, email);
|
||||||
ResultSet rs = pst.executeQuery();
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
return rs.next();
|
return rs.next();
|
||||||
|
}
|
||||||
} catch (SQLException e) {
|
} catch (SQLException e) {
|
||||||
logSqlException(e);
|
logSqlException(e);
|
||||||
}
|
}
|
||||||
@ -941,7 +937,7 @@ public class MySQL implements DataSource {
|
|||||||
.name(row.getString(col.NAME))
|
.name(row.getString(col.NAME))
|
||||||
.realName(row.getString(col.REAL_NAME))
|
.realName(row.getString(col.REAL_NAME))
|
||||||
.password(row.getString(col.PASSWORD), salt)
|
.password(row.getString(col.PASSWORD), salt)
|
||||||
.lastLogin(safeGetTimestamp(row))
|
.lastLogin(row.getLong(col.LAST_LOGIN))
|
||||||
.ip(row.getString(col.IP))
|
.ip(row.getString(col.IP))
|
||||||
.locWorld(row.getString(col.LASTLOC_WORLD))
|
.locWorld(row.getString(col.LASTLOC_WORLD))
|
||||||
.locX(row.getDouble(col.LASTLOC_X))
|
.locX(row.getDouble(col.LASTLOC_X))
|
||||||
@ -953,24 +949,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
|
* @param con Connection to the database
|
||||||
* @return The timestamp (as number of milliseconds since 1970-01-01 00:00:00 GMT)
|
* @param rs ResultSet containing meta data for the lastlogin column
|
||||||
*/
|
*/
|
||||||
private long safeGetTimestamp(ResultSet row) {
|
private void migrateLastLoginColumnToBigInt(Connection con, ResultSet rs) throws SQLException {
|
||||||
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 {
|
|
||||||
final int columnType = rs.getInt("DATA_TYPE");
|
final int columnType = rs.getInt("DATA_TYPE");
|
||||||
if (columnType == Types.BIGINT) {
|
if (columnType == Types.TIMESTAMP) {
|
||||||
ConsoleLogger.info("Migrating lastlogin column from bigint to timestamp");
|
ConsoleLogger.info("Migrating lastlogin column from timestamp to bigint");
|
||||||
final String lastLoginOld = col.LAST_LOGIN + "_old";
|
final String lastLoginOld = col.LAST_LOGIN + "_old";
|
||||||
|
|
||||||
// Rename lastlogin to lastlogin_old
|
// Rename lastlogin to lastlogin_old
|
||||||
@ -981,12 +968,12 @@ public class MySQL implements DataSource {
|
|||||||
|
|
||||||
// Create lastlogin column
|
// Create lastlogin column
|
||||||
sql = String.format("ALTER TABLE %s ADD COLUMN %s "
|
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);
|
tableName, col.LAST_LOGIN, col.IP);
|
||||||
con.prepareStatement(sql).execute();
|
con.prepareStatement(sql).execute();
|
||||||
|
|
||||||
// Set values of lastlogin based on lastlogin_old
|
// 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);
|
tableName, col.LAST_LOGIN, lastLoginOld);
|
||||||
con.prepareStatement(sql).execute();
|
con.prepareStatement(sql).execute();
|
||||||
|
|
||||||
@ -994,7 +981,7 @@ public class MySQL implements DataSource {
|
|||||||
sql = String.format("ALTER TABLE %s DROP COLUMN %s",
|
sql = String.format("ALTER TABLE %s DROP COLUMN %s",
|
||||||
tableName, lastLoginOld);
|
tableName, lastLoginOld);
|
||||||
con.prepareStatement(sql).execute();
|
con.prepareStatement(sql).execute();
|
||||||
ConsoleLogger.info("Finished migration of lastlogin (bigint to timestamp)");
|
ConsoleLogger.info("Finished migration of lastlogin (timestamp to bigint)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1002,4 +989,14 @@ public class MySQL implements DataSource {
|
|||||||
ConsoleLogger.logException("Error during SQL operation:", e);
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
package fr.xephi.authme.datasource;
|
package fr.xephi.authme.datasource;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import fr.xephi.authme.ConsoleLogger;
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
import fr.xephi.authme.cache.auth.PlayerAuth;
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
import fr.xephi.authme.security.crypts.HashedPassword;
|
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 {
|
private synchronized void connect() throws ClassNotFoundException, SQLException {
|
||||||
Class.forName("org.sqlite.JDBC");
|
Class.forName("org.sqlite.JDBC");
|
||||||
ConsoleLogger.info("SQLite driver loaded");
|
ConsoleLogger.info("SQLite driver loaded");
|
||||||
@ -341,7 +350,8 @@ public class SQLite implements DataSource {
|
|||||||
@Override
|
@Override
|
||||||
public synchronized void close() {
|
public synchronized void close() {
|
||||||
try {
|
try {
|
||||||
con.close();
|
if (con != null && !con.isClosed())
|
||||||
|
con.close();
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
}
|
}
|
||||||
@ -394,25 +404,19 @@ public class SQLite implements DataSource {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<String> getAllAuthsByEmail(String email) {
|
public int countAuthsByEmail(String email) {
|
||||||
PreparedStatement pst = null;
|
String sql = "SELECT COUNT(1) FROM " + tableName + " WHERE " + col.EMAIL + " = ? COLLATE NOCASE;";
|
||||||
ResultSet rs = null;
|
try (PreparedStatement pst = con.prepareStatement(sql)) {
|
||||||
List<String> countEmail = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
pst = con.prepareStatement("SELECT * FROM " + tableName + " WHERE " + col.EMAIL + "=?;");
|
|
||||||
pst.setString(1, email);
|
pst.setString(1, email);
|
||||||
rs = pst.executeQuery();
|
try (ResultSet rs = pst.executeQuery()) {
|
||||||
while (rs.next()) {
|
if (rs.next()) {
|
||||||
countEmail.add(rs.getString(col.NAME));
|
return rs.getInt(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return countEmail;
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
logSqlException(ex);
|
logSqlException(ex);
|
||||||
} finally {
|
|
||||||
close(rs);
|
|
||||||
close(pst);
|
|
||||||
}
|
}
|
||||||
return new ArrayList<>();
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -17,7 +17,6 @@ import fr.xephi.authme.settings.Settings;
|
|||||||
import fr.xephi.authme.util.GeoLiteAPI;
|
import fr.xephi.authme.util.GeoLiteAPI;
|
||||||
import fr.xephi.authme.util.Utils;
|
import fr.xephi.authme.util.Utils;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.ChatColor;
|
|
||||||
import org.bukkit.GameMode;
|
import org.bukkit.GameMode;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -243,9 +242,7 @@ public class AuthMePlayerListener implements Listener {
|
|||||||
String realName = auth.getRealName();
|
String realName = auth.getRealName();
|
||||||
if (!realName.isEmpty() && !realName.equals("Player") && !realName.equals(event.getName())) {
|
if (!realName.isEmpty() && !realName.equals("Player") && !realName.equals(event.getName())) {
|
||||||
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
|
event.setLoginResult(AsyncPlayerPreLoginEvent.Result.KICK_OTHER);
|
||||||
// TODO: Add a message like : MessageKey.INVALID_NAME_CASE
|
event.setKickMessage(m.retrieveSingle(MessageKey.INVALID_NAME_CASE, realName, event.getName()));
|
||||||
event.setKickMessage("You should join using username: " + ChatColor.AQUA + realName +
|
|
||||||
ChatColor.RESET + "\nnot: " + ChatColor.RED + event.getName());
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (realName.isEmpty() || realName.equals("Player")) {
|
if (realName.isEmpty() || realName.equals("Player")) {
|
||||||
|
@ -127,7 +127,9 @@ public enum MessageKey {
|
|||||||
|
|
||||||
TWO_FACTOR_CREATE("two_factor_create", "%code", "%url"),
|
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 key;
|
||||||
private String[] tags;
|
private String[] tags;
|
||||||
|
@ -8,6 +8,8 @@ import org.bukkit.configuration.file.FileConfiguration;
|
|||||||
import org.bukkit.configuration.file.YamlConfiguration;
|
import org.bukkit.configuration.file.YamlConfiguration;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for retrieving and sending translatable messages to players.
|
* Class for retrieving and sending translatable messages to players.
|
||||||
@ -16,7 +18,7 @@ public class Messages {
|
|||||||
|
|
||||||
private FileConfiguration configuration;
|
private FileConfiguration configuration;
|
||||||
private String fileName;
|
private String fileName;
|
||||||
private final File defaultFile;
|
private final String defaultFile;
|
||||||
private FileConfiguration defaultConfiguration;
|
private FileConfiguration defaultConfiguration;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -25,7 +27,7 @@ public class Messages {
|
|||||||
* @param messageFile The messages file to use
|
* @param messageFile The messages file to use
|
||||||
* @param defaultFile The file with messages to use as default if missing
|
* @param defaultFile The file with messages to use as default if missing
|
||||||
*/
|
*/
|
||||||
public Messages(File messageFile, File defaultFile) {
|
public Messages(File messageFile, String defaultFile) {
|
||||||
initializeFile(messageFile);
|
initializeFile(messageFile);
|
||||||
this.defaultFile = defaultFile;
|
this.defaultFile = defaultFile;
|
||||||
}
|
}
|
||||||
@ -53,17 +55,7 @@ public class Messages {
|
|||||||
* @param replacements The replacements to apply for the tags
|
* @param replacements The replacements to apply for the tags
|
||||||
*/
|
*/
|
||||||
public void send(CommandSender sender, MessageKey key, String... replacements) {
|
public void send(CommandSender sender, MessageKey key, String... replacements) {
|
||||||
String message = retrieveSingle(key);
|
String message = retrieveSingle(key, replacements);
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (String line : message.split("\n")) {
|
for (String line : message.split("\n")) {
|
||||||
sender.sendMessage(line);
|
sender.sendMessage(line);
|
||||||
}
|
}
|
||||||
@ -97,6 +89,27 @@ public class Messages {
|
|||||||
return StringUtils.join("\n", retrieve(key));
|
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.
|
* Reload the messages manager.
|
||||||
*
|
*
|
||||||
@ -117,7 +130,8 @@ public class Messages {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (defaultConfiguration == null) {
|
if (defaultConfiguration == null) {
|
||||||
defaultConfiguration = YamlConfiguration.loadConfiguration(defaultFile);
|
InputStream stream = Messages.class.getResourceAsStream(defaultFile);
|
||||||
|
defaultConfiguration = YamlConfiguration.loadConfiguration(new InputStreamReader(stream));
|
||||||
}
|
}
|
||||||
String message = defaultConfiguration.getString(code);
|
String message = defaultConfiguration.getString(code);
|
||||||
return message == null ? getDefaultErrorMessage(code) : message;
|
return message == null ? getDefaultErrorMessage(code) : message;
|
||||||
|
@ -64,15 +64,16 @@ public class AsynchronousJoin {
|
|||||||
final String ip = plugin.getIP(player);
|
final String ip = plugin.getIP(player);
|
||||||
|
|
||||||
|
|
||||||
if (Settings.isAllowRestrictedIp && !isNameRestricted(name, ip, player.getAddress().getHostName())) {
|
if (Settings.isAllowRestrictedIp && isNameRestricted(name, ip, player.getAddress().getHostName())) {
|
||||||
sched.scheduleSyncDelayedTask(plugin, new Runnable() {
|
sched.scheduleSyncDelayedTask(plugin, new Runnable() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true);
|
AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true);
|
||||||
player.kickPlayer(m.retrieveSingle(MessageKey.NOT_OWNER_ERROR));
|
player.kickPlayer(m.retrieveSingle(MessageKey.NOT_OWNER_ERROR));
|
||||||
if (Settings.banUnsafeIp)
|
if (Settings.banUnsafeIp) {
|
||||||
plugin.getServer().banIP(ip);
|
plugin.getServer().banIP(ip);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
|
@ -220,7 +220,7 @@ public class AsynchronousLogin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void displayOtherAccounts(PlayerAuth auth) {
|
private void displayOtherAccounts(PlayerAuth auth) {
|
||||||
if (!Settings.displayOtherAccounts || auth == null) {
|
if (!Settings.displayOtherAccounts || auth == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,8 @@ package fr.xephi.authme.process.login;
|
|||||||
|
|
||||||
import fr.xephi.authme.settings.NewSetting;
|
import fr.xephi.authme.settings.NewSetting;
|
||||||
import fr.xephi.authme.settings.properties.HooksSettings;
|
import fr.xephi.authme.settings.properties.HooksSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
@ -92,7 +94,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void restoreSpeedEffects() {
|
private void restoreSpeedEffects() {
|
||||||
if (Settings.isRemoveSpeedEnabled) {
|
if (settings.getProperty(RestrictionSettings.REMOVE_SPEED)) {
|
||||||
player.setWalkSpeed(0.2F);
|
player.setWalkSpeed(0.2F);
|
||||||
player.setFlySpeed(0.1F);
|
player.setFlySpeed(0.1F);
|
||||||
}
|
}
|
||||||
@ -173,19 +175,19 @@ public class ProcessSyncPlayerLogin implements Runnable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
restoreSpeedEffects();
|
restoreSpeedEffects();
|
||||||
if (Settings.applyBlindEffect) {
|
if (settings.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
|
||||||
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
player.removePotionEffect(PotionEffectType.BLINDNESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The Login event now fires (as intended) after everything is processed
|
// The Login event now fires (as intended) after everything is processed
|
||||||
Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player));
|
Bukkit.getServer().getPluginManager().callEvent(new LoginEvent(player));
|
||||||
player.saveData();
|
player.saveData();
|
||||||
if (Settings.bungee) {
|
if (settings.getProperty(HooksSettings.BUNGEECORD)) {
|
||||||
sendBungeeMessage();
|
sendBungeeMessage();
|
||||||
}
|
}
|
||||||
// Login is finish, display welcome message if we use email registration
|
// Login is done, display welcome message
|
||||||
if (Settings.useWelcomeMessage && Settings.emailRegistration) {
|
if (settings.getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
|
||||||
if (Settings.broadcastWelcomeMessage) {
|
if (settings.getProperty(RegistrationSettings.BROADCAST_WELCOME_MESSAGE)) {
|
||||||
for (String s : settings.getWelcomeMessage()) {
|
for (String s : settings.getWelcomeMessage()) {
|
||||||
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
|
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
|
||||||
}
|
}
|
||||||
|
@ -98,7 +98,7 @@ public class AsyncRegister {
|
|||||||
private void emailRegister() {
|
private void emailRegister() {
|
||||||
if (Settings.getmaxRegPerEmail > 0
|
if (Settings.getmaxRegPerEmail > 0
|
||||||
&& !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|
&& !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);
|
m.send(player, MessageKey.MAX_REGISTER_EXCEEDED);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +113,7 @@ public class PasswordSecurity {
|
|||||||
*/
|
*/
|
||||||
private static EncryptionMethod initializeEncryptionMethodWithoutEvent(HashAlgorithm algorithm) {
|
private static EncryptionMethod initializeEncryptionMethodWithoutEvent(HashAlgorithm algorithm) {
|
||||||
try {
|
try {
|
||||||
return HashAlgorithm.CUSTOM.equals(algorithm)
|
return HashAlgorithm.CUSTOM.equals(algorithm) || HashAlgorithm.PLAINTEXT.equals(algorithm)
|
||||||
? null
|
? null
|
||||||
: algorithm.getClazz().newInstance();
|
: algorithm.getClazz().newInstance();
|
||||||
} catch (InstantiationException | IllegalAccessException e) {
|
} catch (InstantiationException | IllegalAccessException e) {
|
||||||
|
@ -11,7 +11,7 @@ import fr.xephi.authme.security.crypts.description.Usage;
|
|||||||
* and store the salt with the hash itself.
|
* and store the salt with the hash itself.
|
||||||
*/
|
*/
|
||||||
@Recommendation(Usage.ACCEPTABLE)
|
@Recommendation(Usage.ACCEPTABLE)
|
||||||
@HasSalt(SaltType.TEXT) // See saltLength() for length
|
@HasSalt(SaltType.TEXT) // See getSaltLength() for length
|
||||||
public abstract class HexSaltedMethod implements EncryptionMethod {
|
public abstract class HexSaltedMethod implements EncryptionMethod {
|
||||||
|
|
||||||
public abstract int getSaltLength();
|
public abstract int getSaltLength();
|
||||||
|
@ -82,4 +82,13 @@ public abstract class CustomConfiguration extends YamlConfiguration {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean containsAll(String... paths) {
|
||||||
|
for (String path : paths) {
|
||||||
|
if (!contains(path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ import org.yaml.snakeyaml.Yaml;
|
|||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
@ -110,18 +109,12 @@ public class NewSetting {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the default messages file within the JAR that should contain all messages.
|
* Return the path to the default messages file within the JAR.
|
||||||
*
|
*
|
||||||
* @return The default messages file, or {@code null} if it could not be retrieved
|
* @return The default messages file path
|
||||||
*/
|
*/
|
||||||
public File getDefaultMessagesFile() {
|
public String getDefaultMessagesFile() {
|
||||||
String defaultFilePath = "/messages/messages_en.yml";
|
return "/messages/messages_en.yml";
|
||||||
URL url = NewSetting.class.getResource(defaultFilePath);
|
|
||||||
if (url == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
File file = new File(url.getFile());
|
|
||||||
return file.exists() ? file : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getEmailMessage() {
|
public String getEmailMessage() {
|
||||||
|
@ -5,6 +5,7 @@ import fr.xephi.authme.datasource.DataSourceType;
|
|||||||
import fr.xephi.authme.security.HashAlgorithm;
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
import fr.xephi.authme.settings.domain.Property;
|
import fr.xephi.authme.settings.domain.Property;
|
||||||
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
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.PluginSettings;
|
||||||
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
import fr.xephi.authme.settings.properties.RegistrationSettings;
|
||||||
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
import fr.xephi.authme.settings.properties.RestrictionSettings;
|
||||||
@ -144,8 +145,6 @@ public final class Settings {
|
|||||||
denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
|
denyTabcompleteBeforeLogin = load(RestrictionSettings.DENY_TABCOMPLETE_BEFORE_LOGIN);
|
||||||
hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN);
|
hideTablistBeforeLogin = load(RestrictionSettings.HIDE_TABLIST_BEFORE_LOGIN);
|
||||||
|
|
||||||
plugin.checkProtocolLib();
|
|
||||||
|
|
||||||
passwordMaxLength = load(SecuritySettings.MAX_PASSWORD_LENGTH);
|
passwordMaxLength = load(SecuritySettings.MAX_PASSWORD_LENGTH);
|
||||||
backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
|
backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
|
||||||
isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
|
isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
|
||||||
@ -176,7 +175,7 @@ public final class Settings {
|
|||||||
emailRegistration = configFile.getBoolean("settings.registration.enableEmailRegistrationSystem", false);
|
emailRegistration = configFile.getBoolean("settings.registration.enableEmailRegistrationSystem", false);
|
||||||
saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8);
|
saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8);
|
||||||
getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1);
|
getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1);
|
||||||
multiverse = configFile.getBoolean("Hooks.multiverse", true);
|
multiverse = load(HooksSettings.MULTIVERSE);
|
||||||
bungee = configFile.getBoolean("Hooks.bungeecord", false);
|
bungee = configFile.getBoolean("Hooks.bungeecord", false);
|
||||||
getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds");
|
getForcedWorlds = configFile.getStringList("settings.restrictions.ForceSpawnOnTheseWorlds");
|
||||||
banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false);
|
banUnsafeIp = configFile.getBoolean("settings.restrictions.banUnsafedIP", false);
|
||||||
@ -213,7 +212,7 @@ public final class Settings {
|
|||||||
broadcastWelcomeMessage = configFile.getBoolean("settings.broadcastWelcomeMessage", false);
|
broadcastWelcomeMessage = configFile.getBoolean("settings.broadcastWelcomeMessage", false);
|
||||||
forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false);
|
forceRegKick = configFile.getBoolean("settings.registration.forceKickAfterRegister", false);
|
||||||
forceRegLogin = configFile.getBoolean("settings.registration.forceLoginAfterRegister", 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);
|
getMaxLoginPerIp = configFile.getInt("settings.restrictions.maxLoginPerIp", 0);
|
||||||
getMaxJoinPerIp = configFile.getInt("settings.restrictions.maxJoinPerIp", 0);
|
getMaxJoinPerIp = configFile.getInt("settings.restrictions.maxJoinPerIp", 0);
|
||||||
checkVeryGames = configFile.getBoolean("VeryGames.enableIpCheck", false);
|
checkVeryGames = configFile.getBoolean("VeryGames.enableIpCheck", false);
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
package fr.xephi.authme.settings;
|
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.Bukkit;
|
||||||
import org.bukkit.Location;
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
@ -12,13 +18,17 @@ import java.io.File;
|
|||||||
public class Spawn extends CustomConfiguration {
|
public class Spawn extends CustomConfiguration {
|
||||||
|
|
||||||
private static Spawn spawn;
|
private static Spawn spawn;
|
||||||
|
private static String[] spawnPriority;
|
||||||
|
|
||||||
public Spawn() {
|
private Spawn() {
|
||||||
super(new File("." + File.separator + "plugins" + File.separator + "AuthMe" + File.separator + "spawn.yml"));
|
super(new File(Settings.PLUGIN_FOLDER, "spawn.yml"));
|
||||||
spawn = this;
|
|
||||||
load();
|
load();
|
||||||
save();
|
save();
|
||||||
saveDefault();
|
spawnPriority = Settings.spawnPriority.split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void reload() {
|
||||||
|
spawn = new Spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -33,111 +43,106 @@ public class Spawn extends CustomConfiguration {
|
|||||||
return spawn;
|
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) {
|
public boolean setSpawn(Location location) {
|
||||||
try {
|
if (location == null || location.getWorld() == null) {
|
||||||
set("spawn.world", location.getWorld().getName());
|
|
||||||
set("spawn.x", location.getX());
|
|
||||||
set("spawn.y", location.getY());
|
|
||||||
set("spawn.z", location.getZ());
|
|
||||||
set("spawn.yaw", location.getYaw());
|
|
||||||
set("spawn.pitch", location.getPitch());
|
|
||||||
save();
|
|
||||||
return true;
|
|
||||||
} catch (NullPointerException npe) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
set("spawn.world", location.getWorld().getName());
|
||||||
|
set("spawn.x", location.getX());
|
||||||
|
set("spawn.y", location.getY());
|
||||||
|
set("spawn.z", location.getZ());
|
||||||
|
set("spawn.yaw", location.getYaw());
|
||||||
|
set("spawn.pitch", location.getPitch());
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method setFirstSpawn.
|
|
||||||
*
|
|
||||||
* @param location Location
|
|
||||||
*
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
public boolean setFirstSpawn(Location location) {
|
public boolean setFirstSpawn(Location location) {
|
||||||
try {
|
if (location == null || location.getWorld() == null) {
|
||||||
set("firstspawn.world", location.getWorld().getName());
|
|
||||||
set("firstspawn.x", location.getX());
|
|
||||||
set("firstspawn.y", location.getY());
|
|
||||||
set("firstspawn.z", location.getZ());
|
|
||||||
set("firstspawn.yaw", location.getYaw());
|
|
||||||
set("firstspawn.pitch", location.getPitch());
|
|
||||||
save();
|
|
||||||
return true;
|
|
||||||
} catch (NullPointerException npe) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
set("firstspawn.world", location.getWorld().getName());
|
||||||
|
set("firstspawn.x", location.getX());
|
||||||
|
set("firstspawn.y", location.getY());
|
||||||
|
set("firstspawn.z", location.getZ());
|
||||||
|
set("firstspawn.yaw", location.getYaw());
|
||||||
|
set("firstspawn.pitch", location.getPitch());
|
||||||
|
save();
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method getLocation.
|
|
||||||
*
|
|
||||||
* @return Location
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public Location getLocation() {
|
|
||||||
return getSpawn();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Method getSpawn.
|
|
||||||
*
|
|
||||||
* @return Location
|
|
||||||
*/
|
|
||||||
public Location getSpawn() {
|
public Location getSpawn() {
|
||||||
try {
|
if (containsAll("spawn.world", "spawn.x", "spawn.y", "spawn.z", "spawn.yaw", "spawn.pitch")) {
|
||||||
if (this.getString("spawn.world").isEmpty() || this.getString("spawn.world").equals(""))
|
String worldName = getString("spawn.world");
|
||||||
return null;
|
World world = Bukkit.getWorld(worldName);
|
||||||
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")));
|
if (!StringUtils.isEmpty(worldName) && world != null) {
|
||||||
return location;
|
return new Location(
|
||||||
} catch (NullPointerException | NumberFormatException npe) {
|
world, getDouble("spawn.x"), getDouble("spawn.y"), getDouble("spawn.z"),
|
||||||
return null;
|
Float.parseFloat(getString("spawn.yaw")), Float.parseFloat(getString("spawn.pitch"))
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Method getFirstSpawn.
|
|
||||||
*
|
|
||||||
* @return Location
|
|
||||||
*/
|
|
||||||
public Location getFirstSpawn() {
|
public Location getFirstSpawn() {
|
||||||
try {
|
if (containsAll("firstspawn.world", "firstspawn.x", "firstspawn.y",
|
||||||
if (this.getString("firstspawn.world").isEmpty() || this.getString("firstspawn.world").equals(""))
|
"firstspawn.z", "firstspawn.yaw", "firstspawn.pitch")) {
|
||||||
return null;
|
String worldName = getString("firstspawn.world");
|
||||||
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")));
|
World world = Bukkit.getWorld(worldName);
|
||||||
return location;
|
if (!StringUtils.isEmpty(worldName) && world != null) {
|
||||||
} catch (NullPointerException | NumberFormatException npe) {
|
return new Location(
|
||||||
return null;
|
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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@ public class BackupSettings implements SettingsClass {
|
|||||||
public static final Property<Boolean> ON_SERVER_STOP =
|
public static final Property<Boolean> ON_SERVER_STOP =
|
||||||
newProperty("BackupSystem.OnServerStop", true);
|
newProperty("BackupSystem.OnServerStop", true);
|
||||||
|
|
||||||
@Comment(" Windows only mysql installation Path")
|
@Comment("Windows only mysql installation Path")
|
||||||
public static final Property<String> MYSQL_WINDOWS_PATH =
|
public static final Property<String> MYSQL_WINDOWS_PATH =
|
||||||
newProperty("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
|
newProperty("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
|
||||||
|
|
||||||
|
72
src/main/java/fr/xephi/authme/util/MigrationService.java
Normal file
72
src/main/java/fr/xephi/authme/util/MigrationService.java
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
package fr.xephi.authme.util;
|
||||||
|
|
||||||
|
import fr.xephi.authme.ConsoleLogger;
|
||||||
|
import fr.xephi.authme.cache.auth.PlayerAuth;
|
||||||
|
import fr.xephi.authme.converter.ForceFlatToSqlite;
|
||||||
|
import fr.xephi.authme.datasource.DataSource;
|
||||||
|
import fr.xephi.authme.datasource.DataSourceType;
|
||||||
|
import fr.xephi.authme.security.HashAlgorithm;
|
||||||
|
import fr.xephi.authme.security.crypts.HashedPassword;
|
||||||
|
import fr.xephi.authme.security.crypts.SHA256;
|
||||||
|
import fr.xephi.authme.settings.NewSetting;
|
||||||
|
import fr.xephi.authme.settings.properties.DatabaseSettings;
|
||||||
|
import fr.xephi.authme.settings.properties.SecuritySettings;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Migrations to perform during the initialization of AuthMe.
|
||||||
|
*/
|
||||||
|
public final class MigrationService {
|
||||||
|
|
||||||
|
private MigrationService() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hash all passwords to SHA256 and updated the setting if the password hash is set to the deprecated PLAINTEXT.
|
||||||
|
*
|
||||||
|
* @param settings The settings instance
|
||||||
|
* @param dataSource The data source
|
||||||
|
* @param authmeSha256 Instance to the AuthMe SHA256 encryption method implementation
|
||||||
|
*/
|
||||||
|
public static void changePlainTextToSha256(NewSetting settings, DataSource dataSource,
|
||||||
|
SHA256 authmeSha256) {
|
||||||
|
if (HashAlgorithm.PLAINTEXT == settings.getProperty(SecuritySettings.PASSWORD_HASH)) {
|
||||||
|
ConsoleLogger.showError("Your HashAlgorithm has been detected as plaintext and is now deprecated;"
|
||||||
|
+ " it will be changed and hashed now to the AuthMe default hashing method");
|
||||||
|
List<PlayerAuth> allAuths = dataSource.getAllAuths();
|
||||||
|
for (PlayerAuth auth : allAuths) {
|
||||||
|
HashedPassword hashedPassword = authmeSha256.computeHash(
|
||||||
|
auth.getPassword().getHash(), auth.getNickname());
|
||||||
|
auth.setPassword(hashedPassword);
|
||||||
|
dataSource.updatePassword(auth);
|
||||||
|
}
|
||||||
|
settings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256);
|
||||||
|
settings.save();
|
||||||
|
ConsoleLogger.info("Migrated " + allAuths.size() + " accounts from plaintext to SHA256");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the data source from the deprecated FLATFILE type to SQLITE.
|
||||||
|
*
|
||||||
|
* @param settings The settings instance
|
||||||
|
* @param dataSource The data source
|
||||||
|
* @return The converted datasource (SQLite), or null if no migration was necessary
|
||||||
|
*/
|
||||||
|
public static DataSource convertFlatfileToSqlite(NewSetting settings, DataSource dataSource) {
|
||||||
|
if (DataSourceType.FILE == settings.getProperty(DatabaseSettings.BACKEND)) {
|
||||||
|
ConsoleLogger.showError("FlatFile backend has been detected and is now deprecated; it will be changed "
|
||||||
|
+ "to SQLite... Connection will be impossible until conversion is done!");
|
||||||
|
ForceFlatToSqlite converter = new ForceFlatToSqlite(dataSource, settings);
|
||||||
|
DataSource result = converter.run();
|
||||||
|
if (result == null) {
|
||||||
|
throw new IllegalStateException("Error during conversion from flatfile to SQLite");
|
||||||
|
} else {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -58,6 +58,7 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично изключ
|
|||||||
# TODO password_error_unsafe: '&cThe chosen password isn''t safe, 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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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"'
|
wrong_captcha: '&cCaptcha inválido, por favor escreva "/captcha THE_CAPTCHA"'
|
||||||
valid_captcha: '&2Código do captcha correto!'
|
valid_captcha: '&2Código do captcha correto!'
|
||||||
kick_forvip: '&3Um vip entrou no servidor!'
|
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_add: '&cUse: /email add <email> <email>'
|
||||||
usage_email_change: '&cUse: /email change <email antigo> <email novo>'
|
usage_email_change: '&cUse: /email change <email antigo> <email novo>'
|
||||||
usage_email_recovery: '&cUse: /email recovery <email>'
|
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_changed: '&2Email mudado com sucesso!'
|
||||||
email_send: '&2Email de recuperação enviado 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:'
|
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_enabled: '&4[AntiBotService] AntiBot ativado devido ao grande número de conexões!'
|
||||||
antibot_auto_disabled: '&2[AntiBotService] AntiBot desativado após %m minutos!'
|
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. Você pode escanear ele daqui %url'
|
||||||
two_factor_create: '&2Seu código secreto é %code'
|
email_already_used: '&4Este endereço de email já está em uso'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
not_owner_error: 'Você não é o dono desta conta. Por favor, tente outro nome!'
|
||||||
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
invalid_name_case: 'Você deve entrar usando %valid, não %invalid.'
|
||||||
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -60,4 +60,5 @@ kick_antibot: 'AntiBotMod ist aktiviert! Bitte warte einige Minuten, bevor du di
|
|||||||
# TODO two_factor_create: Missing tag %url
|
# TODO two_factor_create: Missing tag %url
|
||||||
two_factor_create: '&2Dein geheimer Code ist %code'
|
two_factor_create: '&2Dein geheimer Code ist %code'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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'
|
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'
|
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!'
|
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.'
|
||||||
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 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 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 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 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 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!'
|
# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
|
||||||
|
@ -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 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 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 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 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_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
|
||||||
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
|
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
|
||||||
|
@ -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
|
# TODO two_factor_create: Missing tag %url
|
||||||
two_factor_create: '&2Votre code secret est %code'
|
two_factor_create: '&2Votre code secret est %code'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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!'
|
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.'
|
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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -55,6 +55,7 @@ antibot_auto_enabled: '&4[AntiBotService] AntiBot diaktifkan dikarenakan banyak
|
|||||||
antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!'
|
antibot_auto_disabled: '&2[AntiBotService] AntiBot dimatikan setelah %m menit!'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 country_banned: '&4Your country is banned from this server!'
|
||||||
# TODO usage_unreg: '&cUsage: /unregister <password>'
|
# TODO usage_unreg: '&cUsage: /unregister <password>'
|
||||||
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
|
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
|
||||||
|
@ -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.'
|
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'
|
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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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_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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 password_error_unsafe: '&cThe chosen password isn''t safe, please choose another one...'
|
||||||
# TODO new_email_invalid: '&cInvalid new email, try again!'
|
# 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 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 email_send: '&2Recovery email sent successfully! Please check your email inbox!'
|
||||||
# TODO usage_email_recovery: '&cUsage: /email recovery <Email>'
|
# TODO usage_email_recovery: '&cUsage: /email recovery <Email>'
|
||||||
# TODO email_confirm: '&cPlease confirm your email address!'
|
# TODO email_confirm: '&cPlease confirm your email address!'
|
||||||
|
@ -59,5 +59,6 @@ kick_antibot: 'AntiBot is aangezet! Wacht alsjeblieft enkele minuten voor je met
|
|||||||
two_factor_create: '&2Je geheime code is %code'
|
two_factor_create: '&2Je geheime code is %code'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 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 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 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 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_enabled: '&4[AntiBotService] AntiBot enabled due to the huge number of connections!'
|
||||||
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
|
# TODO antibot_auto_disabled: '&2[AntiBotService] AntiBot disabled disabled after %m minutes!'
|
||||||
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -58,5 +58,6 @@ antibot_auto_disabled: '&a[AuthMe] AntiBot-режим автоматичски
|
|||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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'
|
regex: '&cTvoje meno obsahuje zakázané znaky. Povolené znaky: REG_EX'
|
||||||
add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"'
|
add_email: '&cPridaj svoj e-mail príkazom "/email add email zopakujEmail"'
|
||||||
recovery_email: '&cZabudol si heslo? Pouzi príkaz /email recovery <tvojEmail>'
|
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 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 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 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 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 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 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 usage_email_add: '&cUsage: /email add <email> <confirmEmail>'
|
||||||
# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
|
# TODO wrong_captcha: '&cWrong captcha, please type "/captcha THE_CAPTCHA" into the chat!'
|
||||||
# TODO valid_captcha: '&2Captcha code solved correctly!'
|
# TODO valid_captcha: '&2Captcha code solved correctly!'
|
||||||
# TODO two_factor_create: '&2Your secret code is %code. You can scan it from here %url'
|
# 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -59,5 +59,6 @@ antibot_auto_disabled: '[AuthMe] AntiBotMod автоматично вимкну
|
|||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -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 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -63,5 +63,6 @@ antibot_auto_disabled: '&8[&6用戶系統&8] 防止機械人程序檢查到不
|
|||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -63,4 +63,5 @@ email_already_used: '&4邮箱已被使用'
|
|||||||
kick_antibot: '[AuthMe] 防机器人程序已启用 !请稍等几分钟後才再次进入服务器'
|
kick_antibot: '[AuthMe] 防机器人程序已启用 !请稍等几分钟後才再次进入服务器'
|
||||||
email_exists: '&c恢复邮件已发送 ! 你可以丢弃它然後使用以下的指令来发送新的邮件:'
|
email_exists: '&c恢复邮件已发送 ! 你可以丢弃它然後使用以下的指令来发送新的邮件:'
|
||||||
two_factor_create: '&2你的代码是 %code,你可以使用 %url 来扫描'
|
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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -63,5 +63,6 @@ antibot_auto_enabled: '&b【AuthMe】&6AntiBotMod已自動啟用!'
|
|||||||
antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉'
|
antibot_auto_disabled: '&b【AuthMe】&6AntiBotMod將會於 &c%m &6分鐘後自動關閉'
|
||||||
# TODO email_already_used: '&4The email address is already being used'
|
# 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 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 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!'
|
# TODO not_owner_error: 'You are not the owner of this account. Please try another name!'
|
@ -2,6 +2,8 @@ package fr.xephi.authme;
|
|||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AuthMe test utilities.
|
* AuthMe test utilities.
|
||||||
@ -18,11 +20,31 @@ public final class TestHelper {
|
|||||||
* @return The project file
|
* @return The project file
|
||||||
*/
|
*/
|
||||||
public static File getJarFile(String path) {
|
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);
|
URL url = TestHelper.class.getResource(path);
|
||||||
if (url == null) {
|
if (url == null) {
|
||||||
throw new IllegalStateException("File '" + path + "' could not be loaded");
|
throw new IllegalStateException("File '" + path + "' could not be loaded");
|
||||||
}
|
}
|
||||||
return new File(url.getFile());
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,204 @@
|
|||||||
|
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.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.hasSize;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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"));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
84
src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
Normal file
84
src/test/java/fr/xephi/authme/datasource/AuthMeMatchers.java
Normal 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));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -50,8 +50,7 @@ public class MessagesIntegrationTest {
|
|||||||
@Before
|
@Before
|
||||||
public void setUpMessages() {
|
public void setUpMessages() {
|
||||||
File testFile = TestHelper.getJarFile(YML_TEST_FILE);
|
File testFile = TestHelper.getJarFile(YML_TEST_FILE);
|
||||||
File defaultFile = TestHelper.getJarFile(YML_DEFAULT_TEST_FILE);
|
messages = new Messages(testFile, YML_DEFAULT_TEST_FILE);
|
||||||
messages = new Messages(testFile, defaultFile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -267,4 +266,16 @@ public class MessagesIntegrationTest {
|
|||||||
assertThat(messages.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE),
|
assertThat(messages.retrieveSingle(MessageKey.MUST_REGISTER_MESSAGE),
|
||||||
equalTo("Message from default file"));
|
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"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
|
import org.mockito.internal.stubbing.answers.ReturnsArgumentAt;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
@ -55,17 +56,19 @@ public class NewSettingTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldReturnDefaultFile() {
|
public void shouldReturnDefaultFile() throws IOException {
|
||||||
// given
|
// given
|
||||||
YamlConfiguration configuration = mock(YamlConfiguration.class);
|
YamlConfiguration configuration = mock(YamlConfiguration.class);
|
||||||
NewSetting settings = new NewSetting(configuration, null, null);
|
NewSetting settings = new NewSetting(configuration, null, null);
|
||||||
|
|
||||||
// when
|
// when
|
||||||
File defaultFile = settings.getDefaultMessagesFile();
|
String defaultFile = settings.getDefaultMessagesFile();
|
||||||
|
|
||||||
// then
|
// then
|
||||||
assertThat(defaultFile, not(nullValue()));
|
assertThat(defaultFile, not(nullValue()));
|
||||||
assertThat(defaultFile.exists(), equalTo(true));
|
InputStream stream = this.getClass().getResourceAsStream(defaultFile);
|
||||||
|
assertThat(stream, not(nullValue()));
|
||||||
|
assertThat(stream.read(), not(equalTo(0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static <T> void setReturnValue(YamlConfiguration config, Property<T> property, T value) {
|
private static <T> void setReturnValue(YamlConfiguration config, Property<T> property, T value) {
|
||||||
|
@ -35,7 +35,7 @@ public final class TestConfiguration implements SettingsClass {
|
|||||||
newProperty(PropertyType.STRING_LIST, "features.boring.colors");
|
newProperty(PropertyType.STRING_LIST, "features.boring.colors");
|
||||||
|
|
||||||
public static final Property<Integer> DUST_LEVEL =
|
public static final Property<Integer> DUST_LEVEL =
|
||||||
newProperty(PropertyType.INTEGER, "features.boring.dustLevel", -1);
|
newProperty("features.boring.dustLevel", -1);
|
||||||
|
|
||||||
public static final Property<Boolean> USE_COOL_FEATURES =
|
public static final Property<Boolean> USE_COOL_FEATURES =
|
||||||
newProperty("features.cool.enabled", false);
|
newProperty("features.cool.enabled", false);
|
||||||
|
22
src/test/resources/datasource-integration/sql-initialize.sql
Normal file
22
src/test/resources/datasource-integration/sql-initialize.sql
Normal 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');
|
Loading…
Reference in New Issue
Block a user