mirror of
https://github.com/AuthMe/AuthMeReloaded.git
synced 2024-11-27 04:35:12 +01:00
#450 Fix copying of JAR files to plugin folder
- Create SettingsMigrationService#copyFileFromResource (inspired from CustomSettings) - Use new method to copy missing files in plugin folder from JAR - Create YamlFileConfiguration inside NewSetting: FileConfiguration object provided by JavaPlugin#getConfig() sets default values from the JAR's config.yml :( - Change ConsoleLogger to take logger from plugin (work in progress)
This commit is contained in:
parent
85868ca830
commit
99b7b80f1d
1
pom.xml
1
pom.xml
@ -97,6 +97,7 @@
|
||||
<directory>src/main/resources/</directory>
|
||||
<includes>
|
||||
<include>email.html</include>
|
||||
<include>welcome.txt</include>
|
||||
</includes>
|
||||
</resource>
|
||||
<resource>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
@ -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 <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"));
|
||||
@ -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<String> 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 "";
|
||||
}
|
||||
|
||||
|
@ -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() {
|
||||
|
@ -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("<playername>", "<playername />")
|
||||
.replace("<servername>", "<servername />")
|
||||
.replace("<generatedpass>", "<generatedpass />")
|
||||
.replace("<image>", "<image />");
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
|
3
src/main/resources/welcome.txt
Normal file
3
src/main/resources/welcome.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Welcome {PLAYER} on {SERVER} server
|
||||
|
||||
This server uses AuthMeReloaded protection!
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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() {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user