Merge pull request #92 from AuthMe-Team/450-new-settings-rewrite

450 new settings rewrite
This commit is contained in:
ljacqu 2016-02-06 17:27:40 +01:00
commit ad9625bb4e
72 changed files with 1390 additions and 1264 deletions

View File

@ -97,6 +97,7 @@
<directory>src/main/resources/</directory>
<includes>
<include>email.html</include>
<include>welcome.txt</include>
</includes>
</resource>
<resource>

View File

@ -13,6 +13,7 @@ import java.util.logging.Logger;
import com.google.common.base.Charsets;
import com.google.common.io.Resources;
import fr.xephi.authme.settings.SettingsMigrationService;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
@ -60,7 +61,6 @@ import fr.xephi.authme.listener.AuthMePlayerListener18;
import fr.xephi.authme.listener.AuthMeServerListener;
import fr.xephi.authme.listener.AuthMeTabCompletePacketAdapter;
import fr.xephi.authme.mail.SendMailSSL;
import fr.xephi.authme.modules.ModuleManager;
import fr.xephi.authme.output.ConsoleFilter;
import fr.xephi.authme.output.Log4JFilter;
import fr.xephi.authme.output.MessageKey;
@ -71,15 +71,25 @@ import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.OtherAccounts;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.Spawn;
import fr.xephi.authme.settings.custom.NewSetting;
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.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.GeoLiteAPI;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.Wrapper;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER;
/**
* The AuthMe main class.
*/
@ -103,7 +113,6 @@ public class AuthMe extends JavaPlugin {
private NewSetting newSettings;
private Messages messages;
private JsonCache playerBackup;
private ModuleManager moduleManager;
private PasswordSecurity passwordSecurity;
private DataSource database;
@ -169,15 +178,6 @@ public class AuthMe extends JavaPlugin {
return pluginBuildNumber;
}
/**
* Get the plugin's Settings.
*
* @return Plugin's settings.
*/
public Settings getSettings() {
return settings;
}
/**
* Get the Messages instance.
*
@ -208,19 +208,28 @@ public class AuthMe extends JavaPlugin {
// Set various instances
server = getServer();
plugin = this;
ConsoleLogger.setLogger(getLogger());
setPluginInfos();
// Load settings and custom configurations, if it fails, stop the server due to security reasons.
newSettings = createNewSetting();
if (newSettings == null) {
ConsoleLogger.showError("Could not load configuration. Aborting.");
server.shutdown();
return;
}
ConsoleLogger.setLoggingOptions(newSettings.getProperty(SecuritySettings.USE_LOGGING),
new File(getDataFolder(), "authme.log"));
// Old settings manager
if (!loadSettings()) {
server.shutdown();
setEnabled(false);
return;
}
newSettings = createNewSetting();
// Set up messages & password security
messages = Messages.getInstance();
messages = new Messages(newSettings.getMessagesFile());
// Connect to the database and setup tables
try {
@ -239,15 +248,11 @@ public class AuthMe extends JavaPlugin {
permsMan = initializePermissionsManager();
commandHandler = initializeCommandHandler(permsMan, messages, passwordSecurity, newSettings);
// Set up the module manager
setupModuleManager();
// Setup otherAccounts file
this.otherAccounts = OtherAccounts.getInstance();
// Set up Metrics
final MetricsStarter metrics = new MetricsStarter(this);
metrics.setupMetrics();
MetricsStarter.setupMetrics(plugin, newSettings);
// Set console filter
setupConsoleFilter();
@ -277,7 +282,7 @@ public class AuthMe extends JavaPlugin {
// End of Hooks
// Do a backup on start
new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.START);
new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.START);
// Setup the inventory backup
@ -290,7 +295,7 @@ public class AuthMe extends JavaPlugin {
setupApi();
// Set up the management
management = new Management(this);
management = new Management(this, newSettings);
// Set up the BungeeCord hook
setupBungeeCordHook();
@ -319,32 +324,14 @@ public class AuthMe extends JavaPlugin {
ConsoleLogger.info("AuthMe " + this.getDescription().getVersion() + " correctly enabled!");
}
/**
* Set up the module manager.
*/
private void setupModuleManager() {
// TODO: Clean this up!
// TODO: split the plugin in more modules
// TODO: log number of loaded modules
// Define the module manager instance
moduleManager = new ModuleManager(this);
// Load the modules
// int loaded = moduleManager.loadModules();
}
/**
* Set up the mail API, if enabled.
*/
private void setupMailApi() {
// Make sure the mail API is enabled
if (Settings.getmailAccount.isEmpty() || Settings.getmailPassword.isEmpty()) {
return;
if (!newSettings.getProperty(MAIL_ACCOUNT).isEmpty() && !newSettings.getProperty(MAIL_PASSWORD).isEmpty()) {
this.mail = new SendMailSSL(this, newSettings);
}
// Set up the mail API
this.mail = new SendMailSSL(this);
}
/**
@ -352,12 +339,13 @@ public class AuthMe extends JavaPlugin {
*/
private void showSettingsWarnings() {
// Force single session disabled
if (!Settings.isForceSingleSessionEnabled) {
if (!newSettings.getProperty(RestrictionSettings.FORCE_SINGLE_SESSION)) {
ConsoleLogger.showError("WARNING!!! By disabling ForceSingleSession, your server protection is inadequate!");
}
// Session timeout disabled
if (Settings.getSessionTimeout == 0 && Settings.isSessionsEnabled) {
if (newSettings.getProperty(PluginSettings.SESSIONS_TIMEOUT) == 0
&& newSettings.getProperty(PluginSettings.SESSIONS_ENABLED)) {
ConsoleLogger.showError("WARNING!!! You set session timeout to 0, this may cause security issues!");
}
}
@ -412,7 +400,7 @@ public class AuthMe extends JavaPlugin {
* Set up the BungeeCord hook.
*/
private void setupBungeeCordHook() {
if (Settings.bungee) {
if (newSettings.getProperty(HooksSettings.BUNGEECORD)) {
Bukkit.getMessenger().registerOutgoingPluginChannel(this, "BungeeCord");
Bukkit.getMessenger().registerIncomingPluginChannel(this, "BungeeCord", new BungeeCordMessage(this));
}
@ -420,7 +408,7 @@ public class AuthMe extends JavaPlugin {
private CommandHandler initializeCommandHandler(PermissionsManager permissionsManager, Messages messages,
PasswordSecurity passwordSecurity, NewSetting settings) {
HelpProvider helpProvider = new HelpProvider(permissionsManager);
HelpProvider helpProvider = new HelpProvider(permissionsManager, settings.getProperty(HELP_HEADER));
Set<CommandDescription> baseCommands = CommandInitializer.buildCommands();
CommandMapper mapper = new CommandMapper(baseCommands, permissionsManager);
CommandService commandService = new CommandService(
@ -448,7 +436,6 @@ public class AuthMe extends JavaPlugin {
private boolean loadSettings() {
try {
settings = new Settings(this);
Settings.reload();
return true;
} catch (Exception e) {
ConsoleLogger.logException("Can't load the configuration file... Something went wrong. "
@ -459,8 +446,10 @@ public class AuthMe extends JavaPlugin {
}
private NewSetting createNewSetting() {
File configFile = new File(getDataFolder() + "config.yml");
return new NewSetting(getConfig(), configFile);
File configFile = new File(getDataFolder(), "config.yml");
return SettingsMigrationService.copyFileFromResource(configFile, "config.yml")
? new NewSetting(configFile, getDataFolder())
: null;
}
/**
@ -491,11 +480,8 @@ public class AuthMe extends JavaPlugin {
}
// Do backup on stop if enabled
new PerformBackup(plugin).doBackup(PerformBackup.BackupCause.STOP);
// Unload modules
if (moduleManager != null) {
moduleManager.unloadModules();
if (newSettings != null) {
new PerformBackup(plugin, newSettings).doBackup(PerformBackup.BackupCause.STOP);
}
// Close the database
@ -522,7 +508,7 @@ public class AuthMe extends JavaPlugin {
database.close();
// Backend MYSQL - FILE - SQLITE - SQLITEHIKARI
boolean isSQLite = false;
switch (Settings.getDataSource) {
switch (newSettings.getProperty(DatabaseSettings.BACKEND)) {
case FILE:
database = new FlatFile();
break;
@ -551,7 +537,7 @@ public class AuthMe extends JavaPlugin {
if (Settings.getDataSource == DataSource.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);
ForceFlatToSqlite converter = new ForceFlatToSqlite(database, newSettings);
DataSource source = converter.run();
if (source != null) {
database = source;
@ -559,7 +545,7 @@ public class AuthMe extends JavaPlugin {
}
// TODO: Move this to another place maybe ?
if (Settings.getPasswordHash == HashAlgorithm.PLAINTEXT) {
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()) {
@ -568,11 +554,11 @@ public class AuthMe extends JavaPlugin {
auth.setPassword(hashedPassword);
database.updatePassword(auth);
}
Settings.setValue("settings.security.passwordHash", "SHA256");
Settings.reload();
newSettings.setProperty(SecuritySettings.PASSWORD_HASH, HashAlgorithm.SHA256);
newSettings.save();
}
if (Settings.isCachingEnabled) {
if (newSettings.getProperty(DatabaseSettings.USE_CACHING)) {
database = new CacheDataSource(database);
}
}
@ -663,24 +649,20 @@ public class AuthMe extends JavaPlugin {
// Check the presence of the ProtocolLib plugin
public void checkProtocolLib() {
if (!server.getPluginManager().isPluginEnabled("ProtocolLib")) {
if (Settings.protectInventoryBeforeLogInEnabled) {
ConsoleLogger.showError("WARNING!!! The protectInventory feature requires ProtocolLib! Disabling it...");
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) {
ConsoleLogger.showError("WARNING! The protectInventory feature requires ProtocolLib! Disabling it...");
Settings.protectInventoryBeforeLogInEnabled = false;
getSettings().set("settings.restrictions.ProtectInventoryBeforeLogIn", false);
newSettings.setProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN, false);
}
return;
}
if (Settings.protectInventoryBeforeLogInEnabled) {
if (inventoryProtector == null) {
inventoryProtector = new AuthMeInventoryPacketAdapter(this);
inventoryProtector.register();
}
} else {
if (inventoryProtector != null) {
inventoryProtector.unregister();
inventoryProtector = null;
}
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN) && inventoryProtector == null) {
inventoryProtector = new AuthMeInventoryPacketAdapter(this);
inventoryProtector.register();
} else if (inventoryProtector != null) {
inventoryProtector.unregister();
inventoryProtector = null;
}
if (tabComplete == null) {
tabComplete = new AuthMeTabCompletePacketAdapter(this);
@ -715,16 +697,14 @@ public class AuthMe extends JavaPlugin {
PlayerCache.getInstance().removePlayer(name);
}
// Select the player to kick when a vip player join the server when full
// Select the player to kick when a vip player joins the server when full
public Player generateKickPlayer(Collection<? extends Player> collection) {
Player player = null;
for (Player p : collection) {
if (!getPermissionsManager().hasPermission(p, PlayerPermission.IS_VIP)) {
player = p;
break;
for (Player player : collection) {
if (!getPermissionsManager().hasPermission(player, PlayerPermission.IS_VIP)) {
return player;
}
}
return player;
return null;
}
// Purge inactive players from the database, as defined in the configuration
@ -736,10 +716,7 @@ public class AuthMe extends JavaPlugin {
calendar.add(Calendar.DATE, -(Settings.purgeDelay));
long until = calendar.getTimeInMillis();
List<String> cleared = database.autoPurgeDatabase(until);
if (cleared == null) {
return;
}
if (cleared.isEmpty()) {
if (CollectionUtils.isEmpty(cleared)) {
return;
}
ConsoleLogger.info("AutoPurging the Database: " + cleared.size() + " accounts removed!");
@ -823,12 +800,12 @@ public class AuthMe extends JavaPlugin {
for (Player player : Utils.getOnlinePlayers()) {
if (player.isOnline()) {
String name = player.getName().toLowerCase();
if (database.isAuthAvailable(name))
if (PlayerCache.getInstance().isAuthenticated(name)) {
String email = database.getAuth(name).getEmail();
if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com"))
messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
if (database.isAuthAvailable(name) && PlayerCache.getInstance().isAuthenticated(name)) {
String email = database.getAuth(name).getEmail();
if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) {
messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
}
}
}
}
@ -836,18 +813,18 @@ public class AuthMe extends JavaPlugin {
}
public String replaceAllInfo(String message, Player player) {
int playersOnline = Utils.getOnlinePlayers().size();
message = message.replace("&", "\u00a7");
message = message.replace("{PLAYER}", player.getName());
message = message.replace("{ONLINE}", "" + playersOnline);
message = message.replace("{MAXPLAYERS}", "" + server.getMaxPlayers());
message = message.replace("{IP}", getIP(player));
message = message.replace("{LOGINS}", "" + PlayerCache.getInstance().getLogged());
message = message.replace("{WORLD}", player.getWorld().getName());
message = message.replace("{SERVER}", server.getServerName());
message = message.replace("{VERSION}", server.getBukkitVersion());
message = message.replace("{COUNTRY}", GeoLiteAPI.getCountryName(getIP(player)));
return message;
String playersOnline = Integer.toString(Utils.getOnlinePlayers().size());
return message
.replace("&", "\u00a7")
.replace("{PLAYER}", player.getName())
.replace("{ONLINE}", playersOnline)
.replace("{MAXPLAYERS}", Integer.toString(server.getMaxPlayers()))
.replace("{IP}", getIP(player))
.replace("{LOGINS}", Integer.toString(PlayerCache.getInstance().getLogged()))
.replace("{WORLD}", player.getWorld().getName())
.replace("{SERVER}", server.getServerName())
.replace("{VERSION}", server.getBukkitVersion())
.replace("{COUNTRY}", GeoLiteAPI.getCountryName(getIP(player)));
}
/**
@ -903,10 +880,6 @@ public class AuthMe extends JavaPlugin {
return count >= Settings.getMaxJoinPerIp;
}
public ModuleManager getModuleManager() {
return moduleManager;
}
/**
* Handle Bukkit commands.
*

View File

@ -1,16 +1,16 @@
package fr.xephi.authme;
import com.google.common.base.Throwables;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Wrapper;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;
/**
* The plugin's static logger.
@ -19,21 +19,31 @@ public final class ConsoleLogger {
private static final String NEW_LINE = System.getProperty("line.separator");
private static final DateFormat DATE_FORMAT = new SimpleDateFormat("[MM-dd HH:mm:ss]");
private static Wrapper wrapper = Wrapper.getInstance();
private static Logger logger;
private static boolean useLogging = false;
private static File logFile;
private ConsoleLogger() {
// Service class
}
public static void setLogger(Logger logger) {
ConsoleLogger.logger = logger;
}
public static void setLoggingOptions(boolean useLogging, File logFile) {
ConsoleLogger.useLogging = useLogging;
ConsoleLogger.logFile = logFile;
}
/**
* Print an info message.
*
* @param message String
*/
public static void info(String message) {
wrapper.getLogger().info(message);
if (Settings.useLogging) {
logger.info(message);
if (useLogging) {
writeLog(message);
}
}
@ -44,8 +54,8 @@ public final class ConsoleLogger {
* @param message String
*/
public static void showError(String message) {
wrapper.getLogger().warning(message);
if (Settings.useLogging) {
logger.warning(message);
if (useLogging) {
writeLog("ERROR: " + message);
}
}
@ -61,7 +71,7 @@ public final class ConsoleLogger {
dateTime = DATE_FORMAT.format(new Date());
}
try {
Files.write(Settings.LOG_FILE.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(),
Files.write(logFile.toPath(), (dateTime + ": " + message + NEW_LINE).getBytes(),
StandardOpenOption.APPEND,
StandardOpenOption.CREATE);
} catch (IOException ignored) {
@ -74,7 +84,7 @@ public final class ConsoleLogger {
* @param th The Throwable whose stack trace should be logged
*/
public static void writeStackTrace(Throwable th) {
if (Settings.useLogging) {
if (useLogging) {
writeLog(Throwables.getStackTraceAsString(th));
}
}

View File

@ -1,26 +1,25 @@
package fr.xephi.authme;
import java.io.IOException;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import org.mcstats.Metrics;
import org.mcstats.Metrics.Graph;
import fr.xephi.authme.settings.Settings;
import java.io.IOException;
public class MetricsStarter {
public AuthMe plugin;
public MetricsStarter(final AuthMe plugin) {
this.plugin = plugin;
private MetricsStarter() {
}
public void setupMetrics() {
public static void setupMetrics(AuthMe plugin, NewSetting settings) {
try {
final Metrics metrics = new Metrics(plugin);
final Graph messagesLanguage = metrics.createGraph("Messages Language");
messagesLanguage.addPlotter(new Metrics.Plotter(Settings.messagesLanguage) {
final Graph languageGraph = metrics.createGraph("Messages Language");
final String messagesLanguage = settings.getProperty(PluginSettings.MESSAGES_LANGUAGE);
languageGraph.addPlotter(new Metrics.Plotter(messagesLanguage) {
@Override
public int getValue() {
return 1;
@ -28,7 +27,8 @@ public class MetricsStarter {
});
final Graph databaseBackend = metrics.createGraph("Database Backend");
databaseBackend.addPlotter(new Metrics.Plotter(Settings.getDataSource.toString()) {
final String dataSource = settings.getProperty(DatabaseSettings.BACKEND).toString();
databaseBackend.addPlotter(new Metrics.Plotter(dataSource) {
@Override
public int getValue() {
return 1;
@ -37,7 +37,7 @@ public class MetricsStarter {
// Submit metrics
metrics.start();
} catch (final IOException e) {
} catch (IOException e) {
// Failed to submit the metrics data
ConsoleLogger.logException("Can't start Metrics! The plugin will work anyway...", e);
}

View File

@ -1,8 +1,17 @@
package fr.xephi.authme;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.BackupSettings;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.StringUtils;
import java.io.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.text.SimpleDateFormat;
import java.util.Date;
@ -10,54 +19,56 @@ import java.util.Date;
* The backup management class
*
* @author stefano
* @version $Revision: 1.0 $
*/
public class PerformBackup {
final SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
final String dateString = format.format(new Date());
private final String dbName = Settings.getMySQLDatabase;
private final String dbUserName = Settings.getMySQLUsername;
private final String dbPassword = Settings.getMySQLPassword;
private final String tblname = Settings.getMySQLTablename;
private final String path = AuthMe.getInstance().getDataFolder() + File.separator + "backups" + File.separator + "backup" + dateString;
private AuthMe instance;
private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd_HH-mm");
private final String dbName;
private final String dbUserName;
private final String dbPassword;
private final String tblname;
private final String path;
private final File dataFolder;
private final NewSetting settings;
/**
* Constructor for PerformBackup.
*
* @param instance AuthMe
*/
public PerformBackup(AuthMe instance) {
this.setInstance(instance);
public PerformBackup(AuthMe instance, NewSetting settings) {
this.dataFolder = instance.getDataFolder();
this.settings = settings;
this.dbName = settings.getProperty(DatabaseSettings.MYSQL_DATABASE);
this.dbUserName = settings.getProperty(DatabaseSettings.MYSQL_USERNAME);
this.dbPassword = settings.getProperty(DatabaseSettings.MYSQL_PASSWORD);
this.tblname = settings.getProperty(DatabaseSettings.MYSQL_TABLE);
String dateString = DATE_FORMAT.format(new Date());
this.path = StringUtils.join(File.separator,
instance.getDataFolder().getPath(), "backups", "backup" + dateString);
}
/**
* Perform a backup with the given reason.
*
* @param cause BackupCause The cause of the backup.
* @param cause The cause of the backup.
*/
public void doBackup(BackupCause cause) {
// Do nothing if backup is disabled
if (!Settings.isBackupActivated) {
if (!settings.getProperty(BackupSettings.ENABLED)) {
// Print a warning if the backup was requested via command or by another plugin
if (cause == BackupCause.COMMAND || cause == BackupCause.OTHER) {
ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: " + cause.name());
ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: "
+ cause.name());
}
return;
}
// Check whether a backup should be made at the specified point in time
switch (cause) {
case START:
if (!Settings.isBackupOnStart)
return;
case STOP:
if (!Settings.isBackupOnStop)
return;
case COMMAND:
case OTHER:
if (BackupCause.START.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_START)
|| BackupCause.STOP.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) {
return;
}
// Do backup and check return value!
@ -68,37 +79,31 @@ public class PerformBackup {
}
}
/**
* Method doBackup.
*
* @return boolean
*/
public boolean doBackup() {
switch (Settings.getDataSource) {
DataSource.DataSourceType dataSourceType = settings.getProperty(DatabaseSettings.BACKEND);
switch (dataSourceType) {
case FILE:
return FileBackup("auths.db");
return fileBackup("auths.db");
case MYSQL:
return MySqlBackup();
return mySqlBackup();
case SQLITE:
return FileBackup(Settings.getMySQLDatabase + ".db");
return fileBackup(dbName + ".db");
default:
ConsoleLogger.showError("Unknown data source type '" + dataSourceType + "' for backup");
}
return false;
}
/**
* Method MySqlBackup.
*
* @return boolean
*/
private boolean MySqlBackup() {
File dirBackup = new File(AuthMe.getInstance().getDataFolder() + "/backups");
private boolean mySqlBackup() {
File dirBackup = new File(dataFolder + File.separator + "backups");
if (!dirBackup.exists())
if (!dirBackup.exists()) {
dirBackup.mkdir();
if (checkWindows(Settings.backupWindowsPath)) {
String executeCmd = Settings.backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql";
}
String backupWindowsPath = settings.getProperty(BackupSettings.MYSQL_WINDOWS_PATH);
if (checkWindows(backupWindowsPath)) {
String executeCmd = backupWindowsPath + "\\bin\\mysqldump.exe -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql";
Process runtimeProcess;
try {
runtimeProcess = Runtime.getRuntime().exec(executeCmd);
@ -109,8 +114,12 @@ public class PerformBackup {
} else {
ConsoleLogger.showError("Could not create the backup!");
}
} catch (Exception ex) {
ex.printStackTrace();
} catch (IOException e) {
ConsoleLogger.showError("Error during backup: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
} catch (InterruptedException e) {
ConsoleLogger.showError("Backup was interrupted: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
}
} else {
String executeCmd = "mysqldump -u " + dbUserName + " -p" + dbPassword + " " + dbName + " --tables " + tblname + " -r " + path + ".sql";
@ -124,69 +133,54 @@ public class PerformBackup {
} else {
ConsoleLogger.showError("Could not create the backup!");
}
} catch (Exception ex) {
ex.printStackTrace();
} catch (IOException e) {
ConsoleLogger.showError("Error during backup: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
} catch (InterruptedException e) {
ConsoleLogger.showError("Backup was interrupted: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
}
}
return false;
}
/**
* Method FileBackup.
*
* @param backend String
*
* @return boolean
*/
private boolean FileBackup(String backend) {
File dirBackup = new File(AuthMe.getInstance().getDataFolder() + "/backups");
private boolean fileBackup(String backend) {
File dirBackup = new File(dataFolder + File.separator + "backups");
if (!dirBackup.exists())
dirBackup.mkdir();
try {
copy(new File("plugins" + File.separator + "AuthMe" + File.separator + backend), new File(path + ".db"));
copy("plugins" + File.separator + "AuthMe" + File.separator + backend, path + ".db");
return true;
} catch (Exception ex) {
ex.printStackTrace();
} catch (IOException ex) {
ConsoleLogger.showError("Encountered an error during file backup: " + StringUtils.formatException(ex));
ConsoleLogger.writeStackTrace(ex);
}
return false;
}
/**
* Method checkWindows.
* Check if we are under Windows and correct location of mysqldump.exe
* otherwise return error.
*
* @param windowsPath String
*
* @return boolean
* @param windowsPath The path to check
* @return True if the path is correct, false if it is incorrect or the OS is not Windows
*/
private boolean checkWindows(String windowsPath) {
private static boolean checkWindows(String windowsPath) {
String isWin = System.getProperty("os.name").toLowerCase();
if (isWin.contains("win")) {
if (new File(windowsPath + "\\bin\\mysqldump.exe").exists()) {
return true;
} else {
ConsoleLogger.showError("Mysql Windows Path is incorrect please check it");
return true;
ConsoleLogger.showError("Mysql Windows Path is incorrect. Please check it");
return false;
}
} else return false;
}
return false;
}
/*
* Check if we are under Windows and correct location of mysqldump.exe
* otherwise return error.
*/
/**
* Method copy.
*
* @param src File
* @param dst File
*
* @throws IOException
*/
void copy(File src, File dst) throws IOException {
private static void copy(String src, String dst) throws IOException {
InputStream in = new FileInputStream(src);
OutputStream out = new FileOutputStream(dst);
@ -200,27 +194,6 @@ public class PerformBackup {
out.close();
}
/*
* Copyr src bytefile into dst file
*/
/**
* Method getInstance.
*
* @return AuthMe
*/
public AuthMe getInstance() {
return instance;
}
/**
* Method setInstance.
*
* @param instance AuthMe
*/
public void setInstance(AuthMe instance) {
this.instance = instance;
}
/**
* Possible backup causes.
@ -229,7 +202,7 @@ public class PerformBackup {
START,
STOP,
COMMAND,
OTHER,
OTHER
}
}

View File

@ -8,10 +8,11 @@ import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.custom.NewSetting;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.domain.Property;
import org.bukkit.command.CommandSender;
import java.io.File;
import java.util.List;
/**
@ -101,6 +102,16 @@ public class CommandService {
return authMe.getDataSource();
}
/**
* Return the AuthMe instance for further manipulation. Use only if other methods from
* the command service cannot be used.
*
* @return The AuthMe instance
*/
public AuthMe getAuthMe() {
return authMe;
}
/**
* Return the PasswordSecurity instance.
*
@ -152,6 +163,15 @@ public class CommandService {
return messages.retrieve(key);
}
/**
* Change the messages instance to retrieve messages from the given file.
*
* @param file The new file to read messages from
*/
public void reloadMessages(File file) {
messages.reload(file);
}
/**
* Retrieve the given property's value.
*
@ -163,4 +183,13 @@ public class CommandService {
return settings.getProperty(property);
}
/**
* Return the settings manager.
*
* @return The settings manager
*/
public NewSetting getSettings() {
return settings;
}
}

View File

@ -8,8 +8,8 @@ import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.custom.RestrictionSettings;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.command.CommandSender;
import java.util.List;

View File

@ -7,7 +7,7 @@ import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;

View File

@ -1,35 +1,31 @@
package fr.xephi.authme.command.executable.authme;
import java.util.List;
import org.bukkit.command.CommandSender;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.Settings;
import org.bukkit.command.CommandSender;
import java.util.List;
/**
* The reload command.
*/
public class ReloadCommand implements ExecutableCommand {
@Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) {
// AuthMe plugin instance
AuthMe plugin = AuthMe.getInstance();
AuthMe plugin = commandService.getAuthMe();
try {
Settings.reload();
Messages.getInstance().reloadManager();
plugin.getModuleManager().reloadModules();
commandService.getSettings().reload();
commandService.reloadMessages(commandService.getSettings().getMessagesFile());
plugin.setupDatabase();
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
} catch (Exception e) {
sender.sendMessage("Error occurred during reload of AuthMe: aborting");
ConsoleLogger.logException("Aborting! Encountered exception during reload of AuthMe:", e);
plugin.stopOrUnload();
}
commandService.send(sender, MessageKey.CONFIG_RELOAD_SUCCESS);
}
}

View File

@ -5,7 +5,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils;
import org.bukkit.command.CommandSender;
import java.util.List;
@ -20,7 +20,7 @@ public class SetEmailCommand implements ExecutableCommand {
final String playerEmail = arguments.get(1);
// Validate the email address
if (!Settings.isEmailCorrect(playerEmail)) {
if (!Utils.isEmailCorrect(playerEmail, commandService.getSettings())) {
commandService.send(sender, MessageKey.INVALID_EMAIL);
return;
}

View File

@ -3,7 +3,6 @@ package fr.xephi.authme.command.executable.authme;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.settings.Settings;
import org.bukkit.Bukkit;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -11,12 +10,15 @@ import org.bukkit.entity.Player;
import java.util.List;
import static fr.xephi.authme.settings.properties.PluginSettings.HELP_HEADER;
public class VersionCommand implements ExecutableCommand {
@Override
public void executeCommand(CommandSender sender, List<String> arguments, CommandService commandService) {
// Show some version info
sender.sendMessage(ChatColor.GOLD + "==========[ " + Settings.helpHeader + " ABOUT ]==========");
sender.sendMessage(ChatColor.GOLD + "==========[ " + commandService.getProperty(HELP_HEADER)
+ " ABOUT ]==========");
sender.sendMessage(ChatColor.GOLD + "Version: " + ChatColor.WHITE + AuthMe.getPluginName()
+ " v" + AuthMe.getPluginVersion() + ChatColor.GRAY + " (build: " + AuthMe.getPluginBuildNumber() + ")");
sender.sendMessage(ChatColor.GOLD + "Developers:");

View File

@ -6,7 +6,7 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.Wrapper;
import org.bukkit.entity.Player;

View File

@ -5,8 +5,8 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.custom.RestrictionSettings;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.ChangePasswordTask;
import fr.xephi.authme.util.Wrapper;
import org.bukkit.entity.Player;

View File

@ -6,6 +6,7 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import java.util.List;
@ -26,7 +27,7 @@ public class RegisterCommand extends PlayerCommand {
return;
}
final String email = arguments.get(0);
if (!Settings.isEmailCorrect(email)) {
if (!Utils.isEmailCorrect(email, commandService.getSettings())) {
commandService.send(player, MessageKey.INVALID_EMAIL);
return;
}

View File

@ -10,7 +10,6 @@ import fr.xephi.authme.command.FoundCommandResult;
import fr.xephi.authme.permission.DefaultPermission;
import fr.xephi.authme.permission.PermissionNode;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.CollectionUtils;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -44,9 +43,11 @@ public class HelpProvider {
public static final int ALL_OPTIONS = ~HIDE_COMMAND;
private final PermissionsManager permissionsManager;
private final String helpHeader;
public HelpProvider(PermissionsManager permissionsManager) {
public HelpProvider(PermissionsManager permissionsManager, String helpHeader) {
this.permissionsManager = permissionsManager;
this.helpHeader = helpHeader;
}
public List<String> printHelp(CommandSender sender, FoundCommandResult result, int options) {
@ -55,7 +56,7 @@ public class HelpProvider {
}
List<String> lines = new ArrayList<>();
lines.add(ChatColor.GOLD + "==========[ " + Settings.helpHeader + " HELP ]==========");
lines.add(ChatColor.GOLD + "==========[ " + helpHeader + " HELP ]==========");
CommandDescription command = result.getCommandDescription();
List<String> labels = ImmutableList.copyOf(result.getLabels());

View File

@ -4,32 +4,41 @@ import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.SQLite;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.util.StringUtils;
import java.sql.SQLException;
/**
* Mandatory migration from the deprecated flat file datasource to SQLite.
*/
public class ForceFlatToSqlite {
private final DataSource data;
private final DataSource database;
private final NewSetting settings;
public ForceFlatToSqlite(DataSource data) {
this.data = data;
public ForceFlatToSqlite(DataSource database, NewSetting settings) {
this.database = database;
this.settings = settings;
}
public DataSource run() {
DataSource sqlite = null;
try {
sqlite = new SQLite();
for (PlayerAuth auth : data.getAllAuths()) {
DataSource sqlite = new SQLite();
for (PlayerAuth auth : database.getAllAuths()) {
auth.setRealName("Player");
sqlite.saveAuth(auth);
}
Settings.setValue("DataSource.backend", "sqlite");
ConsoleLogger.info("Database successfully converted to sqlite !");
} catch (Exception e) {
ConsoleLogger.showError("An error occurred while trying to convert flatfile to sqlite ...");
return null;
settings.setProperty(DatabaseSettings.BACKEND, DataSource.DataSourceType.SQLITE);
settings.save();
ConsoleLogger.info("Database successfully converted to sqlite!");
return sqlite;
} catch (SQLException | ClassNotFoundException e) {
ConsoleLogger.showError("An error occurred while trying to convert flatfile to sqlite: "
+ StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
}
return sqlite;
return null;
}
}

View File

@ -36,17 +36,19 @@ public class FlatFile implements DataSource {
private final File source;
public FlatFile() {
source = Settings.AUTH_FILE;
AuthMe instance = AuthMe.getInstance();
source = new File(instance.getDataFolder(), "auths.db");
try {
source.createNewFile();
} catch (IOException e) {
ConsoleLogger.showError(e.getMessage());
if (Settings.isStopEnabled) {
ConsoleLogger.showError("Can't use FLAT FILE... SHUTDOWN...");
AuthMe.getInstance().getServer().shutdown();
instance.getServer().shutdown();
}
if (!Settings.isStopEnabled) {
AuthMe.getInstance().getServer().getPluginManager().disablePlugin(AuthMe.getInstance());
instance.getServer().getPluginManager().disablePlugin(instance);
}
e.printStackTrace();
}

View File

@ -1,25 +1,26 @@
package fr.xephi.authme.mail;
import java.io.File;
import java.io.IOException;
import java.security.Security;
import java.util.Properties;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.imageio.ImageIO;
import javax.mail.Session;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.bukkit.Bukkit;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.ImageGenerator;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import org.bukkit.Bukkit;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.imageio.ImageIO;
import javax.mail.Session;
import java.io.File;
import java.io.IOException;
import java.security.Security;
import java.util.Properties;
/**
* @author Xephi59
@ -27,13 +28,15 @@ import fr.xephi.authme.util.StringUtils;
public class SendMailSSL {
private final AuthMe plugin;
private final NewSetting settings;
public SendMailSSL(AuthMe plugin) {
public SendMailSSL(AuthMe plugin, NewSetting settings) {
this.plugin = plugin;
this.settings = settings;
}
public void main(final PlayerAuth auth, final String newPass) {
final String mailText = replaceMailTags(Settings.getMailText, plugin, auth, newPass);
final String mailText = replaceMailTags(settings.getEmailMessage(), plugin, auth, newPass);
Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() {
@Override
@ -41,21 +44,23 @@ public class SendMailSSL {
Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
HtmlEmail email;
try {
email = initializeMail(auth);
email = initializeMail(auth, settings);
} catch (EmailException e) {
ConsoleLogger.showError("Failed to create email with the given settings: " + StringUtils.formatException(e));
ConsoleLogger.showError("Failed to create email with the given settings: "
+ StringUtils.formatException(e));
return;
}
String content = mailText;
// Generate an image?
File file = null;
if (Settings.generateImage) {
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
file = generateImage(auth, plugin, newPass);
content = embedImageIntoEmailContent(file, email, content);
} catch (IOException | EmailException e) {
ConsoleLogger.showError("Unable to send new password as image for email " + auth.getEmail() + ": " + StringUtils.formatException(e));
ConsoleLogger.showError("Unable to send new password as image for email " + auth.getEmail()
+ ": " + StringUtils.formatException(e));
}
}
@ -68,43 +73,39 @@ public class SendMailSSL {
});
}
private static File generateImage(PlayerAuth auth, AuthMe plugin,
String newPass) throws IOException {
private static File generateImage(PlayerAuth auth, AuthMe plugin, String newPass) throws IOException {
ImageGenerator gen = new ImageGenerator(newPass);
File file = new File(plugin.getDataFolder() + File.separator + auth.getNickname() + "_new_pass.jpg");
File file = new File(plugin.getDataFolder(), auth.getNickname() + "_new_pass.jpg");
ImageIO.write(gen.generateImage(), "jpg", file);
return file;
}
private static String embedImageIntoEmailContent(File image,
HtmlEmail email, String content) throws EmailException {
private static String embedImageIntoEmailContent(File image, HtmlEmail email, String content)
throws EmailException {
DataSource source = new FileDataSource(image);
String tag = email.embed(source, image.getName());
return content.replace("<image />", "<img src=\"cid:" + tag + "\">");
}
private static HtmlEmail initializeMail(PlayerAuth auth)
private static HtmlEmail initializeMail(PlayerAuth auth, NewSetting settings)
throws EmailException {
String senderName;
if (StringUtils.isEmpty(Settings.getmailSenderName)) {
senderName = Settings.getmailAccount;
} else {
senderName = Settings.getmailSenderName;
}
String senderMail = Settings.getmailAccount;
String mailPassword = Settings.getmailPassword;
int port = Settings.getMailPort;
String senderMail = settings.getProperty(EmailSettings.MAIL_ACCOUNT);
String senderName = StringUtils.isEmpty(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail
: settings.getProperty(EmailSettings.MAIL_SENDER_NAME);
String mailPassword = settings.getProperty(EmailSettings.MAIL_PASSWORD);
int port = settings.getProperty(EmailSettings.SMTP_PORT);
HtmlEmail email = new HtmlEmail();
email.setCharset(org.apache.commons.mail.EmailConstants.UTF_8);
email.setCharset(EmailConstants.UTF_8);
email.setSmtpPort(port);
email.setHostName(Settings.getmailSMTP);
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
email.addTo(auth.getEmail());
email.setFrom(senderMail, senderName);
email.setSubject(Settings.getMailSubject);
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
email.setAuthentication(senderMail, mailPassword);
setPropertiesForPort(email, port);
setPropertiesForPort(email, port, settings);
return email;
}
@ -113,7 +114,8 @@ public class SendMailSSL {
email.setHtmlMsg(content);
email.setTextMsg(content);
} catch (EmailException e) {
ConsoleLogger.showError("Your email.html config contains an error and cannot be sent: " + StringUtils.formatException(e));
ConsoleLogger.showError("Your email.html config contains an error and cannot be sent: "
+ StringUtils.formatException(e));
return false;
}
try {
@ -125,17 +127,19 @@ public class SendMailSSL {
}
}
private static String replaceMailTags(String mailText, AuthMe plugin,
PlayerAuth auth, String newPass) {
return mailText.replace("<playername />", auth.getNickname()).replace("<servername />", plugin.getServer().getServerName()).replace("<generatedpass />", newPass);
private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) {
return mailText
.replace("<playername />", auth.getNickname())
.replace("<servername />", plugin.getServer().getServerName())
.replace("<generatedpass />", newPass);
}
@SuppressWarnings("deprecation")
private static void setPropertiesForPort(HtmlEmail email, int port)
private static void setPropertiesForPort(HtmlEmail email, int port, NewSetting settings)
throws EmailException {
switch (port) {
case 587:
if (!Settings.emailOauth2Token.isEmpty()) {
String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN);
if (!oAuth2Token.isEmpty()) {
if (Security.getProvider("Google OAuth2 Provider") == null) {
Security.addProvider(new OAuth2Provider());
}
@ -146,7 +150,7 @@ public class SendMailSSL {
mailProperties.setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2");
mailProperties.setProperty("mail.smtp.auth.login.disable", "true");
mailProperties.setProperty("mail.smtp.auth.plain.disable", "true");
mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, Settings.emailOauth2Token);
mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oAuth2Token);
email.setMailSession(Session.getInstance(mailProperties));
} else {
email.setStartTLSEnabled(true);
@ -159,7 +163,7 @@ public class SendMailSSL {
email.setSSLCheckServerIdentity(true);
break;
case 465:
email.setSslSmtpPort("" + port);
email.setSslSmtpPort(Integer.toString(port));
email.setSSL(true);
break;
default:

View File

@ -1,9 +1,10 @@
package fr.xephi.authme.output;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.command.CommandSender;
import java.io.File;
/**
* Class for retrieving and sending translatable messages to players.
* This class detects when the language settings have changed and will
@ -11,27 +12,15 @@ import org.bukkit.command.CommandSender;
*/
public class Messages {
private static Messages singleton;
private final String language;
private MessagesManager manager;
private Messages(String language, MessagesManager manager) {
this.language = language;
this.manager = manager;
}
/**
* Get the instance of Messages.
* Constructor.
*
* @return The Messages instance
* @param messageFile The messages file to use
*/
public static Messages getInstance() {
if (singleton == null) {
MessagesManager manager = new MessagesManager(Settings.messageFile);
singleton = new Messages(Settings.messagesLanguage, manager);
}
return singleton;
public Messages(File messageFile) {
manager = new MessagesManager(messageFile);
}
/**
@ -60,7 +49,8 @@ public class Messages {
String message = retrieveSingle(key);
String[] tags = key.getTags();
if (replacements.length != tags.length) {
throw new RuntimeException("Given replacement size does not match the tags in message key '" + key + "'");
throw new IllegalStateException(
"Given replacement size does not match the tags in message key '" + key + "'");
}
for (int i = 0; i < tags.length; ++i) {
@ -80,9 +70,6 @@ public class Messages {
* @return The message split by new lines
*/
public String[] retrieve(MessageKey key) {
if (!Settings.messagesLanguage.equalsIgnoreCase(language)) {
reloadManager();
}
return manager.retrieve(key.getKey());
}
@ -100,8 +87,8 @@ public class Messages {
/**
* Reload the messages manager.
*/
public void reloadManager() {
manager = new MessagesManager(Settings.messageFile);
public void reload(File messagesFile) {
manager = new MessagesManager(messagesFile);
}
}

View File

@ -1,8 +1,8 @@
package fr.xephi.authme.output;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.CustomConfiguration;
import org.bukkit.ChatColor;
import org.bukkit.configuration.file.YamlConfiguration;
import java.io.File;
@ -12,7 +12,10 @@ import java.io.File;
* This class is used within {@link Messages}, which offers a high-level interface for accessing
* or sending messages from a properties file.
*/
class MessagesManager extends CustomConfiguration {
class MessagesManager {
private final YamlConfiguration configuration;
private final String fileName;
/**
* Constructor for Messages.
@ -20,8 +23,8 @@ class MessagesManager extends CustomConfiguration {
* @param file the configuration file
*/
MessagesManager(File file) {
super(file);
load();
this.fileName = file.getName();
this.configuration = YamlConfiguration.loadConfiguration(file);
}
/**
@ -31,24 +34,22 @@ class MessagesManager extends CustomConfiguration {
*
* @return The message
*/
String[] retrieve(String key) {
String message = (String) get(key);
public String[] retrieve(String key) {
String message = configuration.getString(key);
if (message != null) {
return formatMessage(message);
}
// Message is null: log key not being found and send error back as message
String retrievalError = "Error getting message with key '" + key + "'. ";
ConsoleLogger.showError(retrievalError + "Please verify your config file at '"
+ getConfigFile().getName() + "'");
ConsoleLogger.showError(retrievalError + "Please verify your config file at '" + fileName + "'");
return new String[]{
retrievalError + "Please contact the admin to verify or update the AuthMe messages file."};
}
static String[] formatMessage(String message) {
private static String[] formatMessage(String message) {
String[] lines = message.split("&n");
for (int i = 0; i < lines.length; ++i) {
// We don't initialize a StringBuilder here because mostly we will only have one entry
lines[i] = ChatColor.translateAlternateColorCodes('&', lines[i]);
}
return lines;

View File

@ -8,6 +8,7 @@ import fr.xephi.authme.process.logout.AsynchronousLogout;
import fr.xephi.authme.process.quit.AsynchronousQuit;
import fr.xephi.authme.process.register.AsyncRegister;
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
import fr.xephi.authme.settings.NewSetting;
import org.bukkit.entity.Player;
import org.bukkit.scheduler.BukkitScheduler;
@ -17,15 +18,17 @@ public class Management {
private final AuthMe plugin;
private final BukkitScheduler sched;
private final NewSetting settings;
/**
* Constructor for Management.
*
* @param plugin AuthMe
*/
public Management(AuthMe plugin) {
public Management(AuthMe plugin, NewSetting settings) {
this.plugin = plugin;
this.sched = this.plugin.getServer().getScheduler();
this.settings = settings;
}
public void performLogin(final Player player, final String password, final boolean forceLogin) {
@ -33,7 +36,8 @@ public class Management {
@Override
public void run() {
new AsynchronousLogin(player, password, forceLogin, plugin, plugin.getDataSource()).process();
new AsynchronousLogin(player, password, forceLogin, plugin, plugin.getDataSource(), settings)
.process();
}
});
}
@ -53,7 +57,7 @@ public class Management {
@Override
public void run() {
new AsyncRegister(player, password, email, plugin, plugin.getDataSource()).process();
new AsyncRegister(player, password, email, plugin, plugin.getDataSource(), settings).process();
}
});
}
@ -94,7 +98,7 @@ public class Management {
sched.runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
new AsyncChangeEmail(player, plugin, null, newEmail, newEmailVerify).process();
new AsyncChangeEmail(player, plugin, null, newEmail, newEmailVerify, settings).process();
}
});
}
@ -103,7 +107,7 @@ public class Management {
sched.runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
new AsyncChangeEmail(player, plugin, oldEmail, newEmail).process();
new AsyncChangeEmail(player, plugin, oldEmail, newEmail, settings).process();
}
});
}

View File

@ -5,8 +5,10 @@ import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
/**
@ -19,18 +21,21 @@ public class AsyncChangeEmail {
private final String newEmail;
private final String newEmailVerify;
private final Messages m;
private final NewSetting settings;
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, String newEmailVerify) {
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, String newEmailVerify,
NewSetting settings) {
this.m = plugin.getMessages();
this.player = player;
this.plugin = plugin;
this.oldEmail = oldEmail;
this.newEmail = newEmail;
this.newEmailVerify = newEmailVerify;
this.settings = settings;
}
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail) {
this(player, plugin, oldEmail, newEmail, newEmail);
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, NewSetting settings) {
this(player, plugin, oldEmail, newEmail, newEmail, settings);
}
public void process() {
@ -57,7 +62,7 @@ public class AsyncChangeEmail {
return;
}
}
if (!Settings.isEmailCorrect(newEmail)) {
if (!Utils.isEmailCorrect(newEmail, settings)) {
m.send(player, MessageKey.INVALID_NEW_EMAIL);
return;
}

View File

@ -49,14 +49,14 @@ public class AsynchronousJoin {
}
public void process() {
if (Settings.checkVeryGames) {
plugin.getVerygamesIp(player);
}
if (Utils.isUnrestricted(player)) {
return;
}
if (Settings.checkVeryGames) {
plugin.getVerygamesIp(player);
}
if (plugin.ess != null && Settings.disableSocialSpy) {
plugin.ess.getUser(player).setSocialSpyEnabled(false);
}
@ -64,13 +64,13 @@ public class AsynchronousJoin {
final String ip = plugin.getIP(player);
if (Settings.isAllowRestrictedIp && !Settings.getRestrictedIp(name, ip, player.getAddress().getHostName())) {
if (Settings.isAllowRestrictedIp && !isNameRestricted(name, ip, player.getAddress().getHostName())) {
sched.scheduleSyncDelayedTask(plugin, new Runnable() {
@Override
public void run() {
AuthMePlayerListener.causeByAuthMe.putIfAbsent(name, true);
player.kickPlayer("You are not the Owner of this account, please try another name!");
player.kickPlayer("You are not the owner of this account. Please try another name!");
if (Settings.banUnsafeIp)
plugin.getServer().banIP(ip);
}
@ -282,4 +282,30 @@ public class AsynchronousJoin {
});
}
/**
* Return whether the name is restricted based on the restriction setting.
*
* @param name The name to check
* @param ip The IP address of the player
* @param domain The hostname of the IP address
* @return True if the name is restricted (IP/domain is not allowed for the given name),
* false if the restrictions are met or if the name has no restrictions to it
*/
private static boolean isNameRestricted(String name, String ip, String domain) {
boolean nameFound = false;
for (String entry : Settings.getRestrictedIp) {
String[] args = entry.split(";");
String testName = args[0];
String testIp = args[1];
if (testName.equalsIgnoreCase(name)) {
nameFound = true;
if ((ip != null && testIp.equals(ip))
|| (domain != null && testIp.equalsIgnoreCase(domain))) {
return false;
}
}
}
return nameFound;
}
}

View File

@ -11,8 +11,11 @@ import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.security.RandomString;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.task.MessageTask;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
@ -34,6 +37,7 @@ public class AsynchronousLogin {
private final DataSource database;
private final Messages m;
private final String ip;
private final NewSetting settings;
/**
* Constructor for AsynchronousLogin.
@ -43,8 +47,10 @@ public class AsynchronousLogin {
* @param forceLogin boolean
* @param plugin AuthMe
* @param data DataSource
* @param settings The settings
*/
public AsynchronousLogin(Player player, String password, boolean forceLogin, AuthMe plugin, DataSource data) {
public AsynchronousLogin(Player player, String password, boolean forceLogin, AuthMe plugin, DataSource data,
NewSetting settings) {
this.m = plugin.getMessages();
this.player = player;
this.name = player.getName().toLowerCase();
@ -54,6 +60,7 @@ public class AsynchronousLogin {
this.plugin = plugin;
this.database = data;
this.ip = plugin.getIP(player);
this.settings = settings;
}
protected boolean needsCaptcha() {
@ -98,7 +105,7 @@ public class AsynchronousLogin {
msg = m.retrieve(MessageKey.REGISTER_MESSAGE);
}
BukkitTask msgT = Bukkit.getScheduler().runTaskAsynchronously(plugin,
new MessageTask(plugin, name, msg, Settings.getWarnMessageInterval));
new MessageTask(plugin, name, msg, settings.getProperty(RegistrationSettings.MESSAGE_INTERVAL)));
LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgT);
}
return null;
@ -165,12 +172,10 @@ public class AsynchronousLogin {
if (!forceLogin)
m.send(player, MessageKey.LOGIN_SUCCESS);
displayOtherAccounts(auth, player);
displayOtherAccounts(auth);
if (Settings.recallEmail) {
if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) {
m.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
}
if (Settings.recallEmail && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) {
m.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
}
if (!Settings.noConsoleSpam) {
@ -186,7 +191,7 @@ public class AsynchronousLogin {
// task, we schedule it in the end
// so that we can be sure, and have not to care if it might be
// processed in other order.
ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database);
ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database, settings);
if (syncPlayerLogin.getLimbo() != null) {
if (syncPlayerLogin.getLimbo().getTimeoutTaskId() != null) {
syncPlayerLogin.getLimbo().getTimeoutTaskId().cancel();
@ -215,7 +220,7 @@ public class AsynchronousLogin {
}
}
public void displayOtherAccounts(PlayerAuth auth, Player p) {
public void displayOtherAccounts(PlayerAuth auth) {
if (!Settings.displayOtherAccounts) {
return;
}
@ -223,30 +228,16 @@ public class AsynchronousLogin {
return;
}
List<String> auths = this.database.getAllAuthsByName(auth);
if (auths.isEmpty()) {
if (auths.isEmpty() || auths.size() == 1) {
return;
}
if (auths.size() == 1) {
return;
}
StringBuilder message = new StringBuilder("[AuthMe] ");
int i = 0;
for (String account : auths) {
i++;
message.append(account);
if (i != auths.size()) {
message.append(", ");
} else {
message.append('.');
}
}
String message = "[AuthMe] " + StringUtils.join(", ", auths) + ".";
for (Player player : Utils.getOnlinePlayers()) {
if (plugin.getPermissionsManager().hasPermission(player, PlayerPermission.SEE_OTHER_ACCOUNTS)
|| (player.getName().equals(this.player.getName())
&& plugin.getPermissionsManager().hasPermission(player, PlayerPermission.SEE_OWN_ACCOUNTS))) {
player.sendMessage("[AuthMe] The player " + auth.getNickname() + " has " + auths.size() + " accounts");
player.sendMessage(message.toString());
player.sendMessage(message);
}
}
}

View File

@ -1,5 +1,7 @@
package fr.xephi.authme.process.login;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.HooksSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.entity.Player;
@ -24,6 +26,8 @@ import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Utils;
import fr.xephi.authme.util.Utils.GroupType;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
/**
*/
public class ProcessSyncPlayerLogin implements Runnable {
@ -36,24 +40,26 @@ public class ProcessSyncPlayerLogin implements Runnable {
private final DataSource database;
private final PluginManager pm;
private final JsonCache playerCache;
private final NewSetting settings;
/**
* Constructor for ProcessSyncPlayerLogin.
*
* @param player Player
* @param plugin AuthMe
* @param data DataSource
* @param database DataSource
*/
public ProcessSyncPlayerLogin(Player player, AuthMe plugin,
DataSource data) {
DataSource database, NewSetting settings) {
this.plugin = plugin;
this.database = data;
this.database = database;
this.pm = plugin.getServer().getPluginManager();
this.player = player;
this.name = player.getName().toLowerCase();
this.limbo = LimboCache.getInstance().getLimboPlayer(name);
this.auth = database.getAuth(name);
this.playerCache = new JsonCache();
this.settings = settings;
}
/**
@ -152,7 +158,7 @@ public class ProcessSyncPlayerLogin implements Runnable {
}
}
if (Settings.protectInventoryBeforeLogInEnabled) {
if (settings.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
restoreInventory();
}
@ -188,27 +194,27 @@ public class ProcessSyncPlayerLogin implements Runnable {
// Login is finish, display welcome message if we use email registration
if (Settings.useWelcomeMessage && Settings.emailRegistration)
if (Settings.broadcastWelcomeMessage) {
for (String s : Settings.welcomeMsg) {
for (String s : settings.getWelcomeMessage()) {
Bukkit.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
}
} else {
for (String s : Settings.welcomeMsg) {
for (String s : settings.getWelcomeMessage()) {
player.sendMessage(plugin.replaceAllInfo(s, player));
}
}
// Login is now finish , we can force all commands
// Login is now finished; we can force all commands
forceCommands();
sendTo();
}
private void sendTo() {
if (Settings.sendPlayerTo.isEmpty())
return;
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(Settings.sendPlayerTo);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER));
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
}
}

View File

@ -9,6 +9,7 @@ import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import org.bukkit.entity.Player;
@ -24,8 +25,10 @@ public class AsyncRegister {
private final AuthMe plugin;
private final DataSource database;
private final Messages m;
private final NewSetting settings;
public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data) {
public AsyncRegister(Player player, String password, String email, AuthMe plugin, DataSource data,
NewSetting settings) {
this.m = plugin.getMessages();
this.player = player;
this.password = password;
@ -34,6 +37,7 @@ public class AsyncRegister {
this.plugin = plugin;
this.database = data;
this.ip = plugin.getIP(player);
this.settings = settings;
}
private boolean preRegisterCheck() throws Exception {
@ -136,7 +140,7 @@ public class AsyncRegister {
plugin.getManagement().performLogin(player, "dontneed", true);
}
plugin.otherAccounts.addPlayer(player.getUniqueId());
ProcessSyncPasswordRegister sync = new ProcessSyncPasswordRegister(player, plugin);
ProcessSyncPasswordRegister sync = new ProcessSyncPasswordRegister(player, plugin, settings);
plugin.getServer().getScheduler().scheduleSyncDelayedTask(plugin, sync);
}
}

View File

@ -1,5 +1,7 @@
package fr.xephi.authme.process.register;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.HooksSettings;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
@ -30,6 +32,7 @@ public class ProcessSyncPasswordRegister implements Runnable {
protected final String name;
private final AuthMe plugin;
private final Messages m;
private final NewSetting settings;
/**
* Constructor for ProcessSyncPasswordRegister.
@ -37,11 +40,12 @@ public class ProcessSyncPasswordRegister implements Runnable {
* @param player Player
* @param plugin AuthMe
*/
public ProcessSyncPasswordRegister(Player player, AuthMe plugin) {
public ProcessSyncPasswordRegister(Player player, AuthMe plugin, NewSetting settings) {
this.m = plugin.getMessages();
this.player = player;
this.name = player.getName().toLowerCase();
this.plugin = plugin;
this.settings = settings;
}
private void sendBungeeMessage() {
@ -63,11 +67,6 @@ public class ProcessSyncPasswordRegister implements Runnable {
}
}
/**
* Method forceLogin.
*
* @param player Player
*/
private void forceLogin(Player player) {
Utils.teleportToSpawn(player);
LimboCache cache = LimboCache.getInstance();
@ -88,11 +87,6 @@ public class ProcessSyncPasswordRegister implements Runnable {
}
}
/**
* Method run.
*
* @see java.lang.Runnable#run()
*/
@Override
public void run() {
LimboPlayer limbo = LimboCache.getInstance().getLimboPlayer(name);
@ -141,11 +135,11 @@ public class ProcessSyncPasswordRegister implements Runnable {
// Register is finish and player is logged, display welcome message
if (Settings.useWelcomeMessage) {
if (Settings.broadcastWelcomeMessage) {
for (String s : Settings.welcomeMsg) {
for (String s : settings.getWelcomeMessage()) {
plugin.getServer().broadcastMessage(plugin.replaceAllInfo(s, player));
}
} else {
for (String s : Settings.welcomeMsg) {
for (String s : settings.getWelcomeMessage()) {
player.sendMessage(plugin.replaceAllInfo(s, player));
}
}
@ -161,18 +155,18 @@ public class ProcessSyncPasswordRegister implements Runnable {
sendBungeeMessage();
}
// Register is now finish , we can force all commands
// Register is now finished; we can force all commands
forceCommands();
sendTo();
}
private void sendTo() {
if (Settings.sendPlayerTo.isEmpty())
return;
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(Settings.sendPlayerTo);
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER));
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
}
}

View File

@ -0,0 +1,274 @@
package fr.xephi.authme.settings;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.Files;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
import org.bukkit.configuration.file.YamlConfiguration;
import org.yaml.snakeyaml.DumperOptions;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import static fr.xephi.authme.settings.SettingsMigrationService.copyFileFromResource;
/**
* The new settings manager.
*/
public class NewSetting {
private final File pluginFolder;
private final File configFile;
private FileConfiguration configuration;
/** The file with the localized messages based on {@link PluginSettings#MESSAGES_LANGUAGE}. */
private File messagesFile;
private List<String> welcomeMessage;
private String emailMessage;
/**
* Constructor. Checks the given {@link FileConfiguration} object for completeness.
*
* @param configFile The configuration file
* @param pluginFolder The AuthMe plugin folder
*/
public NewSetting(File configFile, File pluginFolder) {
this.configuration = YamlConfiguration.loadConfiguration(configFile);
this.configFile = configFile;
this.pluginFolder = pluginFolder;
validateAndLoadOptions();
}
/**
* Constructor for testing purposes, allowing more options.
*
* @param configuration The FileConfiguration object to use
* @param configFile The file to write to
* @param propertyMap The property map whose properties should be verified for presence, or null to skip this
*/
@VisibleForTesting
NewSetting(FileConfiguration configuration, File configFile, PropertyMap propertyMap) {
this.configuration = configuration;
this.configFile = configFile;
this.pluginFolder = new File("");
if (propertyMap != null && SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) {
save(propertyMap);
}
}
/**
* Get the given property from the configuration.
*
* @param property The property to retrieve
* @param <T> The property's type
* @return The property's value
*/
public <T> T getProperty(Property<T> property) {
return property.getFromFile(configuration);
}
/**
* Set a new value for the given property.
*
* @param property The property to modify
* @param value The new value to assign to the property
* @param <T> The property's type
*/
public <T> void setProperty(Property<T> property, T value) {
configuration.set(property.getPath(), value);
}
/**
* Save the config file. Use after migrating one or more settings.
*/
public void save() {
save(SettingsFieldRetriever.getAllPropertyFields());
}
/**
* Return the messages file based on the messages language config.
*
* @return The messages file to read messages from
*/
public File getMessagesFile() {
return messagesFile;
}
public String getEmailMessage() {
return emailMessage;
}
public List<String> getWelcomeMessage() {
return welcomeMessage;
}
/**
* Reload the configuration.
*/
public void reload() {
configuration = YamlConfiguration.loadConfiguration(configFile);
validateAndLoadOptions();
}
private void save(PropertyMap propertyMap) {
try (FileWriter writer = new FileWriter(configFile)) {
Yaml simpleYaml = newYaml(false);
Yaml singleQuoteYaml = newYaml(true);
writer.write("");
// Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
List<String> currentPath = new ArrayList<>();
for (Map.Entry<Property<?>, String[]> entry : propertyMap.entrySet()) {
Property<?> property = entry.getKey();
// Handle properties
List<String> propertyPath = Arrays.asList(property.getPath().split("\\."));
List<String> commonPathParts = CollectionUtils.filterCommonStart(
currentPath, propertyPath.subList(0, propertyPath.size() - 1));
List<String> newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
if (commonPathParts.isEmpty()) {
writer.append("\n");
}
int indentationLevel = commonPathParts.size();
if (newPathParts.size() > 1) {
for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
writer.append("\n")
.append(indent(indentationLevel))
.append(path)
.append(": ");
++indentationLevel;
}
}
for (String comment : entry.getValue()) {
writer.append("\n")
.append(indent(indentationLevel))
.append("# ")
.append(comment);
}
writer.append("\n")
.append(indent(indentationLevel))
.append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
.append(": ")
.append(toYaml(property, indentationLevel, simpleYaml, singleQuoteYaml));
currentPath = propertyPath.subList(0, propertyPath.size() - 1);
}
writer.flush();
writer.close();
} catch (IOException e) {
ConsoleLogger.logException("Could not save config file:", e);
}
}
private void validateAndLoadOptions() {
PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
if (SettingsMigrationService.checkAndMigrate(configuration, propertyMap, pluginFolder)) {
ConsoleLogger.info("Merged new config options");
ConsoleLogger.info("Please check your config.yml file for new settings!");
save(propertyMap);
}
messagesFile = buildMessagesFile();
welcomeMessage = readWelcomeMessage();
emailMessage = readEmailMessage();
}
private <T> String toYaml(Property<T> property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml);
return join("\n" + indent(indent), representation.split("\\n"));
}
private File buildMessagesFile() {
String languageCode = getProperty(PluginSettings.MESSAGES_LANGUAGE);
File messagesFile = buildMessagesFileFromCode(languageCode);
if (messagesFile.exists()) {
return messagesFile;
}
return copyFileFromResource(messagesFile, buildMessagesFilePathFromCode(languageCode))
? messagesFile
: buildMessagesFileFromCode("en");
}
private File buildMessagesFileFromCode(String language) {
return new File(pluginFolder, buildMessagesFilePathFromCode(language));
}
private static String buildMessagesFilePathFromCode(String language) {
return StringUtils.makePath("messages", "messages_" + language + ".yml");
}
private List<String> readWelcomeMessage() {
if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
final File welcomeFile = new File(pluginFolder, "welcome.txt");
final Charset charset = Charset.forName("UTF-8");
if (copyFileFromResource(welcomeFile, "welcome.txt")) {
try {
return Files.readLines(welcomeFile, charset);
} catch (IOException e) {
ConsoleLogger.logException("Failed to read file '" + welcomeFile.getPath() + "':", e);
}
}
}
return new ArrayList<>(0);
}
private String readEmailMessage() {
final File emailFile = new File(pluginFolder, "email.html");
final Charset charset = Charset.forName("UTF-8");
if (copyFileFromResource(emailFile, "email.html")) {
try {
return StringUtils.join("", Files.readLines(emailFile, charset));
} catch (IOException e) {
ConsoleLogger.logException("Failed to read file '" + emailFile.getPath() + "':", e);
}
}
return "";
}
private static Yaml newYaml(boolean useSingleQuotes) {
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setAllowUnicode(true);
if (useSingleQuotes) {
options.setDefaultScalarStyle(DumperOptions.ScalarStyle.SINGLE_QUOTED);
}
return new Yaml(options);
}
private static String join(String delimiter, String[] items) {
StringBuilder sb = new StringBuilder();
String delim = "";
for (String item : items) {
sb.append(delim).append(item);
delim = delimiter;
}
return sb.toString();
}
private static String indent(int level) {
// We use an indentation of 4 spaces
StringBuilder sb = new StringBuilder(level * 4);
for (int i = 0; i < level; ++i) {
sb.append(" ");
}
return sb.toString();
}
}

View File

@ -1,42 +1,32 @@
package fr.xephi.authme.settings;
import com.google.common.base.Charsets;
import com.google.common.io.Files;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Wrapper;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Pattern;
/**
* Old settings manager. See {@link NewSetting} for the new manager.
*/
public final class Settings {
public static final File PLUGIN_FOLDER = Wrapper.getInstance().getDataFolder();
public static final File MODULE_FOLDER = new File(PLUGIN_FOLDER, "modules");
public static final File CACHE_FOLDER = new File(PLUGIN_FOLDER, "cache");
public static final File AUTH_FILE = new File(PLUGIN_FOLDER, "auths.db");
public static final File EMAIL_FILE = new File(PLUGIN_FOLDER, "email.html");
public static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml");
private static final File SETTINGS_FILE = new File(PLUGIN_FOLDER, "config.yml");
public static final File LOG_FILE = new File(PLUGIN_FOLDER, "authme.log");
// This is not an option!
public static boolean antiBotInAction = false;
public static File messageFile;
public static List<String> allowCommands;
public static List<String> getJoinPermissions;
public static List<String> getUnrestrictedName;
@ -49,7 +39,6 @@ public final class Settings {
public static List<String> forceCommandsAsConsole;
public static List<String> forceRegisterCommands;
public static List<String> forceRegisterCommandsAsConsole;
public static List<String> welcomeMsg;
public static List<String> unsafePasswords;
public static List<String> emailBlacklist;
public static List<String> emailWhitelist;
@ -66,8 +55,7 @@ public final class Settings {
isSaveQuitLocationEnabled, isForceSurvivalModeEnabled,
isCachingEnabled,
isKickOnWrongPasswordEnabled, enablePasswordConfirmation,
protectInventoryBeforeLogInEnabled, isBackupActivated,
isBackupOnStart, isBackupOnStop, isStopEnabled, reloadSupport,
protectInventoryBeforeLogInEnabled, isStopEnabled, reloadSupport,
rakamakUseIp, noConsoleSpam, removePassword, displayOtherAccounts,
useCaptcha, emailRegistration, multiverse, bungee,
banUnsafeIp, doubleEmailCheck, sessionExpireOnIpChange,
@ -79,19 +67,18 @@ public final class Settings {
checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect,
kickPlayersBeforeStopping, allowAllCommandsIfRegIsOptional,
customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase;
public static String helpHeader, getNickRegex, getUnloggedinGroup, getMySQLHost,
public static String getNickRegex, getUnloggedinGroup, getMySQLHost,
getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase,
getMySQLTablename, getMySQLColumnName, getMySQLColumnPassword,
getMySQLColumnIp, getMySQLColumnLastLogin, getMySQLColumnSalt,
getMySQLColumnGroup, getMySQLColumnEmail, unRegisteredGroup,
backupWindowsPath, getRegisteredGroup,
messagesLanguage, getMySQLlastlocX, getMySQLlastlocY,
getMySQLlastlocX, getMySQLlastlocY,
getMySQLlastlocZ, rakamakUsers, rakamakUsersIp, getmailAccount,
getmailPassword, getmailSMTP, getMySQLColumnId, getmailSenderName,
getMailSubject, getMailText, getMySQLlastlocWorld, defaultWorld,
getMySQLColumnId, getMySQLlastlocWorld, defaultWorld,
getPhpbbPrefix, getWordPressPrefix, getMySQLColumnLogged,
spawnPriority, crazyloginFileName, getPassRegex,
getMySQLColumnRealName, emailOauth2Token, sendPlayerTo;
getMySQLColumnRealName, sendPlayerTo;
public static int getWarnMessageInterval, getSessionTimeout,
getRegistrationTimeout, getMaxNickLength, getMinNickLength,
getPasswordMinLen, getMovementRadius, getmaxRegPerIp,
@ -100,7 +87,7 @@ public final class Settings {
getmaxRegPerEmail, bCryptLog2Rounds, getPhpbbGroup,
antiBotSensibility, antiBotDuration, delayRecall, getMaxLoginPerIp,
getMaxJoinPerIp;
protected static YamlConfiguration configFile;
protected static FileConfiguration configFile;
private static AuthMe plugin;
private static Settings instance;
@ -112,34 +99,11 @@ public final class Settings {
public Settings(AuthMe pl) {
instance = this;
plugin = pl;
configFile = (YamlConfiguration) plugin.getConfig();
}
/**
* Method reload.
*
* @throws Exception if something went wrong
*/
public static void reload() throws Exception {
plugin.getLogger().info("Loading Configuration File...");
boolean exist = SETTINGS_FILE.exists();
if (!exist) {
plugin.saveDefaultConfig();
}
configFile.load(SETTINGS_FILE);
if (exist) {
instance.mergeConfig();
}
configFile = plugin.getConfig();
loadVariables();
if (exist) {
instance.saveDefaults();
}
messageFile = new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + messagesLanguage + ".yml");
}
public static void loadVariables() {
helpHeader = configFile.getString("settings.helpHeader", "AuthMeReloaded");
messagesLanguage = checkLang(configFile.getString("settings.messagesLanguage", "en").toLowerCase());
isPermissionCheckEnabled = configFile.getBoolean("permission.EnablePermissionCheck", false);
isForcedRegistrationEnabled = configFile.getBoolean("settings.registration.force", true);
isRegistrationEnabled = configFile.getBoolean("settings.registration.enabled", true);
@ -204,9 +168,6 @@ public final class Settings {
plugin.checkProtocolLib();
passwordMaxLength = configFile.getInt("settings.security.passwordMaxLength", 20);
isBackupActivated = configFile.getBoolean("BackupSystem.ActivateBackup", false);
isBackupOnStart = configFile.getBoolean("BackupSystem.OnServerStart", false);
isBackupOnStop = configFile.getBoolean("BackupSystem.OnServeStop", false);
backupWindowsPath = configFile.getString("BackupSystem.MysqlWindowsPath", "C:\\Program Files\\MySQL\\MySQL Server 5.1\\");
isStopEnabled = configFile.getBoolean("Security.SQLProblem.stopServer", true);
reloadSupport = configFile.getBoolean("Security.ReloadCommand.useReloadCommandSupport", true);
@ -227,19 +188,14 @@ public final class Settings {
noConsoleSpam = configFile.getBoolean("Security.console.noConsoleSpam", false);
removePassword = configFile.getBoolean("Security.console.removePassword", true);
getmailAccount = configFile.getString("Email.mailAccount", "");
getmailPassword = configFile.getString("Email.mailPassword", "");
getmailSMTP = configFile.getString("Email.mailSMTP", "smtp.gmail.com");
getMailPort = configFile.getInt("Email.mailPort", 465);
getRecoveryPassLength = configFile.getInt("Email.RecoveryPasswordLength", 8);
getMySQLOtherUsernameColumn = configFile.getStringList("ExternalBoardOptions.mySQLOtherUsernameColumns");
displayOtherAccounts = configFile.getBoolean("settings.restrictions.displayOtherAccounts", true);
getMySQLColumnId = configFile.getString("DataSource.mySQLColumnId", "id");
getmailSenderName = configFile.getString("Email.mailSenderName", "");
useCaptcha = configFile.getBoolean("Security.captcha.useCaptcha", false);
maxLoginTry = configFile.getInt("Security.captcha.maxLoginTry", 5);
captchaLength = configFile.getInt("Security.captcha.captchaLength", 5);
getMailSubject = configFile.getString("Email.mailSubject", "Your new AuthMe Password");
getMailText = loadEmailText();
emailRegistration = configFile.getBoolean("settings.registration.enableEmailRegistrationSystem", false);
saltLength = configFile.getInt("settings.security.doubleMD5SaltLength", 8);
getmaxRegPerEmail = configFile.getInt("Email.maxRegPerEmail", 1);
@ -298,33 +254,8 @@ public final class Settings {
generateImage = configFile.getBoolean("Email.generateImage", false);
preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false);
kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true);
emailOauth2Token = configFile.getString("Email.emailOauth2Token", "");
sendPlayerTo = configFile.getString("Hooks.sendPlayerTo", "");
// Load the welcome message
getWelcomeMessage();
}
private static String loadEmailText() {
if (!EMAIL_FILE.exists()) {
plugin.saveResource("email.html", false);
}
try {
return Files.toString(EMAIL_FILE, Charsets.UTF_8);
} catch (IOException e) {
ConsoleLogger.logException("Error loading email text:", e);
return "";
}
}
/**
* @param key the key to set
* @param value the value to set
*/
public static void setValue(String key, Object value) {
instance.set(key, value);
save();
}
/**
@ -357,49 +288,12 @@ public final class Settings {
}
}
/**
* Config option for setting and check restricted user by username;ip ,
* return false if ip and name doesn't match with player that join the
* server, so player has a restricted access
*
* @param name String
* @param ip String
* @param domain String
*
* @return boolean
*/
public static boolean getRestrictedIp(String name, String ip, String domain) {
Iterator<String> iterator = getRestrictedIp.iterator();
boolean trueOnce = false;
boolean nameFound = false;
while (iterator.hasNext()) {
String[] args = iterator.next().split(";");
String testName = args[0];
String testIp = args[1];
if (testName.equalsIgnoreCase(name)) {
nameFound = true;
if (ip != null) {
if (testIp.equalsIgnoreCase(ip)) {
trueOnce = true;
}
}
if (domain != null) {
if (testIp.equalsIgnoreCase(domain)) {
trueOnce = true;
}
}
}
}
return !nameFound || trueOnce;
}
/**
* Saves the configuration to disk
*
* @return True if saved successfully
*/
public static boolean save() {
private static boolean save() {
try {
configFile.save(SETTINGS_FILE);
return true;
@ -415,7 +309,7 @@ public final class Settings {
*
* @return String
*/
public static String checkLang(String lang) {
private static String checkLang(String lang) {
if (new File(PLUGIN_FOLDER, "messages" + File.separator + "messages_" + lang + ".yml").exists()) {
ConsoleLogger.info("Set Language to: " + lang);
return lang;
@ -443,325 +337,6 @@ public final class Settings {
}
}
private static void getWelcomeMessage() {
AuthMe plugin = AuthMe.getInstance();
welcomeMsg = new ArrayList<>();
if (!useWelcomeMessage) {
return;
}
if (!(new File(plugin.getDataFolder() + File.separator + "welcome.txt").exists())) {
try {
FileWriter fw = new FileWriter(plugin.getDataFolder() + File.separator + "welcome.txt", true);
BufferedWriter w = new BufferedWriter(fw);
w.write("Welcome {PLAYER} on {SERVER} server");
w.newLine();
w.write("This server uses " + AuthMe.getPluginName() + " protection!");
w.close();
} catch (IOException e) {
e.printStackTrace();
}
}
try {
FileReader fr = new FileReader(plugin.getDataFolder() + File.separator + "welcome.txt");
BufferedReader br = new BufferedReader(fr);
String line;
while ((line = br.readLine()) != null) {
welcomeMsg.add(line);
}
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* Method isEmailCorrect.
*
* @param email String
*
* @return boolean
*/
public static boolean isEmailCorrect(String email) {
if (!email.contains("@"))
return false;
if (email.equalsIgnoreCase("your@email.com"))
return false;
String emailDomain = email.split("@")[1];
boolean correct = true;
if (emailWhitelist != null && !emailWhitelist.isEmpty()) {
for (String domain : emailWhitelist) {
if (!domain.equalsIgnoreCase(emailDomain)) {
correct = false;
} else {
correct = true;
break;
}
}
return correct;
}
if (emailBlacklist != null && !emailBlacklist.isEmpty()) {
for (String domain : emailBlacklist) {
if (domain.equalsIgnoreCase(emailDomain)) {
correct = false;
break;
}
}
}
return correct;
}
public void mergeConfig() {
boolean changes = false;
if (contains("Xenoforo.predefinedSalt")) {
set("Xenoforo.predefinedSalt", null);
changes = true;
}
if (!contains("Protection.enableProtection")) {
set("Protection.enableProtection", false);
changes = true;
}
if (!contains("settings.restrictions.removeSpeed")) {
set("settings.restrictions.removeSpeed", true);
changes = true;
}
if (!contains("Protection.countries")) {
countries = new ArrayList<>();
countries.add("US");
countries.add("GB");
set("Protection.countries", countries);
changes = true;
}
if (!contains("Protection.enableAntiBot")) {
set("Protection.enableAntiBot", false);
changes = true;
}
if (!contains("Protection.antiBotSensibility")) {
set("Protection.antiBotSensibility", 5);
changes = true;
}
if (!contains("Protection.antiBotDuration")) {
set("Protection.antiBotDuration", 10);
changes = true;
}
if (!contains("settings.forceCommands")) {
set("settings.forceCommands", new ArrayList<String>());
changes = true;
}
if (contains("settings.delayJoinMessage")) {
set("settings.delayJoinLeaveMessages", false);
set("settings.delayJoinMessage", null);
changes = true;
}
if (!contains("settings.forceCommandsAsConsole")) {
set("settings.forceCommandsAsConsole", new ArrayList<String>());
changes = true;
}
if (!contains("Email.recallPlayers")) {
set("Email.recallPlayers", false);
changes = true;
}
if (!contains("Email.delayRecall")) {
set("Email.delayRecall", 5);
changes = true;
}
if (!contains("settings.useWelcomeMessage")) {
set("settings.useWelcomeMessage", true);
changes = true;
}
if (!contains("settings.restrictions.enablePasswordConfirmation")) {
set("settings.restrictions.enablePasswordConfirmation", true);
changes = true;
}
if (contains("settings.restrictions.enablePasswordVerifier")) {
set("settings.restrictions.enablePasswordVerifier", null);
changes = true;
}
if(!contains("settings.restrictions.allowAllCommandsIfRegistrationIsOptional")) {
set("settings.restrictions.allowAllCommandsIfRegistrationIsOptional", false);
changes = true;
}
if (!contains("settings.security.unsafePasswords")) {
List<String> str = new ArrayList<>();
str.add("123456");
str.add("password");
set("settings.security.unsafePasswords", str);
changes = true;
}
if (!contains("Protection.countriesBlacklist")) {
countriesBlacklist = new ArrayList<>();
countriesBlacklist.add("A1");
set("Protection.countriesBlacklist", countriesBlacklist);
changes = true;
}
if (!contains("settings.helpHeader")) {
set("settings.helpHeader", "AuthMeReloaded");
changes = true;
}
if (!contains("settings.broadcastWelcomeMessage")) {
set("settings.broadcastWelcomeMessage", false);
changes = true;
}
if (!contains("settings.registration.forceKickAfterRegister")) {
set("settings.registration.forceKickAfterRegister", false);
changes = true;
}
if (!contains("settings.registration.forceLoginAfterRegister")) {
set("settings.registration.forceLoginAfterRegister", false);
changes = true;
}
if (!contains("DataSource.mySQLColumnLogged")) {
set("DataSource.mySQLColumnLogged", "isLogged");
changes = true;
}
if (!contains("settings.restrictions.spawnPriority")) {
set("settings.restrictions.spawnPriority", "authme,essentials,multiverse,default");
changes = true;
}
if (!contains("settings.restrictions.maxLoginPerIp")) {
set("settings.restrictions.maxLoginPerIp", 0);
changes = true;
}
if (!contains("settings.restrictions.maxJoinPerIp")) {
set("settings.restrictions.maxJoinPerIp", 0);
changes = true;
}
if (!contains("VeryGames.enableIpCheck")) {
set("VeryGames.enableIpCheck", false);
changes = true;
}
if (configFile.getString("settings.restrictions.allowedNicknameCharacters").equals("[a-zA-Z0-9_?]*")) {
set("settings.restrictions.allowedNicknameCharacters", "[a-zA-Z0-9_]*");
changes = true;
}
if (contains("settings.delayJoinMessage")) {
set("settings.delayJoinMessage", null);
changes = true;
}
if (!contains("settings.delayJoinLeaveMessages")) {
set("settings.delayJoinLeaveMessages", true);
changes = true;
}
if (!contains("settings.restrictions.noTeleport")) {
set("settings.restrictions.noTeleport", false);
changes = true;
}
if (contains("Converter.Rakamak.newPasswordHash")) {
set("Converter.Rakamak.newPasswordHash", null);
changes = true;
}
if (!contains("Converter.CrazyLogin.fileName")) {
set("Converter.CrazyLogin.fileName", "accounts.db");
changes = true;
}
if (!contains("settings.restrictions.allowedPasswordCharacters")) {
set("settings.restrictions.allowedPasswordCharacters", "[\\x21-\\x7E]*");
changes = true;
}
if (!contains("settings.applyBlindEffect")) {
set("settings.applyBlindEffect", false);
changes = true;
}
if (!contains("Email.emailBlacklisted")) {
set("Email.emailBlacklisted", new ArrayList<String>());
changes = true;
}
if (contains("Performances")) {
set("Performances", null);
changes = true;
}
if (contains("Passpartu.enablePasspartu")) {
set("Passpartu.enablePasspartu", null);
changes = true;
}
if (contains("Passpartu")) {
set("Passpartu", null);
changes = true;
}
if (!contains("Email.emailWhitelisted")) {
set("Email.emailWhitelisted", new ArrayList<String>());
changes = true;
}
if (!contains("settings.forceRegisterCommands")) {
set("settings.forceRegisterCommands", new ArrayList<String>());
changes = true;
}
if (!contains("settings.forceRegisterCommandsAsConsole")) {
set("settings.forceRegisterCommandsAsConsole", new ArrayList<String>());
changes = true;
}
if (!contains("Hooks.customAttributes")) {
set("Hooks.customAttributes", false);
changes = true;
}
if (!contains("Purge.removePermissions")) {
set("Purge.removePermissions", false);
changes = true;
}
if (contains("Hooks.notifications")) {
set("Hooks.notifications", null);
changes = true;
}
if (contains("Hooks.chestshop")) {
set("Hooks.chestshop", null);
changes = true;
}
if (contains("Hooks.legacyChestshop")) {
set("Hooks.legacyChestshop", null);
changes = true;
}
if (!contains("Email.generateImage")) {
set("Email.generateImage", false);
changes = true;
}
if (!contains("DataSource.mySQLRealName")) {
set("DataSource.mySQLRealName", "realname");
changes = true;
}
if (!contains("settings.preventOtherCase")) {
set("settings.preventOtherCase", false);
changes = true;
}
if (contains("Email.mailText")) {
set("Email.mailText", null);
ConsoleLogger.showError("Remove Email.mailText from config, we now use the email.html file");
}
if (!contains("Security.stop.kickPlayersBeforeStopping")) {
set("Security.stop.kickPlayersBeforeStopping", true);
changes = true;
}
if (!contains("Email.emailOauth2Token"))
set("Email.emailOauth2Token", "");
if (!contains("Hooks.sendPlayerTo")) {
set("Hooks.sendPlayerTo", "");
changes = true;
}
if (changes) {
save();
plugin.getLogger().warning("Merged new Config Options - I'm not an error, please don't report me");
plugin.getLogger().warning("Please check your config.yml file for new configs!");
}
}
private static boolean contains(String path) {
return configFile.contains(path);
}
// public because it's used in AuthMe at one place
/**
* @param path String
* @param value String
*/
public void set(String path, Object value) {
configFile.set(path, value);
}
/**
* Saves current configuration (plus defaults) to disk.
* <p>
@ -769,7 +344,7 @@ public final class Settings {
*
* @return True if saved successfully
*/
public final boolean saveDefaults() {
private boolean saveDefaults() {
configFile.options()
.copyDefaults(true)
.copyHeader(true);

View File

@ -0,0 +1,139 @@
package fr.xephi.authme.settings;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import static fr.xephi.authme.settings.properties.RestrictionSettings.ALLOWED_NICKNAME_CHARACTERS;
import static java.lang.String.format;
/**
* Service for verifying that the configuration is up-to-date.
*/
public final class SettingsMigrationService {
private SettingsMigrationService() {
}
/**
* Checks the config file and does any necessary migrations.
*
* @param configuration The file configuration to check and migrate
* @param propertyMap The property map of all existing properties
* @param pluginFolder The plugin folder
* @return True if there is a change and the config must be saved, false if the config is up-to-date
*/
public static boolean checkAndMigrate(FileConfiguration configuration, PropertyMap propertyMap, File pluginFolder) {
return performMigrations(configuration, pluginFolder) || hasDeprecatedProperties(configuration)
|| !containsAllSettings(configuration, propertyMap);
}
private static boolean performMigrations(FileConfiguration configuration, File pluginFolder) {
boolean changes = false;
if ("[a-zA-Z0-9_?]*".equals(configuration.getString(ALLOWED_NICKNAME_CHARACTERS.getPath()))) {
configuration.set(ALLOWED_NICKNAME_CHARACTERS.getPath(), "[a-zA-Z0-9_]*");
changes = true;
}
changes = changes || performMailTextToFileMigration(configuration, pluginFolder);
return changes;
}
@VisibleForTesting
static boolean containsAllSettings(FileConfiguration configuration, PropertyMap propertyMap) {
for (Property<?> property : propertyMap.keySet()) {
if (!property.isPresent(configuration)) {
return false;
}
}
return true;
}
private static boolean hasDeprecatedProperties(FileConfiguration configuration) {
String[] deprecatedProperties = {
"Converter.Rakamak.newPasswordHash", "Hooks.chestshop", "Hooks.legacyChestshop", "Hooks.notifications",
"Passpartu", "Performances", "settings.delayJoinMessage", "settings.restrictions.enablePasswordVerifier",
"Xenoforo.predefinedSalt"};
for (String deprecatedPath : deprecatedProperties) {
if (configuration.contains(deprecatedPath)) {
return true;
}
}
return false;
}
// --------
// Specific migrations
// --------
/**
* Check if {@code Email.mailText} is present and move it to the Email.html file if it doesn't exist yet.
*
* @param configuration The file configuration to verify
* @param dataFolder The plugin data folder
* @return True if a migration has been completed, false otherwise
*/
private static boolean performMailTextToFileMigration(FileConfiguration configuration, File dataFolder) {
final String oldSettingPath = "Email.mailText";
if (!configuration.contains(oldSettingPath)) {
return false;
}
final File emailFile = new File(dataFolder, "email.html");
final String mailText = configuration.getString(oldSettingPath)
.replace("<playername>", "<playername />")
.replace("<servername>", "<servername />")
.replace("<generatedpass>", "<generatedpass />")
.replace("<image>", "<image />");
if (!emailFile.exists()) {
try (FileWriter fw = new FileWriter(emailFile)) {
fw.write(mailText);
} catch (IOException e) {
ConsoleLogger.logException("Could not create email.html configuration file:", e);
}
}
return true;
}
/**
* Copy a resource file (from the JAR) to the given file if it doesn't exist.
*
* @param destinationFile The file to check and copy to (outside of JAR)
* @param resourcePath Absolute path to the resource file (path to file within JAR)
* @return False if the file does not exist and could not be copied, true otherwise
*/
public static boolean copyFileFromResource(File destinationFile, String resourcePath) {
if (destinationFile.exists()) {
return true;
} else if (!destinationFile.getParentFile().exists() && !destinationFile.getParentFile().mkdirs()) {
ConsoleLogger.showError("Cannot create parent directories for '" + destinationFile + "'");
return false;
}
// ClassLoader#getResourceAsStream does not deal with the '\' path separator: replace to '/'
final String normalizedPath = resourcePath.replace("\\", "/");
try (InputStream is = AuthMe.class.getClassLoader().getResourceAsStream(normalizedPath)) {
if (is == null) {
ConsoleLogger.showError(format("Cannot copy resource '%s' to file '%s': cannot load resource",
resourcePath, destinationFile.getPath()));
} else {
Files.copy(is, destinationFile.toPath());
return true;
}
} catch (IOException e) {
ConsoleLogger.logException(format("Cannot copy resource '%s' to file '%s':",
resourcePath, destinationFile.getPath()), e);
}
return false;
}
}

View File

@ -1,155 +0,0 @@
package fr.xephi.authme.settings.custom;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* The new settings manager.
*/
public class NewSetting {
private File file;
private FileConfiguration configuration;
/**
* Constructor.
* Loads the file as YAML and checks its integrity.
*
* @param configuration The configuration to interact with
* @param file The configuration file
*/
public NewSetting(FileConfiguration configuration, File file) {
this.configuration = configuration;
this.file = file;
// TODO ljacqu 20160109: Ensure that save() works as desired (i.e. that it always produces valid YAML)
// and then uncomment the lines below. Once this is uncommented, the checks in the old Settings.java should
// be removed as we should check to rewrite the config.yml file only at one place
// --------
// PropertyMap propertyMap = SettingsFieldRetriever.getAllPropertyFields();
// if (!containsAllSettings(propertyMap)) {
// save(propertyMap);
// }
}
/**
* Constructor for testing purposes, allowing more options.
*
* @param configuration The FileConfiguration object to use
* @param file The file to write to
* @param propertyMap The property map whose properties should be verified for presence, or null to skip this
*/
@VisibleForTesting
NewSetting(FileConfiguration configuration, File file, PropertyMap propertyMap) {
this.configuration = configuration;
this.file = file;
if (propertyMap != null && !containsAllSettings(propertyMap)) {
save(propertyMap);
}
}
/**
* Get the given property from the configuration.
*
* @param property The property to retrieve
* @param <T> The property's type
* @return The property's value
*/
public <T> T getProperty(Property<T> property) {
return property.getFromFile(configuration);
}
public void save() {
save(SettingsFieldRetriever.getAllPropertyFields());
}
public void save(PropertyMap propertyMap) {
try (FileWriter writer = new FileWriter(file)) {
writer.write("");
// Contains all but the last node of the setting, e.g. [DataSource, mysql] for "DataSource.mysql.username"
List<String> currentPath = new ArrayList<>();
for (Map.Entry<Property<?>, String[]> entry : propertyMap.entrySet()) {
Property<?> property = entry.getKey();
// Handle properties
List<String> propertyPath = Arrays.asList(property.getPath().split("\\."));
List<String> commonPathParts = CollectionUtils.filterCommonStart(
currentPath, propertyPath.subList(0, propertyPath.size() - 1));
List<String> newPathParts = CollectionUtils.getRange(propertyPath, commonPathParts.size());
if (commonPathParts.isEmpty()) {
writer.append("\n");
}
int indentationLevel = commonPathParts.size();
if (newPathParts.size() > 1) {
for (String path : newPathParts.subList(0, newPathParts.size() - 1)) {
writer.append("\n")
.append(indent(indentationLevel))
.append(path)
.append(": ");
++indentationLevel;
}
}
for (String comment : entry.getValue()) {
writer.append("\n")
.append(indent(indentationLevel))
.append("# ")
.append(comment);
}
writer.append("\n")
.append(indent(indentationLevel))
.append(CollectionUtils.getRange(newPathParts, newPathParts.size() - 1).get(0))
.append(": ");
List<String> yamlLines = property.formatValueAsYaml(configuration);
String delim = "";
for (String yamlLine : yamlLines) {
writer.append(delim).append(yamlLine);
delim = "\n" + indent(indentationLevel);
}
currentPath = propertyPath.subList(0, propertyPath.size() - 1);
}
writer.flush();
writer.close();
} catch (IOException e) {
ConsoleLogger.logException("Could not save config file:", e);
}
}
@VisibleForTesting
boolean containsAllSettings(PropertyMap propertyMap) {
for (Property<?> property : propertyMap.keySet()) {
if (!property.isPresent(configuration)) {
return false;
}
}
return true;
}
private static String indent(int level) {
// YAML uses indentation of 4 spaces
StringBuilder sb = new StringBuilder(level * 4);
for (int i = 0; i < level; ++i) {
sb.append(" ");
}
return sb.toString();
}
}

View File

@ -1,13 +1,11 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.FileConfiguration;
import java.util.List;
import static java.util.Arrays.asList;
import org.yaml.snakeyaml.Yaml;
/**
* Enum property type.
*
* @param <E> The enum class
*/
class EnumPropertyType<E extends Enum<E>> extends PropertyType<E> {
@ -28,17 +26,17 @@ class EnumPropertyType<E extends Enum<E>> extends PropertyType<E> {
return mappedValue != null ? mappedValue : property.getDefaultValue();
}
@Override
protected List<String> asYaml(E value) {
return asList("'" + value + "'");
}
@Override
public boolean contains(Property<E> property, FileConfiguration configuration) {
return super.contains(property, configuration)
&& mapToEnum(configuration.getString(property.getPath())) != null;
}
@Override
public String toYaml(E value, Yaml simpleYaml, Yaml singleQuoteYaml) {
return singleQuoteYaml.dump(value.name());
}
private E mapToEnum(String value) {
for (E entry : clazz.getEnumConstants()) {
if (entry.name().equalsIgnoreCase(value)) {

View File

@ -1,13 +1,14 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.FileConfiguration;
import org.yaml.snakeyaml.Yaml;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
/**
* Properties (i.e. a <i>setting</i> that is read from the config.yml file).
* Property class, representing a <i>setting</i> that is read from the config.yml file.
*/
public class Property<T> {
@ -22,15 +23,43 @@ public class Property<T> {
this.defaultValue = defaultValue;
}
/**
* Create a new property. See also {@link #newProperty(PropertyType, String, Object[])} for lists and
* {@link #newProperty(Class, String, Enum)}.
*
* @param type The property type
* @param path The property's path
* @param defaultValue The default value
* @param <T> The type of the property
* @return The created property
*/
public static <T> Property<T> newProperty(PropertyType<T> type, String path, T defaultValue) {
return new Property<>(type, path, defaultValue);
}
/**
* Create a new list property.
*
* @param type The list type of the property
* @param path The property's path
* @param defaultValues The default value's items
* @param <U> The list type
* @return The created list property
*/
@SafeVarargs
public static <U> Property<List<U>> newProperty(PropertyType<List<U>> type, String path, U... defaultValues) {
return new Property<>(type, path, Arrays.asList(defaultValues));
}
/**
* Create a new enum property.
*
* @param clazz The enum class
* @param path The property's path
* @param defaultValue The default value
* @param <E> The enum type
* @return The created enum property
*/
public static <E extends Enum<E>> Property<E> newProperty(Class<E> clazz, String path, E defaultValue) {
return new Property<>(new EnumPropertyType<>(clazz), path, defaultValue);
}
@ -53,9 +82,8 @@ public class Property<T> {
// -----
// Hooks to the PropertyType methods
// -----
/**
* Get the property value from the given configuration.
* Get the property value from the given configuration &ndash; guaranteed to never return null.
*
* @param configuration The configuration to read the value from
* @return The value, or default if not present
@ -64,16 +92,6 @@ public class Property<T> {
return type.getFromFile(this, configuration);
}
/**
* Format the property value as YAML.
*
* @param configuration The configuration to read the value from
* @return The property value as YAML
*/
public List<String> formatValueAsYaml(FileConfiguration configuration) {
return type.asYaml(this, configuration);
}
/**
* Return whether or not the given configuration file contains the property.
*
@ -84,10 +102,21 @@ public class Property<T> {
return type.contains(this, configuration);
}
/**
* Format the property's value as YAML.
*
* @param configuration The file configuration
* @param simpleYaml YAML object (default)
* @param singleQuoteYaml YAML object using single quotes
* @return The generated YAML
*/
public String toYaml(FileConfiguration configuration, Yaml simpleYaml, Yaml singleQuoteYaml) {
return type.toYaml(getFromFile(configuration), simpleYaml, singleQuoteYaml);
}
// -----
// Trivial getters
// -----
/**
* Return the default value of the property.
*

View File

@ -1,12 +1,10 @@
package fr.xephi.authme.settings.domain;
import org.bukkit.configuration.file.FileConfiguration;
import org.yaml.snakeyaml.Yaml;
import java.util.ArrayList;
import java.util.List;
import static java.util.Arrays.asList;
/**
* Handles a certain property type and provides type-specific functionality.
*
@ -16,7 +14,6 @@ import static java.util.Arrays.asList;
public abstract class PropertyType<T> {
public static final PropertyType<Boolean> BOOLEAN = new BooleanProperty();
public static final PropertyType<Double> DOUBLE = new DoubleProperty();
public static final PropertyType<Integer> INTEGER = new IntegerProperty();
public static final PropertyType<String> STRING = new StringProperty();
public static final PropertyType<List<String>> STRING_LIST = new StringListProperty();
@ -30,17 +27,6 @@ public abstract class PropertyType<T> {
*/
public abstract T getFromFile(Property<T> property, FileConfiguration configuration);
/**
* Return the property's value (or its default) as YAML.
*
* @param property The property to transform
* @param configuration The YAML configuration to read from
* @return The read value or its default in YAML format
*/
public List<String> asYaml(Property<T> property, FileConfiguration configuration) {
return asYaml(getFromFile(property, configuration));
}
/**
* Return whether the property is present in the given configuration.
*
@ -53,12 +39,16 @@ public abstract class PropertyType<T> {
}
/**
* Transform the given value to YAML.
* Format the value as YAML.
*
* @param value The value to transform
* @return The value as YAML
* @param value The value to export
* @param simpleYaml YAML object (default)
* @param singleQuoteYaml YAML object set to use single quotes
* @return The generated YAML
*/
protected abstract List<String> asYaml(T value);
public String toYaml(T value, Yaml simpleYaml, Yaml singleQuoteYaml) {
return simpleYaml.dump(value);
}
/**
@ -69,26 +59,6 @@ public abstract class PropertyType<T> {
public Boolean getFromFile(Property<Boolean> property, FileConfiguration configuration) {
return configuration.getBoolean(property.getPath(), property.getDefaultValue());
}
@Override
protected List<String> asYaml(Boolean value) {
return asList(value ? "true" : "false");
}
}
/**
* Double property.
*/
private static final class DoubleProperty extends PropertyType<Double> {
@Override
public Double getFromFile(Property<Double> property, FileConfiguration configuration) {
return configuration.getDouble(property.getPath(), property.getDefaultValue());
}
@Override
protected List<String> asYaml(Double value) {
return asList(String.valueOf(value));
}
}
/**
@ -99,11 +69,6 @@ public abstract class PropertyType<T> {
public Integer getFromFile(Property<Integer> property, FileConfiguration configuration) {
return configuration.getInt(property.getPath(), property.getDefaultValue());
}
@Override
protected List<String> asYaml(Integer value) {
return asList(String.valueOf(value));
}
}
/**
@ -114,15 +79,9 @@ public abstract class PropertyType<T> {
public String getFromFile(Property<String> property, FileConfiguration configuration) {
return configuration.getString(property.getPath(), property.getDefaultValue());
}
@Override
protected List<String> asYaml(String value) {
return asList(toYamlLiteral(value));
}
public static String toYamlLiteral(String str) {
// TODO: Need to handle new lines properly
return "'" + str.replace("'", "''") + "'";
public String toYaml(String value, Yaml simpleYaml, Yaml singleQuoteYaml) {
return singleQuoteYaml.dump(value);
}
}
@ -139,23 +98,18 @@ public abstract class PropertyType<T> {
}
@Override
protected List<String> asYaml(List<String> value) {
if (value.isEmpty()) {
return asList("[]");
}
List<String> resultLines = new ArrayList<>();
resultLines.add(""); // add
for (String entry : value) {
// TODO: StringProperty#toYamlLiteral will return List<String>...
resultLines.add(" - " + StringProperty.toYamlLiteral(entry));
}
return resultLines;
public boolean contains(Property<List<String>> property, FileConfiguration configuration) {
return configuration.contains(property.getPath()) && configuration.isList(property.getPath());
}
@Override
public boolean contains(Property<List<String>> property, FileConfiguration configuration) {
return configuration.contains(property.getPath()) && configuration.isList(property.getPath());
public String toYaml(List<String> value, Yaml simpleYaml, Yaml singleQuoteYaml) {
String yaml = singleQuoteYaml.dump(value);
// If the property is a non-empty list we need to append a new line because it will be
// something like the following, which requires a new line:
// - 'item 1'
// - 'second item in list'
return value.isEmpty() ? yaml : "\n" + yaml;
}
}

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.settings.domain.Comment;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.settings.domain.Comment;
@ -30,6 +30,10 @@ public class SecuritySettings implements SettingsClass {
public static final Property<Boolean> REMOVE_PASSWORD_FROM_CONSOLE =
newProperty("Security.console.removePassword", true);
@Comment("Copy AuthMe log output in a separate file as well?")
public static final Property<Boolean> USE_LOGGING =
newProperty("Security.console.logConsole", true);
@Comment("Player need to put a captcha when he fails too lot the password")
public static final Property<Boolean> USE_CAPTCHA =
newProperty("Security.captcha.useCaptcha", false);

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Comment;
import fr.xephi.authme.settings.domain.Property;
@ -12,9 +12,10 @@ import java.util.Arrays;
import java.util.List;
/**
* Utility class responsible for the retrieval of all {@link Property} fields via reflections.
* Utility class responsible for retrieving all {@link Property} fields
* from {@link SettingsClass} implementations via reflection.
*/
final class SettingsFieldRetriever {
public final class SettingsFieldRetriever {
/** The classes to scan for properties. */
private static final List<Class<? extends SettingsClass>> CONFIGURATION_CLASSES = Arrays.asList(
@ -37,7 +38,7 @@ final class SettingsFieldRetriever {
for (Class<?> clazz : CONFIGURATION_CLASSES) {
Field[] declaredFields = clazz.getDeclaredFields();
for (Field field : declaredFields) {
Property property = getFieldIfRelevant(field);
Property property = getPropertyField(field);
if (property != null) {
properties.put(property, getCommentsForField(field));
}
@ -53,7 +54,13 @@ final class SettingsFieldRetriever {
return new String[0];
}
private static Property<?> getFieldIfRelevant(Field field) {
/**
* Return the given field's value if it is a static {@link Property}.
*
* @param field The field's value to return
* @return The property the field defines, or null if not applicable
*/
private static Property<?> getPropertyField(Field field) {
field.setAccessible(true);
if (field.isAccessible() && Property.class.equals(field.getType()) && Modifier.isStatic(field.getModifiers())) {
try {

View File

@ -52,11 +52,12 @@ public final class CollectionUtils {
}
/**
* @param <T> element
* @param coll Collection
* @return boolean Boolean
* Null-safe way to check whether a collection is empty or not.
*
* @param coll The collection to verify
* @return True if the collection is null or empty, false otherwise
*/
public static <T> boolean isEmpty(Collection<T> coll) {
public static boolean isEmpty(Collection<?> coll) {
return coll == null || coll.isEmpty();
}

View File

@ -4,6 +4,7 @@ import net.ricecode.similarity.LevenshteinDistanceStrategy;
import net.ricecode.similarity.StringSimilarityService;
import net.ricecode.similarity.StringSimilarityServiceImpl;
import java.io.File;
import java.util.Arrays;
/**
@ -37,12 +38,12 @@ public final class StringUtils {
}
/**
* Returns whether the given string contains any of the provided elements.
* Return whether the given string contains any of the provided elements.
*
* @param str the string to analyze
* @param pieces the items to check the string for
* @param str The string to analyze
* @param pieces The items to check the string for
*
* @return true if the string contains at least one of the items
* @return True if the string contains at least one of the items
*/
public static boolean containsAny(String str, String... pieces) {
if (str == null) {
@ -60,21 +61,21 @@ public final class StringUtils {
* Null-safe method for checking whether a string is empty. Note that the string
* is trimmed, so this method also considers a string with whitespace as empty.
*
* @param str the string to verify
* @param str The string to verify
*
* @return true if the string is empty, false otherwise
* @return True if the string is empty, false otherwise
*/
public static boolean isEmpty(String str) {
return str == null || str.trim().isEmpty();
}
/**
* Joins a list of elements into a single string with the specified delimiter.
* Join a list of elements into a single string with the specified delimiter.
*
* @param delimiter the delimiter to use
* @param elements the elements to join
* @param delimiter The delimiter to use
* @param elements The elements to join
*
* @return a new String that is composed of the elements separated by the delimiter
* @return A new String that is composed of the elements separated by the delimiter
*/
public static String join(String delimiter, Iterable<String> elements) {
if (delimiter == null) {
@ -95,12 +96,12 @@ public final class StringUtils {
}
/**
* Joins a list of elements into a single string with the specified delimiter.
* Join a list of elements into a single string with the specified delimiter.
*
* @param delimiter the delimiter to use
* @param elements the elements to join
* @param delimiter The delimiter to use
* @param elements The elements to join
*
* @return a new String that is composed of the elements separated by the delimiter
* @return A new String that is composed of the elements separated by the delimiter
*/
public static String join(String delimiter, String... elements) {
return join(delimiter, Arrays.asList(elements));
@ -117,4 +118,15 @@ public final class StringUtils {
return "[" + th.getClass().getSimpleName() + "]: " + th.getMessage();
}
/**
* Construct a file path from the given elements, i.e. separate the given elements by the file separator.
*
* @param elements The elements to create a path with
*
* @return The created path
*/
public static String makePath(String... elements) {
return join(File.separator, elements);
}
}

View File

@ -7,8 +7,10 @@ import fr.xephi.authme.cache.limbo.LimboCache;
import fr.xephi.authme.cache.limbo.LimboPlayer;
import fr.xephi.authme.events.AuthMeTeleportEvent;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.World;
@ -19,6 +21,7 @@ import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
/**
* Utility class for various operations used in the codebase.
@ -254,6 +257,30 @@ public final class Utils {
}
}
public static boolean isEmailCorrect(String email, NewSetting settings) {
if (!email.contains("@") || "your@email.com".equalsIgnoreCase(email)) {
return false;
}
final String emailDomain = email.split("@")[1];
List<String> whitelist = settings.getProperty(EmailSettings.DOMAIN_WHITELIST);
if (!CollectionUtils.isEmpty(whitelist)) {
return containsIgnoreCase(whitelist, emailDomain);
}
List<String> blacklist = settings.getProperty(EmailSettings.DOMAIN_BLACKLIST);
return CollectionUtils.isEmpty(blacklist) || !containsIgnoreCase(blacklist, emailDomain);
}
private static boolean containsIgnoreCase(Collection<String> coll, String needle) {
for (String entry : coll) {
if (entry.equalsIgnoreCase(needle)) {
return true;
}
}
return false;
}
/**
*/
public enum GroupType {

View File

@ -308,6 +308,8 @@ Security:
noConsoleSpam: false
# Replace passwords in the console when player type a command like /login
removePassword: true
# Copy AuthMe log output in a separate file as well?
logConsole: true
captcha:
# Player need to put a captcha when he fails too lot the password
useCaptcha: false

View File

@ -0,0 +1,3 @@
Welcome {PLAYER} on {SERVER} server
This server uses AuthMeReloaded protection!

View File

@ -0,0 +1,20 @@
package fr.xephi.authme;
import org.mockito.Mockito;
import java.util.logging.Logger;
/**
* Test initializer for {@link ConsoleLogger}.
*/
public class ConsoleLoggerTestInitializer {
private ConsoleLoggerTestInitializer() {
}
public static Logger setupLogger() {
Logger logger = Mockito.mock(Logger.class);
ConsoleLogger.setLogger(logger);
return logger;
}
}

View File

@ -8,8 +8,8 @@ import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.settings.custom.NewSetting;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.settings.domain.Property;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
@ -18,6 +18,7 @@ import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import java.io.File;
import java.util.Arrays;
import java.util.List;
@ -95,19 +96,6 @@ public class CommandServiceTest {
verify(commandMapper).mapPartsToCommand(sender, commandParts);
}
@Test
@Ignore
public void shouldRunTaskInAsync() {
// given
Runnable runnable = mock(Runnable.class);
// when
commandService.runTaskAsynchronously(runnable);
// then
// TODO ljacqu 20151226: AuthMe#getServer() is final, i.e. not mockable
}
@Test
public void shouldGetDataSource() {
// given
@ -193,10 +181,40 @@ public class CommandServiceTest {
given(settings.getProperty(property)).willReturn(7);
// when
int result = settings.getProperty(property);
int result = commandService.getProperty(property);
// then
assertThat(result, equalTo(7));
verify(settings).getProperty(property);
}
@Test
public void shouldReloadMessages() {
// given
File file = new File("some/bogus-file.test");
// when
commandService.reloadMessages(file);
// then
verify(messages).reload(file);
}
@Test
public void shouldReturnSettings() {
// given/when
NewSetting result = commandService.getSettings();
// then
assertThat(result, equalTo(settings));
}
@Test
public void shouldReturnAuthMe() {
// given/when
AuthMe result = commandService.getAuthMe();
// then
assertThat(result, equalTo(authMe));
}
}

View File

@ -5,7 +5,7 @@ import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.ExecutableCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;

View File

@ -4,8 +4,8 @@ import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.custom.RestrictionSettings;
import fr.xephi.authme.settings.custom.SecuritySettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.task.ChangePasswordTask;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.Server;

View File

@ -6,7 +6,6 @@ import fr.xephi.authme.command.FoundResultStatus;
import fr.xephi.authme.command.TestCommandsUtil;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.ChatColor;
import org.bukkit.command.CommandSender;
@ -40,22 +39,22 @@ import static org.mockito.Mockito.mock;
*/
public class HelpProviderTest {
private static final String HELP_HEADER = "Help";
private static Set<CommandDescription> commands;
private HelpProvider helpProvider;
private PermissionsManager permissionsManager;
private CommandSender sender;
private static Set<CommandDescription> commands;
@BeforeClass
public static void setUpCommands() {
WrapperMock.createInstance();
Settings.helpHeader = "Help";
commands = TestCommandsUtil.generateCommands();
}
@Before
public void setUpHelpProvider() {
permissionsManager = mock(PermissionsManager.class);
helpProvider = new HelpProvider(permissionsManager);
helpProvider = new HelpProvider(permissionsManager, HELP_HEADER);
sender = mock(CommandSender.class);
}
@ -70,7 +69,7 @@ public class HelpProviderTest {
// then
assertThat(lines, hasSize(5));
assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP"));
assertThat(lines.get(0), containsString(HELP_HEADER + " HELP"));
assertThat(removeColors(lines.get(1)), containsString("Command: /authme login <password>"));
assertThat(removeColors(lines.get(2)), containsString("Short description: login cmd"));
assertThat(removeColors(lines.get(3)), equalTo("Detailed description:"));
@ -88,7 +87,7 @@ public class HelpProviderTest {
// then
assertThat(lines, hasSize(4));
assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP"));
assertThat(lines.get(0), containsString(HELP_HEADER + " HELP"));
assertThat(removeColors(lines.get(1)), equalTo("Arguments:"));
assertThat(removeColors(lines.get(2)), containsString("password: 'password' argument description"));
assertThat(removeColors(lines.get(3)), containsString("confirmation: 'confirmation' argument description"));
@ -279,7 +278,7 @@ public class HelpProviderTest {
// then
assertThat(lines, hasSize(2));
assertThat(lines.get(0), containsString(Settings.helpHeader + " HELP"));
assertThat(lines.get(0), containsString(HELP_HEADER + " HELP"));
assertThat(removeColors(lines.get(1)), containsString("Command: /authme register <password> <confirmation>"));
}

View File

@ -219,8 +219,8 @@ public class Log4JFilterTest {
* Mocks a {@link Message} object and makes it return the given formatted message.
*
* @param formattedMessage the formatted message the mock should return
* @return Message mock */
* @return Message mock
*/
private static Message mockMessage(String formattedMessage) {
Message message = Mockito.mock(Message.class);
when(message.getFormattedMessage()).thenReturn(formattedMessage);

View File

@ -1,10 +1,11 @@
package fr.xephi.authme.output;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
@ -28,6 +29,12 @@ public class MessagesIntegrationTest {
private static final String YML_TEST_FILE = "messages_test.yml";
private Messages messages;
@BeforeClass
public static void setup() {
WrapperMock.createInstance();
ConsoleLoggerTestInitializer.setupLogger();
}
/**
* Loads the messages in the file {@code messages_test.yml} in the test resources folder.
* The file does not contain all messages defined in {@link MessageKey} and its contents
@ -35,17 +42,12 @@ public class MessagesIntegrationTest {
*/
@Before
public void setUpMessages() {
WrapperMock.createInstance();
Settings.messagesLanguage = "en";
URL url = getClass().getClassLoader().getResource(YML_TEST_FILE);
if (url == null) {
throw new RuntimeException("File '" + YML_TEST_FILE + "' could not be loaded");
}
Settings.messageFile = new File(url.getFile());
Settings.messagesLanguage = "en";
messages = Messages.getInstance();
messages = new Messages(new File(url.getFile()));
}
@Test

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.WrapperMock;
import org.junit.BeforeClass;
@ -13,6 +14,7 @@ public class BcryptTest extends AbstractEncryptionMethodTest {
public static void setUpSettings() {
WrapperMock.createInstance();
Settings.bCryptLog2Rounds = 8;
ConsoleLoggerTestInitializer.setupLogger();
}
public BcryptTest() {

View File

@ -1,5 +1,6 @@
package fr.xephi.authme.security.crypts;
import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.util.WrapperMock;
import org.junit.BeforeClass;
@ -9,8 +10,9 @@ import org.junit.BeforeClass;
public class XFBCRYPTTest extends AbstractEncryptionMethodTest {
@BeforeClass
public static void setUpWrapper() {
public static void setup() {
WrapperMock.createInstance();
ConsoleLoggerTestInitializer.setupLogger();
}
public XFBCRYPTTest() {

View File

@ -1,7 +1,7 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.SettingsFieldRetriever;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.StringUtils;
import org.bukkit.configuration.MemorySection;
@ -34,16 +34,14 @@ public class ConfigFileConsistencyTest {
// given
URL url = this.getClass().getResource(CONFIG_FILE);
File configFile = new File(url.getFile());
NewSetting settings = new NewSetting(YamlConfiguration.loadConfiguration(configFile), new File("bogus"), null);
FileConfiguration configuration = YamlConfiguration.loadConfiguration(configFile);
// when
boolean result = settings.containsAllSettings(SettingsFieldRetriever.getAllPropertyFields());
boolean result = SettingsMigrationService.containsAllSettings(
configuration, SettingsFieldRetriever.getAllPropertyFields());
// then
if (!result) {
FileConfiguration configuration =
(FileConfiguration) ReflectionTestUtils.getFieldValue(NewSetting.class, settings, "configuration");
Set<String> knownProperties = getAllKnownPropertyPaths();
List<String> missingProperties = new ArrayList<>();
for (String path : knownProperties) {

View File

@ -1,11 +1,13 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings;
import com.google.common.collect.ImmutableMap;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
@ -13,8 +15,10 @@ import java.lang.reflect.Field;
import java.net.URL;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import static fr.xephi.authme.settings.domain.Property.newProperty;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertThat;
import static org.junit.Assume.assumeThat;
@ -28,40 +32,28 @@ public class NewSettingIntegrationTest {
private static final String COMPLETE_FILE = "config-sample-values.yml";
/** File name of the sample config missing certain {@link TestConfiguration} values. */
private static final String INCOMPLETE_FILE = "config-incomplete-sample.yml";
/** File name for testing difficult values. */
private static final String DIFFICULT_FILE = "config-difficult-values.yml";
private static PropertyMap propertyMap;
@BeforeClass
public static void generatePropertyMap() {
propertyMap = new PropertyMap();
for (Field field : TestConfiguration.class.getDeclaredFields()) {
Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName());
if (fieldValue instanceof Property<?>) {
Property<?> property = (Property<?>) fieldValue;
String[] comments = new String[]{"Comment for '" + property.getPath() + "'"};
propertyMap.put(property, comments);
}
}
}
private static PropertyMap propertyMap = generatePropertyMap();
@Test
public void shouldLoadAndReadAllProperties() {
// given
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(getConfigFile(COMPLETE_FILE));
File file = new File("unused");
assumeThat(file.exists(), equalTo(false));
// when / then
NewSetting settings = new NewSetting(configuration, file, propertyMap);
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 22)
.put(TestConfiguration.SYSTEM_NAME, "Custom sys name")
.put(TestConfiguration.RATIO_LIMIT, -4.1)
.put(TestConfiguration.RATIO_ORDER, TestEnum.FIRST)
.put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia", "Burundi", "Colombia"))
.put(TestConfiguration.VERSION_NUMBER, 2492)
.put(TestConfiguration.SKIP_BORING_FEATURES, false)
.put(TestConfiguration.BORING_COLORS, Arrays.asList("beige", "gray"))
.put(TestConfiguration.DUST_LEVEL, 0.81)
.put(TestConfiguration.DUST_LEVEL, 2)
.put(TestConfiguration.USE_COOL_FEATURES, true)
.put(TestConfiguration.COOL_OPTIONS, Arrays.asList("Dinosaurs", "Explosions", "Big trucks"))
.build();
@ -89,12 +81,12 @@ public class NewSettingIntegrationTest {
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 22)
.put(TestConfiguration.SYSTEM_NAME, "[TestDefaultValue]")
.put(TestConfiguration.RATIO_LIMIT, 3.0)
.put(TestConfiguration.RATIO_ORDER, TestEnum.SECOND)
.put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia", "Burundi", "Colombia"))
.put(TestConfiguration.VERSION_NUMBER, 32046)
.put(TestConfiguration.SKIP_BORING_FEATURES, false)
.put(TestConfiguration.BORING_COLORS, Collections.EMPTY_LIST)
.put(TestConfiguration.DUST_LEVEL, 0.2)
.put(TestConfiguration.DUST_LEVEL, -1)
.put(TestConfiguration.USE_COOL_FEATURES, false)
.put(TestConfiguration.COOL_OPTIONS, Arrays.asList("Dinosaurs", "Explosions", "Big trucks"))
.build();
@ -104,6 +96,62 @@ public class NewSettingIntegrationTest {
}
}
/** Verify that "difficult cases" such as apostrophes in strings etc. are handled properly. */
@Test
public void shouldProperlyExportAnyValues() {
// given
File file = getConfigFile(DIFFICULT_FILE);
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(file);
assumeThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(false));
// Additional string properties
List<Property<String>> additionalProperties = Arrays.asList(
newProperty("more.string1", "it's a text with some \\'apostrophes'"),
newProperty("more.string2", "\tthis one\nhas some\nnew '' lines-test")
);
PropertyMap propertyMap = generatePropertyMap();
for (Property<?> property : additionalProperties) {
propertyMap.put(property, new String[0]);
}
// when
new NewSetting(configuration, file, propertyMap);
// reload the file as settings should hav been rewritten
configuration = YamlConfiguration.loadConfiguration(file);
// then
// assert that we won't rewrite the settings again! One rewrite should produce a valid, complete configuration
File unusedFile = new File("config-difficult-values.unused.yml");
NewSetting settings = new NewSetting(configuration, unusedFile, propertyMap);
assertThat(unusedFile.exists(), equalTo(false));
assertThat(configuration.contains(TestConfiguration.DUST_LEVEL.getPath()), equalTo(true));
Map<Property<?>, Object> expectedValues = ImmutableMap.<Property<?>, Object>builder()
.put(TestConfiguration.DURATION_IN_SECONDS, 20)
.put(TestConfiguration.SYSTEM_NAME, "A 'test' name")
.put(TestConfiguration.RATIO_ORDER, TestEnum.FOURTH)
.put(TestConfiguration.RATIO_FIELDS, Arrays.asList("Australia\\", "\tBurundi'", "Colombia?\n''"))
.put(TestConfiguration.VERSION_NUMBER, -1337)
.put(TestConfiguration.SKIP_BORING_FEATURES, false)
.put(TestConfiguration.BORING_COLORS, Arrays.asList("it's a difficult string!", "gray\nwith new lines\n"))
.put(TestConfiguration.DUST_LEVEL, -1)
.put(TestConfiguration.USE_COOL_FEATURES, true)
.put(TestConfiguration.COOL_OPTIONS, Collections.EMPTY_LIST)
.put(additionalProperties.get(0), additionalProperties.get(0).getDefaultValue())
.put(additionalProperties.get(1), additionalProperties.get(1).getDefaultValue())
.build();
for (Map.Entry<Property<?>, Object> entry : expectedValues.entrySet()) {
assertThat("Property '" + entry.getKey().getPath() + "' has expected value"
+ entry.getValue() + " but found " + settings.getProperty(entry.getKey()),
settings.getProperty(entry.getKey()), equalTo(entry.getValue()));
}
}
/**
* Return a {@link File} instance to an existing file in the target/test-classes folder.
*
* @return The generated File
*/
private File getConfigFile(String file) {
URL url = getClass().getClassLoader().getResource(file);
if (url == null) {
@ -112,4 +160,23 @@ public class NewSettingIntegrationTest {
return new File(url.getFile());
}
/**
* Generate a property map with all properties in {@link TestConfiguration}.
*
* @return The generated property map
*/
private static PropertyMap generatePropertyMap() {
WrapperMock.createInstance();
PropertyMap propertyMap = new PropertyMap();
for (Field field : TestConfiguration.class.getDeclaredFields()) {
Object fieldValue = ReflectionTestUtils.getFieldValue(TestConfiguration.class, null, field.getName());
if (fieldValue instanceof Property<?>) {
Property<?> property = (Property<?>) fieldValue;
String[] comments = new String[]{"Comment for '" + property.getPath() + "'"};
propertyMap.put(property, comments);
}
}
return propertyMap;
}
}

View File

@ -1,6 +1,9 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.properties.TestConfiguration;
import fr.xephi.authme.settings.properties.TestEnum;
import fr.xephi.authme.settings.propertymap.PropertyMap;
import org.bukkit.configuration.file.YamlConfiguration;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
@ -35,15 +38,15 @@ public class NewSettingTest {
setReturnValue(file, TestConfiguration.VERSION_NUMBER, 20);
setReturnValue(file, TestConfiguration.SKIP_BORING_FEATURES, true);
setReturnValue(file, TestConfiguration.RATIO_LIMIT, 4.25);
setReturnValue(file, TestConfiguration.RATIO_ORDER, TestEnum.THIRD);
setReturnValue(file, TestConfiguration.SYSTEM_NAME, "myTestSys");
// when / then
NewSetting settings = new NewSetting(file, new File("conf.txt"), null);
NewSetting settings = new NewSetting(file, new File("conf.txt"), (PropertyMap) null);
assertThat(settings.getProperty(TestConfiguration.VERSION_NUMBER), equalTo(20));
assertThat(settings.getProperty(TestConfiguration.SKIP_BORING_FEATURES), equalTo(true));
assertThat(settings.getProperty(TestConfiguration.RATIO_LIMIT), equalTo(4.25));
assertThat(settings.getProperty(TestConfiguration.RATIO_ORDER), equalTo(TestEnum.THIRD));
assertThat(settings.getProperty(TestConfiguration.SYSTEM_NAME), equalTo("myTestSys"));
assertDefaultValue(TestConfiguration.DURATION_IN_SECONDS, settings);
@ -58,8 +61,8 @@ public class NewSettingTest {
when(config.getInt(eq(property.getPath()), anyInt())).thenReturn((Integer) value);
} else if (value instanceof Boolean) {
when(config.getBoolean(eq(property.getPath()), anyBoolean())).thenReturn((Boolean) value);
} else if (value instanceof Double) {
when(config.getDouble(eq(property.getPath()), anyDouble())).thenReturn((Double) value);
} else if (value instanceof Enum<?>) {
when(config.getString(property.getPath())).thenReturn(((Enum<?>) value).name());
} else {
throw new UnsupportedOperationException("Value has unsupported type '"
+ (value == null ? "null" : value.getClass().getSimpleName()) + "'");

View File

@ -13,7 +13,6 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyDouble;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
@ -33,8 +32,6 @@ public class PropertyTypeTest {
when(configuration.getBoolean(eq("bool.path.test"), anyBoolean())).thenReturn(true);
when(configuration.getBoolean(eq("bool.path.wrong"), anyBoolean())).thenAnswer(secondParameter());
when(configuration.getDouble(eq("double.path.test"), anyDouble())).thenReturn(-6.4);
when(configuration.getDouble(eq("double.path.wrong"), anyDouble())).thenAnswer(secondParameter());
when(configuration.getInt(eq("int.path.test"), anyInt())).thenReturn(27);
when(configuration.getInt(eq("int.path.wrong"), anyInt())).thenAnswer(secondParameter());
when(configuration.getString(eq("str.path.test"), anyString())).thenReturn("Test value");
@ -69,31 +66,6 @@ public class PropertyTypeTest {
assertThat(result, equalTo(true));
}
/* Double */
@Test
public void shouldGetDoubleValue() {
// given
Property<Double> property = Property.newProperty(PropertyType.DOUBLE, "double.path.test", 3.8);
// when
double result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(-6.4));
}
@Test
public void shouldGetDoubleDefault() {
// given
Property<Double> property = Property.newProperty(PropertyType.DOUBLE, "double.path.wrong", 12.0);
// when
double result = property.getFromFile(configuration);
// then
assertThat(result, equalTo(12.0));
}
/* Integer */
@Test
public void shouldGetIntValue() {

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.settings.domain.Property;
@ -25,7 +25,7 @@ import static org.junit.Assert.fail;
*/
public class SettingsClassConsistencyTest {
private static final String SETTINGS_FOLDER = "src/main/java/fr/xephi/authme/settings/custom";
private static final String SETTINGS_FOLDER = "src/main/java/fr/xephi/authme/settings/properties";
private static List<Class<? extends SettingsClass>> classes;
@BeforeClass

View File

@ -1,4 +1,4 @@
package fr.xephi.authme.settings.custom;
package fr.xephi.authme.settings.properties;
import fr.xephi.authme.settings.domain.Property;
import fr.xephi.authme.settings.domain.PropertyType;
@ -11,7 +11,7 @@ import static fr.xephi.authme.settings.domain.Property.newProperty;
/**
* Sample properties for testing purposes.
*/
class TestConfiguration implements SettingsClass {
public final class TestConfiguration implements SettingsClass {
public static final Property<Integer> DURATION_IN_SECONDS =
newProperty("test.duration", 4);
@ -19,8 +19,8 @@ class TestConfiguration implements SettingsClass {
public static final Property<String> SYSTEM_NAME =
newProperty("test.systemName", "[TestDefaultValue]");
public static final Property<Double> RATIO_LIMIT =
newProperty(PropertyType.DOUBLE, "sample.ratio.limit", 3.0);
public static final Property<TestEnum> RATIO_ORDER =
newProperty(TestEnum.class, "sample.ratio.order", TestEnum.SECOND);
public static final Property<List<String>> RATIO_FIELDS =
newProperty(PropertyType.STRING_LIST, "sample.ratio.fields", "a", "b", "c");
@ -34,8 +34,8 @@ class TestConfiguration implements SettingsClass {
public static final Property<List<String>> BORING_COLORS =
newProperty(PropertyType.STRING_LIST, "features.boring.colors");
public static final Property<Double> DUST_LEVEL =
newProperty(PropertyType.DOUBLE, "features.boring.dustLevel", 0.2);
public static final Property<Integer> DUST_LEVEL =
newProperty(PropertyType.INTEGER, "features.boring.dustLevel", -1);
public static final Property<Boolean> USE_COOL_FEATURES =
newProperty("features.cool.enabled", false);
@ -43,4 +43,8 @@ class TestConfiguration implements SettingsClass {
public static final Property<List<String>> COOL_OPTIONS =
newProperty(PropertyType.STRING_LIST, "features.cool.options", "Sparks", "Sprinkles");
private TestConfiguration() {
}
}

View File

@ -0,0 +1,16 @@
package fr.xephi.authme.settings.properties;
/**
* Test enum used in {@link TestConfiguration}.
*/
public enum TestEnum {
FIRST,
SECOND,
THIRD,
FOURTH
}

View File

@ -2,6 +2,7 @@ package fr.xephi.authme.util;
import org.junit.Test;
import java.io.File;
import java.net.MalformedURLException;
import java.util.Arrays;
import java.util.List;
@ -135,4 +136,13 @@ public class StringUtilsTest {
assertThat(StringUtils.getDifference("test", "bear"), equalTo(0.75));
assertThat(StringUtils.getDifference("test", "something"), greaterThan(0.88));
}
@Test
public void shouldConstructPath() {
// given/when
String result = StringUtils.makePath("path", "to", "test-file.txt");
// then
assertThat(result, equalTo("path" + File.separator + "to" + File.separator + "test-file.txt"));
}
}

View File

@ -1,16 +1,21 @@
package fr.xephi.authme.util;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.ConsoleLoggerTestInitializer;
import fr.xephi.authme.ReflectionTestUtils;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import org.bukkit.entity.Player;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
@ -35,6 +40,7 @@ public class UtilsTest {
public static void setUpMocks() {
WrapperMock wrapperMock = WrapperMock.createInstance();
authMeMock = wrapperMock.getAuthMe();
ConsoleLoggerTestInitializer.setupLogger();
}
@Before
@ -92,6 +98,95 @@ public class UtilsTest {
assertThat(players, hasSize(2));
}
// ----------------
// Tests for Utils#isEmailCorrect()
// ----------------
@Test
public void shouldAcceptEmailWithEmptyLists() {
// given
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST);
given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST);
// when
boolean result = Utils.isEmailCorrect("test@example.org", settings);
// then
assertThat(result, equalTo(true));
}
@Test
public void shouldAcceptEmailWithWhitelist() {
// given
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST))
.willReturn(Arrays.asList("domain.tld", "example.com"));
given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST);
// when
boolean result = Utils.isEmailCorrect("TesT@Example.com", settings);
// then
assertThat(result, equalTo(true));
}
@Test
public void shouldRejectEmailNotInWhitelist() {
// given
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST))
.willReturn(Arrays.asList("domain.tld", "example.com"));
given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST)).willReturn(Collections.EMPTY_LIST);
// when
boolean result = Utils.isEmailCorrect("email@other-domain.abc", settings);
// then
assertThat(result, equalTo(false));
}
@Test
public void shouldAcceptEmailNotInBlacklist() {
// given
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST);
given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST))
.willReturn(Arrays.asList("Example.org", "a-test-name.tld"));
// when
boolean result = Utils.isEmailCorrect("sample@valid-name.tld", settings);
// then
assertThat(result, equalTo(true));
}
@Test
public void shouldRejectEmailInBlacklist() {
// given
NewSetting settings = mock(NewSetting.class);
given(settings.getProperty(EmailSettings.DOMAIN_WHITELIST)).willReturn(Collections.EMPTY_LIST);
given(settings.getProperty(EmailSettings.DOMAIN_BLACKLIST))
.willReturn(Arrays.asList("Example.org", "a-test-name.tld"));
// when
boolean result = Utils.isEmailCorrect("sample@a-Test-name.tld", settings);
// then
assertThat(result, equalTo(false));
}
@Test
public void shouldRejectInvalidEmail() {
// given/when/then
assertThat(Utils.isEmailCorrect("invalidinput", mock(NewSetting.class)), equalTo(false));
}
@Test
public void shouldRejectDefaultEmail() {
// given/when/then
assertThat(Utils.isEmailCorrect("your@email.com", mock(NewSetting.class)), equalTo(false));
}
// Note: This method is used through reflections
public static Player[] onlinePlayersImpl() {
return new Player[]{

View File

@ -0,0 +1,29 @@
# Test config file with some "difficult" values
test:
duration: 20.102
systemName: 'A ''test'' name'
sample:
ratio:
order: Fourth
fields:
- Australia\
- ' Burundi'''
- 'Colombia?
'''''
# The last element above represents "Colombia?\n''"
version: -1337
features:
boring:
# YAML allows both "yes"/"no" and "true"/"false" for expressing booleans
skip: no
colors:
- 'it''s a difficult string!'
- |
gray
with new lines
# dustLevel: 8 <-- missing property triggering rewrite
cool:
enabled: yes
options: []

View File

@ -6,7 +6,7 @@ test:
# systemName: 'Custom sys name'
sample:
ratio:
# limit: 3.0
# order: 'THIRD'
fields:
- 'Australia'
- 'Burundi'
@ -18,7 +18,7 @@ features:
# colors:
# - 'beige'
# - 'gray'
# dustLevel: 0.81
# dustLevel: 1
cool:
# enabled: true
options:

View File

@ -6,7 +6,7 @@ test:
systemName: 'Custom sys name'
sample:
ratio:
limit: -4.1
order: 'first'
fields:
- 'Australia'
- 'Burundi'
@ -18,7 +18,7 @@ features:
colors:
- 'beige'
- 'gray'
dustLevel: 0.81
dustLevel: 2
cool:
enabled: true
options: