diff --git a/pom.xml b/pom.xml
index 7a77f60ff..9bbbd39b5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -97,6 +97,7 @@
src/main/resources/
email.html
+ welcome.txt
diff --git a/src/main/java/fr/xephi/authme/AuthMe.java b/src/main/java/fr/xephi/authme/AuthMe.java
index 980e3e955..c5a26048c 100644
--- a/src/main/java/fr/xephi/authme/AuthMe.java
+++ b/src/main/java/fr/xephi/authme/AuthMe.java
@@ -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;
@@ -207,11 +208,21 @@ 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);
@@ -425,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. "
@@ -436,8 +446,10 @@ public class AuthMe extends JavaPlugin {
}
private NewSetting createNewSetting() {
- File configFile = new File(getDataFolder() + "config.yml");
- return new NewSetting(getConfig(), configFile, getDataFolder());
+ File configFile = new File(getDataFolder(), "config.yml");
+ return SettingsMigrationService.copyFileFromResource(configFile, "config.yml")
+ ? new NewSetting(configFile, getDataFolder())
+ : null;
}
/**
diff --git a/src/main/java/fr/xephi/authme/ConsoleLogger.java b/src/main/java/fr/xephi/authme/ConsoleLogger.java
index 605cabc08..eca20fbba 100644
--- a/src/main/java/fr/xephi/authme/ConsoleLogger.java
+++ b/src/main/java/fr/xephi/authme/ConsoleLogger.java
@@ -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));
}
}
diff --git a/src/main/java/fr/xephi/authme/settings/NewSetting.java b/src/main/java/fr/xephi/authme/settings/NewSetting.java
index 85ae65058..29e833d0a 100644
--- a/src/main/java/fr/xephi/authme/settings/NewSetting.java
+++ b/src/main/java/fr/xephi/authme/settings/NewSetting.java
@@ -24,7 +24,7 @@ import java.util.Arrays;
import java.util.List;
import java.util.Map;
-import static fr.xephi.authme.util.StringUtils.makePath;
+import static fr.xephi.authme.settings.SettingsMigrationService.copyFileFromResource;
/**
* The new settings manager.
@@ -42,24 +42,14 @@ public class NewSetting {
/**
* Constructor. Checks the given {@link FileConfiguration} object for completeness.
*
- * @param configuration The configuration to interact with
* @param configFile The configuration file
* @param pluginFolder The AuthMe plugin folder
*/
- public NewSetting(FileConfiguration configuration, File configFile, File pluginFolder) {
- this.configuration = configuration;
+ public NewSetting(File configFile, File pluginFolder) {
+ this.configuration = YamlConfiguration.loadConfiguration(configFile);
this.configFile = configFile;
this.pluginFolder = pluginFolder;
- messagesFile = buildMessagesFile();
- welcomeMessage = readWelcomeMessage();
- emailMessage = readEmailMessage();
-
- 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);
- }
+ validateAndLoadOptions();
}
/**
@@ -131,6 +121,7 @@ public class NewSetting {
*/
public void reload() {
configuration = YamlConfiguration.loadConfiguration(configFile);
+ validateAndLoadOptions();
}
private void save(PropertyMap propertyMap) {
@@ -185,6 +176,19 @@ public class NewSetting {
}
}
+ 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 String toYaml(Property property, int indent, Yaml simpleYaml, Yaml singleQuoteYaml) {
String representation = property.toYaml(configuration, simpleYaml, singleQuoteYaml);
return join("\n" + indent(indent), representation.split("\\n"));
@@ -196,59 +200,45 @@ public class NewSetting {
if (messagesFile.exists()) {
return messagesFile;
}
- return buildMessagesFileFromCode("en");
+
+ return copyFileFromResource(messagesFile, buildMessagesFilePathFromCode(languageCode))
+ ? messagesFile
+ : buildMessagesFileFromCode("en");
}
private File buildMessagesFileFromCode(String language) {
- return new File(pluginFolder,
- makePath("messages", "messages_" + language + ".yml"));
+ return new File(pluginFolder, buildMessagesFilePathFromCode(language));
+ }
+
+ private static String buildMessagesFilePathFromCode(String language) {
+ return StringUtils.makePath("messages", "messages_" + language + ".yml");
}
private List readWelcomeMessage() {
if (getProperty(RegistrationSettings.USE_WELCOME_MESSAGE)) {
final File welcomeFile = new File(pluginFolder, "welcome.txt");
final Charset charset = Charset.forName("UTF-8");
- if (!welcomeFile.exists()) {
+ if (copyFileFromResource(welcomeFile, "welcome.txt")) {
try {
- Files.write(
- "Welcome {PLAYER} to {SERVER} server\n\nThis server uses AuthMe protection!",
- welcomeFile, charset);
+ return Files.readLines(welcomeFile, charset);
} catch (IOException e) {
- ConsoleLogger.showError("Failed to create file '" + welcomeFile.getPath() + "': "
- + StringUtils.formatException(e));
- ConsoleLogger.writeStackTrace(e);
+ ConsoleLogger.logException("Failed to read file '" + welcomeFile.getPath() + "':", e);
}
}
- try {
- return Files.readLines(welcomeFile, charset);
- } catch (IOException e) {
- ConsoleLogger.showError("Failed to read file '" + welcomeFile.getPath() + "': " +
- StringUtils.formatException(e));
- ConsoleLogger.writeStackTrace(e);
- }
}
return new ArrayList<>(0);
}
private String readEmailMessage() {
- final File emailFile = new File(pluginFolder, "email.txt");
+ final File emailFile = new File(pluginFolder, "email.html");
final Charset charset = Charset.forName("UTF-8");
- if (!emailFile.exists()) {
+ if (copyFileFromResource(emailFile, "email.html")) {
try {
- Files.write("", emailFile, charset);
+ return StringUtils.join("", Files.readLines(emailFile, charset));
} catch (IOException e) {
- ConsoleLogger.showError("Failed to create file '" + emailFile.getPath() + "': "
- + StringUtils.formatException(e));
- ConsoleLogger.writeStackTrace(e);
+ ConsoleLogger.logException("Failed to read file '" + emailFile.getPath() + "':", e);
}
}
- try {
- return StringUtils.join("", Files.readLines(emailFile, charset));
- } catch (IOException e) {
- ConsoleLogger.showError("Failed to read file '" + emailFile.getPath() + "': " +
- StringUtils.formatException(e));
- ConsoleLogger.writeStackTrace(e);
- }
return "";
}
diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java
index 96d15d12e..ff7116213 100644
--- a/src/main/java/fr/xephi/authme/settings/Settings.java
+++ b/src/main/java/fr/xephi/authme/settings/Settings.java
@@ -6,7 +6,7 @@ import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.datasource.DataSource.DataSourceType;
import fr.xephi.authme.security.HashAlgorithm;
import fr.xephi.authme.util.Wrapper;
-import org.bukkit.configuration.file.YamlConfiguration;
+import org.bukkit.configuration.file.FileConfiguration;
import java.io.File;
import java.io.IOException;
@@ -87,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;
@@ -99,25 +99,8 @@ 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);
+ configFile = plugin.getConfig();
loadVariables();
- if (exist) {
- instance.saveDefaults();
- }
}
public static void loadVariables() {
diff --git a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
index 1e010f4c5..0a41301c7 100644
--- a/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
+++ b/src/main/java/fr/xephi/authme/settings/SettingsMigrationService.java
@@ -1,17 +1,20 @@
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 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.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.
@@ -86,15 +89,51 @@ public final class SettingsMigrationService {
}
final File emailFile = new File(dataFolder, "email.html");
+ final String mailText = configuration.getString(oldSettingPath)
+ .replace("", "")
+ .replace("", "")
+ .replace("", "")
+ .replace("", "");
if (!emailFile.exists()) {
try (FileWriter fw = new FileWriter(emailFile)) {
- fw.write(configuration.getString("Email.mailText"));
+ fw.write(mailText);
} catch (IOException e) {
- ConsoleLogger.showError("Could not create email.html configuration file: "
- + StringUtils.formatException(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;
+ }
+
}
diff --git a/src/main/resources/welcome.txt b/src/main/resources/welcome.txt
new file mode 100644
index 000000000..1c49f042b
--- /dev/null
+++ b/src/main/resources/welcome.txt
@@ -0,0 +1,3 @@
+Welcome {PLAYER} on {SERVER} server
+
+This server uses AuthMeReloaded protection!
diff --git a/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java b/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java
new file mode 100644
index 000000000..cfa871e3e
--- /dev/null
+++ b/src/test/java/fr/xephi/authme/ConsoleLoggerTestInitializer.java
@@ -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;
+ }
+}
diff --git a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java b/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java
index fdd338919..b9977de8e 100644
--- a/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java
+++ b/src/test/java/fr/xephi/authme/output/Log4JFilterTest.java
@@ -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);
diff --git a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
index 6e63a934d..2d3e7b08f 100644
--- a/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
+++ b/src/test/java/fr/xephi/authme/output/MessagesIntegrationTest.java
@@ -1,9 +1,11 @@
package fr.xephi.authme.output;
+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;
@@ -27,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
@@ -34,8 +42,6 @@ public class MessagesIntegrationTest {
*/
@Before
public void setUpMessages() {
- WrapperMock.createInstance();
-
URL url = getClass().getClassLoader().getResource(YML_TEST_FILE);
if (url == null) {
throw new RuntimeException("File '" + YML_TEST_FILE + "' could not be loaded");
diff --git a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java
index 106689ae7..6ee291143 100644
--- a/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java
+++ b/src/test/java/fr/xephi/authme/security/crypts/BcryptTest.java
@@ -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() {
diff --git a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java
index 3b7294a04..ed49ccd71 100644
--- a/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java
+++ b/src/test/java/fr/xephi/authme/security/crypts/XFBCRYPTTest.java
@@ -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() {
diff --git a/src/test/java/fr/xephi/authme/util/UtilsTest.java b/src/test/java/fr/xephi/authme/util/UtilsTest.java
index 526e511fe..67723c494 100644
--- a/src/test/java/fr/xephi/authme/util/UtilsTest.java
+++ b/src/test/java/fr/xephi/authme/util/UtilsTest.java
@@ -1,6 +1,7 @@
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;
@@ -39,6 +40,7 @@ public class UtilsTest {
public static void setUpMocks() {
WrapperMock wrapperMock = WrapperMock.createInstance();
authMeMock = wrapperMock.getAuthMe();
+ ConsoleLoggerTestInitializer.setupLogger();
}
@Before