Merge branch 'master' of https://github.com/AuthMe-Team/AuthMeReloaded into 437-add-email

Conflicts:
	src/main/java/fr/xephi/authme/datasource/MySQL.java
	src/main/java/fr/xephi/authme/datasource/SQLite.java
	src/main/java/fr/xephi/authme/process/Management.java
	src/main/java/fr/xephi/authme/process/email/AsyncChangeEmail.java
This commit is contained in:
ljacqu 2016-02-06 18:01:11 +01:00
commit b4b679d3b9
96 changed files with 1674 additions and 1762 deletions

3
.floo
View File

@ -1,3 +0,0 @@
{
"url": "https://floobits.com/AuthMe-Team/AuthMeReloaded"
}

View File

@ -1,123 +0,0 @@
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
#*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### NetBeans ###
nbproject/private/
build/
nbbuild/
dist/
nbdist/
nbactions.xml
nb-configuration.xml
.nb-gradle/

View File

@ -14,6 +14,7 @@
- Build status: [![Build Status](https://travis-ci.org/Xephi/AuthMeReloaded.svg?branch=master)](https://travis-ci.org/Xephi/AuthMeReloaded) [![Dependency Status](https://www.versioneye.com/user/projects/55bab9e8653762002000190a/badge.svg?style=flat)](https://www.versioneye.com/user/projects/55bab9e8653762002000190a)
- Build status (CircleCI): [![Circle CI](https://circleci.com/gh/Xephi/AuthMeReloaded.svg?style=svg)](https://circleci.com/gh/Xephi/AuthMeReloaded)
- Alternative Dev Build download link (via CircleCi): <a href="https://circleci-tkn.rhcloud.com/api/v1/project/AuthMe-Team/AuthMeReloaded/tree/master/latest/artifacts/AuthMe.jar">Download</a>
- Code Coverage: [![Coverage Status](https://coveralls.io/repos/AuthMe-Team/AuthMeReloaded/badge.svg?branch=master&service=github)](https://coveralls.io/github/AuthMe-Team/AuthMeReloaded?branch=master)

View File

@ -7,7 +7,9 @@ general:
test:
override:
- mvn clean install -B
post:
- cp ./target/AuthMe*.jar $CIRCLE_ARTIFACTS
- cp ./target/AuthMe-*-SNAPSHOT.jar $CIRCLE_ARTIFACTS/AuthMe.jar
notify:
webhooks:
- url: https://webhooks.gitter.im/e/7b92ac1a1741748b26bf

70
pom.xml
View File

@ -97,6 +97,7 @@
<directory>src/main/resources/</directory>
<includes>
<include>email.html</include>
<include>welcome.txt</include>
</includes>
</resource>
<resource>
@ -125,73 +126,22 @@
</testResource>
</testResources>
<!-- Just to keep Eclipse compatibility... -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<versionRange>[1.0,)</versionRange>
<goals>
<goal>create-timestamp</goal>
</goals>
</pluginExecutionFilter>
<action>
<execute>
<runOnConfiguration>true</runOnConfiguration>
<runOnIncremental>true</runOnIncremental>
</execute>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<version>3.5</version>
<configuration>
<source>1.7</source>
<target>${javaVersion}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>buildnumber-maven-plugin</artifactId>
<version>1.4</version>
<configuration>
<timestampFormat>dd-MM-yy_HH-mm</timestampFormat>
<timestampPropertyName>build.time</timestampPropertyName>
</configuration>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>create-timestamp</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- TODO: we need also to relocate the other libs -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<version>2.4.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
<minimizeJar>false</minimizeJar>
@ -263,6 +213,14 @@
<docencoding>UTF-8</docencoding>
<docfilessubdirs>true</docfilessubdirs>
</configuration>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@ -271,7 +229,7 @@
<!-- SpigotMC Repo (Bukkit and SpigotAPI) -->
<repository>
<id>spigot-repo</id>
<url>http://hub.spigotmc.org/nexus/content/groups/public</url>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots</url>
</repository>
<!-- EssentialsX Repo -->
@ -341,7 +299,7 @@
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.7.13</version>
<version>1.7.14</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>
@ -378,7 +336,7 @@
<dependency>
<groupId>com.maxmind.geoip</groupId>
<artifactId>geoip-api</artifactId>
<version>1.2.15</version>
<version>1.3.0</version>
<scope>compile</scope>
<optional>true</optional>
</dependency>

View File

@ -1,9 +1,36 @@
package fr.xephi.authme;
import com.earth2me.essentials.Essentials;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
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;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import com.earth2me.essentials.Essentials;
import com.onarandombox.MultiverseCore.MultiverseCore;
import net.minelink.ctplus.CombatTagPlus;
import fr.xephi.authme.api.API;
import fr.xephi.authme.api.NewAPI;
import fr.xephi.authme.cache.auth.PlayerAuth;
@ -34,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;
@ -45,41 +71,24 @@ 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 net.minelink.ctplus.CombatTagPlus;
import org.apache.logging.log4j.LogManager;
import org.bukkit.Bukkit;
import org.bukkit.Location;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import org.bukkit.scheduler.BukkitTask;
import org.mcstats.Metrics;
import org.mcstats.Metrics.Graph;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
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.
@ -104,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;
@ -170,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.
*
@ -209,27 +208,35 @@ 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.
if (loadSettings()) {
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 {
setupDatabase();
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError(e.getMessage());
ConsoleLogger.showError("Fatal error occurred during database connection! Authme initialization ABORTED!");
ConsoleLogger.logException("Fatal error occurred during database connection! "
+ "Authme initialization aborted!", e);
stopOrUnload();
return;
}
@ -241,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
setupMetrics();
MetricsStarter.setupMetrics(plugin, newSettings);
// Set console filter
setupConsoleFilter();
@ -279,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
@ -292,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();
@ -321,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);
}
/**
@ -354,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!");
}
}
@ -414,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));
}
@ -422,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(
@ -450,20 +436,20 @@ public class AuthMe extends JavaPlugin {
private boolean loadSettings() {
try {
settings = new Settings(this);
Settings.reload();
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError("Can't load the configuration file... Something went wrong. "
+ "To avoid security issues the server will shut down!");
server.shutdown();
return true;
} catch (Exception e) {
ConsoleLogger.logException("Can't load the configuration file... Something went wrong. "
+ "To avoid security issues the server will shut down!", e);
server.shutdown();
}
return false;
}
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;
}
/**
@ -485,42 +471,6 @@ public class AuthMe extends JavaPlugin {
}
}
/**
* Set up Metrics.
*/
private void setupMetrics() {
try {
Metrics metrics = new Metrics(this);
Graph messagesLanguage = metrics.createGraph("Messages language");
Graph databaseBackend = metrics.createGraph("Database backend");
// Custom graphs
if (Settings.messageFile.exists()) {
messagesLanguage.addPlotter(new Metrics.Plotter(Settings.messagesLanguage) {
@Override
public int getValue() {
return 1;
}
});
}
databaseBackend.addPlotter(new Metrics.Plotter(Settings.getDataSource.toString()) {
@Override
public int getValue() {
return 1;
}
});
metrics.start();
ConsoleLogger.info("Metrics started successfully!");
} catch (Exception e) {
// Failed to submit the metrics data
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError("Can't start Metrics! The plugin will work anyway...");
}
}
@Override
public void onDisable() {
// Save player data
@ -530,47 +480,10 @@ 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);
}
List<BukkitTask> pendingTasks = getServer().getScheduler().getPendingTasks();
for (Iterator<BukkitTask> iterator = pendingTasks.iterator(); iterator.hasNext();) {
BukkitTask pendingTask = iterator.next();
if (!pendingTask.getOwner().equals(this) || pendingTask.isSync()) {
//remove all unrelevant tasks
iterator.remove();
}
}
getLogger().log(Level.INFO, "Waiting for {0} tasks to finish", pendingTasks.size());
int progress = 0;
try {
for (BukkitTask pendingTask : pendingTasks) {
int maxTries = 5;
int taskId = pendingTask.getTaskId();
while (getServer().getScheduler().isCurrentlyRunning(taskId)) {
if (maxTries <= 0) {
getLogger().log(Level.INFO, "Async task {0} times out after to many tries", taskId);
break;
}
//one second
Thread.sleep(1000);
maxTries--;
}
progress++;
getLogger().log(Level.INFO, "Progress: {0} / {1}", new Object[]{progress, pendingTasks.size()});
}
} catch (InterruptedException interruptedException) {
}
// Close the database
if (database != null) {
database.close();
@ -595,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;
@ -624,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;
@ -632,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()) {
@ -641,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);
}
}
@ -736,25 +649,21 @@ 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) {
if (newSettings.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN) && inventoryProtector == null) {
inventoryProtector = new AuthMeInventoryPacketAdapter(this);
inventoryProtector.register();
}
} else {
if (inventoryProtector != null) {
} else if (inventoryProtector != null) {
inventoryProtector.unregister();
inventoryProtector = null;
}
}
if (tabComplete == null) {
tabComplete = new AuthMeTabCompletePacketAdapter(this);
tabComplete.register();
@ -788,17 +697,15 @@ 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 null;
}
// Purge inactive players from the database, as defined in the configuration
private void autoPurge() {
@ -809,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!");
@ -896,31 +800,31 @@ 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)) {
if (database.isAuthAvailable(name) && PlayerCache.getInstance().isAuthenticated(name)) {
String email = database.getAuth(name).getEmail();
if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com"))
if (email == null || email.isEmpty() || email.equalsIgnoreCase("your@email.com")) {
messages.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
}
}
}
}
}, 1, 1200 * Settings.delayRecall);
}
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)));
}
/**
@ -976,10 +880,6 @@ public class AuthMe extends JavaPlugin {
return count >= Settings.getMaxJoinPerIp;
}
public ModuleManager getModuleManager() {
return moduleManager;
}
/**
* Handle Bukkit commands.
*

View File

@ -1,15 +1,16 @@
package fr.xephi.authme;
import com.google.common.base.Throwables;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.Wrapper;
import fr.xephi.authme.util.StringUtils;
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.
@ -18,24 +19,33 @@ 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) {
return;
logger.info(message);
if (useLogging) {
writeLog(message);
}
writeLog("" + message);
}
/**
@ -44,12 +54,11 @@ public final class ConsoleLogger {
* @param message String
*/
public static void showError(String message) {
wrapper.getLogger().warning(message);
if (!Settings.useLogging) {
return;
}
logger.warning(message);
if (useLogging) {
writeLog("ERROR: " + message);
}
}
/**
* Write a message into the log file with a TimeStamp.
@ -62,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) {
@ -72,12 +81,22 @@ public final class ConsoleLogger {
/**
* Write a StackTrace into the log.
*
* @param ex Exception
* @param th The Throwable whose stack trace should be logged
*/
public static void writeStackTrace(Exception ex) {
if (!Settings.useLogging) {
return;
}
writeLog(Throwables.getStackTraceAsString(ex));
public static void writeStackTrace(Throwable th) {
if (useLogging) {
writeLog(Throwables.getStackTraceAsString(th));
}
}
/**
* Logs a Throwable with the provided message and saves the stack trace to the log file.
*
* @param message The message to accompany the exception
* @param th The Throwable to log
*/
public static void logException(String message, Throwable th) {
showError(message + " " + StringUtils.formatException(th));
writeStackTrace(th);
}
}

View File

@ -0,0 +1,45 @@
package fr.xephi.authme;
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 java.io.IOException;
public class MetricsStarter {
private MetricsStarter() {
}
public static void setupMetrics(AuthMe plugin, NewSetting settings) {
try {
final Metrics metrics = new Metrics(plugin);
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;
}
});
final Graph databaseBackend = metrics.createGraph("Database Backend");
final String dataSource = settings.getProperty(DatabaseSettings.BACKEND).toString();
databaseBackend.addPlotter(new Metrics.Plotter(dataSource) {
@Override
public int getValue() {
return 1;
}
});
// Submit metrics
metrics.start();
} 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,47 +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) {
if (!Settings.isBackupActivated) {
ConsoleLogger.showError("Can't perform a Backup: disabled in configuration. Cause of the Backup: " + cause.name());
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());
}
return;
}
// Check whether a backup should be made at the specified point in time
switch (cause) {
case START:
if (!Settings.isBackupOnStart)
if (BackupCause.START.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_START)
|| BackupCause.STOP.equals(cause) && !settings.getProperty(BackupSettings.ON_SERVER_STOP)) {
return;
case STOP:
if (!Settings.isBackupOnStop)
return;
case COMMAND:
case OTHER:
}
// Do backup and check return value!
@ -61,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);
@ -102,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";
@ -117,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);
@ -193,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.
@ -222,7 +202,7 @@ public class PerformBackup {
START,
STOP,
COMMAND,
OTHER,
OTHER
}
}

View File

@ -1,8 +1,6 @@
package fr.xephi.authme.command;
import fr.xephi.authme.command.executable.HelpCommand;
import fr.xephi.authme.command.help.HelpProvider;
import fr.xephi.authme.output.Messages;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.util.CollectionUtils;
import fr.xephi.authme.util.StringUtils;

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,36 +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.showError("Fatal error occurred! AuthMe instance ABORTED!");
ConsoleLogger.writeStackTrace(e);
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

@ -3,8 +3,7 @@ package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.command.PlayerCommand;
import fr.xephi.authme.output.MessageKey;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.util.StringUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import java.util.List;
@ -16,7 +15,7 @@ public class AddEmailCommand extends PlayerCommand {
String email = arguments.get(0);
String emailConfirmation = arguments.get(1);
if (StringUtils.isEmpty(email) || "your@email.com".equals(email) || !Settings.isEmailCorrect(email)) {
if (!Utils.isEmailCorrect(email, commandService.getSettings())) {
commandService.send(player, MessageKey.INVALID_EMAIL);
} else if (email.equals(emailConfirmation)) {
commandService.getManagement().performAddEmail(player, email);

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");
settings.setProperty(DatabaseSettings.BACKEND, DataSource.DataSourceType.SQLITE);
settings.save();
ConsoleLogger.info("Database successfully converted to sqlite!");
} catch (Exception e) {
ConsoleLogger.showError("An error occurred while trying to convert flatfile 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 null;
}
return sqlite;
}
}

View File

@ -33,8 +33,7 @@ public class RoyalAuthConverter implements Converter {
PlayerAuth auth = new PlayerAuth(name, ra.getHash(), "127.0.0.1", ra.getLastLogin(), "your@email.com", o.getName());
data.saveAuth(auth);
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError("Error while trying to import " + o.getName() + " RoyalAuth datas");
ConsoleLogger.logException("Error while trying to import " + o.getName() + " RoyalAuth data", e);
}
}
}

View File

@ -8,6 +8,7 @@ import org.bukkit.Bukkit;
import org.bukkit.OfflinePlayer;
import java.io.File;
import java.io.IOException;
import java.util.Scanner;
import java.util.UUID;
@ -27,7 +28,7 @@ class vAuthFileReader {
}
public void convert() {
final File file = new File(plugin.getDataFolder().getParent() + "" + File.separator + "vAuth" + File.separator + "passwords.yml");
final File file = new File(plugin.getDataFolder().getParent() + File.separator + "vAuth" + File.separator + "passwords.yml");
Scanner scanner;
try {
scanner = new Scanner(file);
@ -52,8 +53,8 @@ class vAuthFileReader {
database.saveAuth(auth);
}
scanner.close();
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
} catch (IOException e) {
ConsoleLogger.logException("Error while trying to import some vAuth data", e);
}
}
@ -63,12 +64,10 @@ class vAuthFileReader {
}
private String getName(UUID uuid) {
try {
for (OfflinePlayer op : Bukkit.getOfflinePlayers()) {
if (op.getUniqueId().compareTo(uuid) == 0)
if (op.getUniqueId().compareTo(uuid) == 0) {
return op.getName();
}
} catch (Exception ignored) {
}
return null;
}

View File

@ -5,17 +5,13 @@ import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.cache.RemovalListener;
import com.google.common.cache.RemovalListeners;
import com.google.common.cache.RemovalNotification;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.cache.auth.PlayerAuth;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.security.crypts.HashedPassword;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
@ -23,7 +19,6 @@ import java.util.concurrent.TimeUnit;
public class CacheDataSource implements DataSource {
private final DataSource source;
private final ExecutorService exec;
private final LoadingCache<String, Optional<PlayerAuth>> cachedAuths;
/**
@ -33,10 +28,9 @@ public class CacheDataSource implements DataSource {
*/
public CacheDataSource(DataSource src) {
this.source = src;
this.exec = Executors.newCachedThreadPool();
cachedAuths = CacheBuilder.newBuilder()
.expireAfterWrite(5, TimeUnit.MINUTES)
.removalListener(RemovalListeners.asynchronous(new RemovalListener<String, Optional<PlayerAuth>>() {
this.cachedAuths = CacheBuilder.newBuilder()
.expireAfterWrite(8, TimeUnit.MINUTES)
.removalListener(new RemovalListener<String, Optional<PlayerAuth>>() {
@Override
public void onRemoval(RemovalNotification<String, Optional<PlayerAuth>> removalNotification) {
String name = removalNotification.getKey();
@ -44,7 +38,7 @@ public class CacheDataSource implements DataSource {
cachedAuths.getUnchecked(name);
}
}
}, exec))
})
.build(
new CacheLoader<String, Optional<PlayerAuth>>() {
public Optional<PlayerAuth> load(String key) {
@ -168,25 +162,14 @@ public class CacheDataSource implements DataSource {
@Override
public synchronized void close() {
try {
exec.shutdown();
exec.awaitTermination(8, TimeUnit.SECONDS);
} catch (InterruptedException e) {
ConsoleLogger.writeStackTrace(e);
}
source.close();
}
@Override
public void reload() { // unused method
exec.execute(new Runnable() {
@Override
public void run() {
source.reload();
cachedAuths.invalidateAll();
}
});
}
@Override
public synchronized boolean updateEmail(final PlayerAuth auth) {
@ -214,14 +197,9 @@ public class CacheDataSource implements DataSource {
@Override
public synchronized void purgeBanned(final List<String> banned) {
exec.execute(new Runnable() {
@Override
public void run() {
source.purgeBanned(banned);
cachedAuths.invalidateAll(banned);
}
});
}
@Override
public DataSourceType getType() {
@ -235,34 +213,19 @@ public class CacheDataSource implements DataSource {
@Override
public void setLogged(final String user) {
exec.execute(new Runnable() {
@Override
public void run() {
source.setLogged(user.toLowerCase());
}
});
}
@Override
public void setUnlogged(final String user) {
exec.execute(new Runnable() {
@Override
public void run() {
source.setUnlogged(user.toLowerCase());
}
});
}
@Override
public void purgeLogged() {
exec.execute(new Runnable() {
@Override
public void run() {
source.purgeLogged();
cachedAuths.invalidateAll();
}
});
}
@Override
public int getAccountsRegistered() {
@ -270,15 +233,10 @@ public class CacheDataSource implements DataSource {
}
@Override
public void updateName(final String oldOne, final String newOne) {
exec.execute(new Runnable() {
@Override
public void run() {
public void updateName(final String oldOne, final String newOne) { // unused method
source.updateName(oldOne, newOne);
cachedAuths.invalidate(oldOne);
}
});
}
@Override
public List<PlayerAuth> getAllAuths() {

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

@ -257,8 +257,7 @@ public class MySQL implements DataSource {
ResultSet rs = pst.executeQuery();
return rs.next();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -276,8 +275,7 @@ public class MySQL implements DataSource {
!columnSalt.isEmpty() ? rs.getString(columnSalt) : null);
}
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return null;
}
@ -322,8 +320,7 @@ public class MySQL implements DataSource {
}
}
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
return null;
}
return pAuth;
@ -525,8 +522,7 @@ public class MySQL implements DataSource {
}
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -589,8 +585,7 @@ public class MySQL implements DataSource {
}
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -623,8 +618,7 @@ public class MySQL implements DataSource {
pst.setLong(1, until);
result = pst.executeUpdate();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return result;
}
@ -647,8 +641,7 @@ public class MySQL implements DataSource {
st.executeUpdate();
st.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return list;
}
@ -680,8 +673,7 @@ public class MySQL implements DataSource {
pst.executeUpdate();
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -702,8 +694,7 @@ public class MySQL implements DataSource {
pst.close();
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -722,8 +713,7 @@ public class MySQL implements DataSource {
rs.close();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return countIp;
}
@ -739,8 +729,7 @@ public class MySQL implements DataSource {
pst.close();
return true;
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return false;
}
@ -750,9 +739,8 @@ public class MySQL implements DataSource {
try {
reloadArguments();
} catch (Exception ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.showError("Can't reconnect to MySQL database... Please check your MySQL configuration!");
ConsoleLogger.writeStackTrace(ex);
ConsoleLogger.logException("Can't reconnect to MySQL database... " +
"Please check your MySQL configuration! Encountered", ex);
AuthMe.getInstance().stopOrUnload();
}
}
@ -778,8 +766,7 @@ public class MySQL implements DataSource {
rs.close();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return result;
}
@ -798,8 +785,7 @@ public class MySQL implements DataSource {
rs.close();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return result;
}
@ -818,8 +804,7 @@ public class MySQL implements DataSource {
rs.close();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return countEmail;
}
@ -834,8 +819,7 @@ public class MySQL implements DataSource {
}
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
}
@ -854,8 +838,7 @@ public class MySQL implements DataSource {
ResultSet rs = pst.executeQuery();
isLogged = rs.next() && (rs.getInt(columnLogged) == 1);
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
return isLogged;
}
@ -870,8 +853,7 @@ public class MySQL implements DataSource {
pst.executeUpdate();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
}
@ -885,8 +867,7 @@ public class MySQL implements DataSource {
pst.executeUpdate();
pst.close();
} catch (SQLException ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
logSqlException(ex);
}
}
@ -899,9 +880,8 @@ public class MySQL implements DataSource {
pst.setInt(2, 1);
pst.executeUpdate();
pst.close();
} catch (Exception ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
} catch (SQLException ex) {
logSqlException(ex);
}
}
@ -916,9 +896,8 @@ public class MySQL implements DataSource {
}
rs.close();
st.close();
} catch (Exception ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
} catch (SQLException ex) {
logSqlException(ex);
}
return result;
}
@ -931,9 +910,8 @@ public class MySQL implements DataSource {
pst.setString(1, newOne);
pst.setString(2, oldOne);
pst.executeUpdate();
} catch (Exception ex) {
ConsoleLogger.showError(ex.getMessage());
ConsoleLogger.writeStackTrace(ex);
} catch (SQLException ex) {
logSqlException(ex);
}
}
@ -1041,8 +1019,7 @@ public class MySQL implements DataSource {
}
private static void logSqlException(SQLException e) {
ConsoleLogger.showError("Error executing SQL query: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.logException("Error during SQL operation:", e);
}
}

View File

@ -108,6 +108,9 @@ public class AuthMePlayerListener implements Listener {
if (Settings.useEssentialsMotd && cmd.equals("/motd")) {
return;
}
if(!Settings.isForcedRegistrationEnabled && Settings.allowAllCommandsIfRegIsOptional) {
return;
}
if (Settings.allowCommands.contains(cmd)) {
return;
}
@ -185,7 +188,7 @@ public class AuthMePlayerListener implements Listener {
}
}
@EventHandler(priority = EventPriority.LOW)
@EventHandler(priority = EventPriority.LOWEST)
public void onPlayerJoin(PlayerJoinEvent event) {
final Player player = event.getPlayer();
if (player == null) {

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

@ -135,8 +135,7 @@ public class ModuleManager {
}
} catch (Exception ex) {
ConsoleLogger.writeStackTrace(ex);
ConsoleLogger.showError("Cannot load " + pathToJar.getName() + " jar file !");
ConsoleLogger.logException("Cannot load " + pathToJar.getName() + " jar file!", ex);
} finally {
try {
if (jarFile != null) {

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

@ -2,7 +2,6 @@ package fr.xephi.authme.process;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.process.email.AsyncAddEmail;
import fr.xephi.authme.process.email.AsyncChangeEmail;
import fr.xephi.authme.process.join.AsynchronousJoin;
import fr.xephi.authme.process.login.AsynchronousLogin;
@ -10,6 +9,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;
@ -19,15 +19,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) {
@ -35,7 +37,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();
}
});
}
@ -55,7 +58,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();
}
});
}
@ -96,8 +99,7 @@ public class Management {
sched.runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
new AsyncAddEmail(plugin, player, newEmail, plugin.getDataSource(), PlayerCache.getInstance())
.process();
new AsyncChangeEmail(player, plugin, null, newEmail, plugin.getDataSource(), PlayerCache.getInstance(), settings).process();
}
});
}
@ -106,7 +108,7 @@ public class Management {
sched.runTaskAsynchronously(plugin, new Runnable() {
@Override
public void run() {
new AsyncChangeEmail(player, plugin, oldEmail, newEmail, plugin.getDataSource(), PlayerCache.getInstance()).process();
new AsyncChangeEmail(player, plugin, oldEmail, newEmail, plugin.getDataSource(), PlayerCache.getInstance(), settings).process();
}
});
}

View File

@ -6,8 +6,10 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
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;
/**
@ -20,13 +22,16 @@ public class AsyncAddEmail {
private final Messages messages;
private final DataSource dataSource;
private final PlayerCache playerCache;
private final NewSetting settings;
public AsyncAddEmail(AuthMe plugin, Player player, String email, DataSource dataSource, PlayerCache playerCache) {
public AsyncAddEmail(AuthMe plugin, Player player, String email, DataSource dataSource,
PlayerCache playerCache, NewSetting settings) {
this.messages = plugin.getMessages();
this.player = player;
this.email = email;
this.dataSource = dataSource;
this.playerCache = playerCache;
this.settings = settings;
}
public void process() {
@ -52,9 +57,9 @@ public class AsyncAddEmail {
}
}
private static boolean isEmailInvalid(String email) {
private boolean isEmailInvalid(String email) {
return StringUtils.isEmpty(email) || "your@email.com".equals(email)
|| !Settings.isEmailCorrect(email);
|| !Utils.isEmailCorrect(email, settings);
}
private void sendUnloggedMessage(DataSource dataSource) {

View File

@ -6,8 +6,10 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
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,17 +21,19 @@ public class AsyncChangeEmail {
private final String oldEmail;
private final String newEmail;
private final Messages m;
private final NewSetting settings;
private final PlayerCache playerCache;
private final DataSource dataSource;
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail,
String newEmail, DataSource dataSource, PlayerCache playerCache) {
public AsyncChangeEmail(Player player, AuthMe plugin, String oldEmail, String newEmail, DataSource dataSource,
PlayerCache playerCache, NewSetting settings) {
this.m = plugin.getMessages();
this.player = player;
this.oldEmail = oldEmail;
this.newEmail = newEmail;
this.playerCache = playerCache;
this.dataSource = dataSource;
this.settings = settings;
}
public void process() {
@ -54,9 +58,9 @@ public class AsyncChangeEmail {
}
}
private static boolean isEmailInvalid(String email) {
private boolean isEmailInvalid(String email) {
return StringUtils.isEmpty(email) || "your@email.com".equals(email)
|| !Settings.isEmailCorrect(email);
|| !Utils.isEmailCorrect(email, settings);
}
private void saveNewEmail(PlayerAuth auth) {

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);
}
@ -225,7 +225,7 @@ public class AsynchronousJoin {
? m.retrieve(MessageKey.REGISTER_EMAIL_MESSAGE)
: m.retrieve(MessageKey.REGISTER_MESSAGE);
}
if (LimboCache.getInstance().getLimboPlayer(name) != null) {
if (msgInterval > 0 && LimboCache.getInstance().getLimboPlayer(name) != null) {
BukkitTask msgTask = sched.runTaskAsynchronously(plugin, new MessageTask(plugin, name, msg, msgInterval));
LimboCache.getInstance().getLimboPlayer(name).setMessageTaskId(msgTask);
}
@ -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,13 +172,11 @@ 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")) {
if (Settings.recallEmail && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) {
m.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
}
}
if (!Settings.noConsoleSpam) {
ConsoleLogger.info(realName + " logged in!");
@ -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;
if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(Settings.sendPlayerTo);
out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER));
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
}
}

View File

@ -49,6 +49,13 @@ public class ProcessSyncronousPlayerLogout implements Runnable {
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
protected void restoreSpeedEffect() {
if (Settings.isRemoveSpeedEnabled) {
player.setWalkSpeed(0.0F);
player.setFlySpeed(0.0F);
}
}
/**
* Method run.
*
@ -77,6 +84,7 @@ public class ProcessSyncronousPlayerLogout implements Runnable {
if (Settings.applyBlindEffect)
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, Settings.getRegistrationTimeout * 20, 2));
player.setOp(false);
restoreSpeedEffect();
// Player is now logout... Time to fire event !
Bukkit.getServer().getPluginManager().callEvent(new LogoutEvent(player));
if (Settings.bungee)

View File

@ -75,18 +75,21 @@ public class AsynchronousQuit {
}
if (Settings.isSessionsEnabled && !isKick) {
if (Settings.getSessionTimeout != 0) {
if (plugin.isEnabled()) {
BukkitTask task = plugin.getServer().getScheduler().runTaskLaterAsynchronously(plugin, new Runnable() {
@Override
public void run() {
PlayerCache.getInstance().removePlayer(name);
if (database.isLogged(name))
database.setUnlogged(name);
plugin.sessions.remove(name);
postLogout();
}
}, Settings.getSessionTimeout * 20 * 60);
plugin.sessions.put(name, task);
} else {
//plugin is disable we canno schedule more tasks so run it directly here
postLogout();
}
}
} else {
PlayerCache.getInstance().removePlayer(name);
@ -94,6 +97,15 @@ public class AsynchronousQuit {
}
plugin.realIp.remove(name);
if (plugin.isEnabled()) {
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new ProcessSyncronousPlayerQuit(plugin, player, isOp, needToChange));
}
}
private void postLogout() {
PlayerCache.getInstance().removePlayer(name);
if (database.isLogged(name))
database.setUnlogged(name);
plugin.sessions.remove(name);
}
}

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 {
@ -75,14 +79,13 @@ public class AsyncRegister {
if (!preRegisterCheck()) {
return;
}
if (!email.isEmpty() && !email.equals("")) {
if (email != null && !email.isEmpty()) {
emailRegister();
} else {
passwordRegister();
}
} catch (Exception e) {
ConsoleLogger.showError(e.getMessage());
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.logException("Error during async register process", e);
m.send(player, MessageKey.ERROR);
}
}
@ -137,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;
if (!settings.getProperty(HooksSettings.BUNGEECORD_SERVER).isEmpty()) {
ByteArrayDataOutput out = ByteStreams.newDataOutput();
out.writeUTF("Connect");
out.writeUTF(Settings.sendPlayerTo);
out.writeUTF(settings.getProperty(HooksSettings.BUNGEECORD_SERVER));
player.sendPluginMessage(plugin, "BungeeCord", out.toByteArray());
}
}
}

View File

@ -2,11 +2,6 @@ package fr.xephi.authme.security.crypts;
import fr.xephi.authme.security.HashUtils;
import fr.xephi.authme.security.MessageDigestAlgorithm;
import fr.xephi.authme.security.crypts.description.Usage;
import fr.xephi.authme.security.crypts.description.Recommendation;
import fr.xephi.authme.security.crypts.description.SaltType;
import fr.xephi.authme.security.crypts.description.HasSalt;
import java.nio.charset.Charset;
import java.security.MessageDigest;

View File

@ -77,8 +77,7 @@ public abstract class CustomConfiguration extends YamlConfiguration {
return true;
}
} catch (Exception e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.showError("Failed to load config from JAR");
ConsoleLogger.logException("Failed to load config from JAR", e);
}
}
return false;

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,
@ -77,21 +65,20 @@ public final class Settings {
enableProtection, enableAntiBot, recallEmail, useWelcomeMessage,
broadcastWelcomeMessage, forceRegKick, forceRegLogin,
checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect,
kickPlayersBeforeStopping,
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,13 +168,11 @@ 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);
allowAllCommandsIfRegIsOptional = configFile.getBoolean("settings.restrictions.allowAllCommandsIfRegistrationIsOptional", false);
allowCommands = new ArrayList<>();
allowCommands.addAll(Arrays.asList("/login", "/l", "/register", "/reg", "/email", "/captcha"));
for (String cmd : configFile.getStringList("settings.restrictions.allowCommands")) {
@ -226,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);
@ -297,34 +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.showError("Error loading email text: " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(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,321 +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.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.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!");
}
}
/**
* @param path
*
* @return
*/
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>
@ -765,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,156 +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.showError("Could not save config file - " + StringUtils.formatException(e));
ConsoleLogger.writeStackTrace(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);
}
}
@ -138,25 +97,20 @@ public abstract class PropertyType<T> {
return configuration.getStringList(property.getPath());
}
@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;
}
@Override
public boolean contains(Property<List<String>> property, FileConfiguration configuration) {
return configuration.contains(property.getPath()) && configuration.isList(property.getPath());
}
@Override
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;
@ -18,13 +18,19 @@ public class RestrictionSettings implements SettingsClass {
public static final Property<Boolean> ALLOW_CHAT =
newProperty("settings.restrictions.allowChat", false);
@Comment({
"Allow unlogged users to use all the commands if registration is not forced!",
"WARNING: use this only if you need it!)"})
public static final Property<Boolean> ALLOW_ALL_COMMANDS_IF_REGISTRATION_IS_OPTIONAL =
newProperty("settings.restrictions.allowAllCommandsIfRegistrationIsOptional", false);
@Comment("Allowed commands for unauthenticated players")
public static final Property<List<String>> ALLOW_COMMANDS =
newProperty(PropertyType.STRING_LIST, "settings.restrictions.allowCommands",
"login", "register", "l", "reg", "email", "captcha");
@Comment("Max number of allowed registrations per IP")
// TODO ljacqu 20160109: If 0 == unlimited, add this fact ot the comment
// TODO ljacqu 20160109: If 0 == unlimited, add this fact to the comment
public static final Property<Integer> MAX_REGISTRATION_PER_IP =
newProperty("settings.restrictions.maxRegPerIp", 1);

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

@ -31,9 +31,4 @@ final class PropertyMapComparator implements Comparator<Property> {
return Node.compare(parent, p1.getPath(), p2.getPath());
}
@Override
public boolean equals(Object obj) {
return this == obj;
}
}

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

@ -36,7 +36,7 @@ public class GeoLiteAPI {
plugin.getLogger().info(LICENSE);
return true;
} catch (IOException e) {
// TODO ljacqu 20151123: Log the exception instead of just swallowing it
ConsoleLogger.logException("Could not find/download GeoLiteAPI", e);
return false;
}
}
@ -63,7 +63,7 @@ public class GeoLiteAPI {
output.close();
input.close();
} catch (IOException e) {
ConsoleLogger.writeStackTrace(e);
ConsoleLogger.logException("Could not download GeoLiteAPI", e);
}
}
});

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

@ -67,6 +67,9 @@ settings:
# Care that this feature blocks also all the commands not
# listed in the list below.
allowChat: false
# WARNING: use this only if you need it!
# Allow unlogged users to use all the commands if registration is not forced!
allowAllCommandsIfRegistrationIsOptional: false
# Commands allowed when a player is not authenticated
allowCommands:
- /login
@ -305,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

@ -4,56 +4,56 @@ registered: '&aSikeres regisztráció. Üdvözöllek!'
user_regged: '&cJátékosnév már regisztrálva'
login_msg: '&cKérlek jelentkezz be: "/login jelszó"'
not_logged_in: '&cNem vagy bejelentkezve!'
logout: '&cSikeresen kijelentkeztél'
usage_log: '&cBejelentkezés: /login jelszó'
unknown_user: User is not in database
reg_voluntarily: Regisztrálhatod beceneved a szerveren a következö parancsal "/register jelszó jelszó"
reg_disabled: '&cRegisztráció letiltva'
no_perm: '&cNincs engedélyed'
usage_reg: '&cHasználat: /register jelszó jelszóújra'
password_error_nick: '&fYou can''t use your name as password'
password_error_unsafe: '&fYou can''t use unsafe passwords'
logout: '&cSikeresen kijelentkeztél!'
usage_log: '&cBejelentkezés: /login <jelszó>'
unknown_user: '&cA kért felhasználó nem telálható az adatbázisban!'
reg_voluntarily: Regisztrálhatod magad a szerveren a következö parancsal "/register <jelszó> <jelszó újra>"
reg_disabled: '&cRegisztráció letiltva!'
no_perm: '&cNincs jogod ehhez!'
usage_reg: '&cHasználat: /register <jelszó> <jelszó újra>'
password_error_nick: '&cNem használhatod a felhasználóneved jelszónak, kérlek válassz másikat...'
password_error_unsafe: '&cA választott jelszó nem biztonságos, kérlek válassz másikat...'
unregistered: '&cRegisztráció sikeresen törölve!'
same_nick: Ezen a játékosnéven már játszanak
valid_session: '&cSession login'
same_nick: 'Ezzel a játékosnévvel már játszanak a szerveren.'
valid_session: '&2A hálózati kapcsolat újraépítése megtörtént.'
pwd_changed: '&cJelszó cserélve!'
reload: Beálítások és adatbázis újratöltve!
timeout: Bejelentkezési idötúllépés
error: Hiba lépett fel; Lépj kapcsolatba a tulajjal'
reload: 'Beálítások és adatbázis újratöltve!'
timeout: 'Bejelentkezési időtúllépés!'
error: 'Hiba lépett fel; Lépj kapcsolatba a tulajjal'
logged_in: '&cMár be vagy jelentkezve!'
login: '&aSikeresen Beléptél! Üdvözöllek!!!'
wrong_pwd: '&4Hibás jelszó'
user_unknown: '&cJátékosnév nem regisztrált'
login: '&aSikeresen beléptél!'
wrong_pwd: '&4Hibás jelszó!'
user_unknown: '&cEz a felhasználó nincs regisztrálva!'
reg_msg: '&cKérlek Regisztrálj: "/register jelszó jelszóújra"'
reg_email_msg: '&cPlease register with "/register <email> <confirmEmail>"'
unsafe_spawn: A kilépési helyzeted nem biztonságos, teleportálás a kezdö Spawnra.
max_reg: Csak egy karakterrel Registrálhatsz!!!
password_error: A jelszó nem illik össze
invalid_session: Session Dataes doesnt corrispond Plaese wait the end of session
pass_len: A jelszavad nem éri el a minimális hosszat
vb_nonActiv: Your Account isent Activated yet check your Emails!
usage_changepassword: 'használat: /changepassword régiJelszó újJelszó'
name_len: '&cYour nickname is too Short or too long'
regex: '&cYour nickname contains illegal characters. Allowed chars: REG_EX'
add_email: '&cPlease add your email with : /email add yourEmail confirmEmail'
recovery_email: '&cForgot your password? Please use /email recovery <yourEmail>'
usage_captcha: '&cUsage: /captcha <theCaptcha>'
wrong_captcha: '&cWrong Captcha, please use : /captcha THE_CAPTCHA'
valid_captcha: '&cYour captcha is valid !'
kick_forvip: '&cA VIP Player join the full server!'
kick_fullserver: '&cThe server is actually full, Sorry!'
usage_email_add: '&fUsage: /email add <email> <confirmEmail> '
usage_email_change: '&fUsage: /email change <oldEmail> <newEmail> '
usage_email_recovery: '&fUsage: /email recovery <Email>'
new_email_invalid: '[AuthMe] New email invalid!'
old_email_invalid: '[AuthMe] Old email invalid!'
email_invalid: '[AuthMe] Invalid Email'
email_added: '[AuthMe] Email Added !'
email_confirm: '[AuthMe] Confirm your Email !'
email_changed: '[AuthMe] Email Change !'
email_send: '[AuthMe] Recovery Email Send !'
country_banned: 'Your country is banned from this server'
antibot_auto_enabled: '[AuthMe] AntiBotMod automatically enabled due to massive connections!'
antibot_auto_disabled: '[AuthMe] AntiBotMod automatically disabled after %m Minutes, hope invasion stopped'
kick_antibot: 'AntiBot protection mode is enabled! You have to wait some minutes before joining the server.'
email_exists: '&cA recovery email was already sent! You can discard it and send a new one using the command below:'
reg_email_msg: '&cKérlek regisztrálj: "/register <Email> <Email újra>"'
unsafe_spawn: 'A kilépési helyzeted nem biztonságos, teleportálás a Spawnra.'
max_reg: 'Csak egy karakterrel registrálhatsz!'
password_error: 'A két jelszó nem egyezik!'
invalid_session: '&cAz IP címed megváltozott és a hálózati kapcsolatod lejárt. Kapcsolódj újra.'
pass_len: 'A jelszavad nem éri el a minimális hosszúságot!'
vb_nonActiv: '&cA felhasználód aktiválása még nem történt meg, ellenőrizd a leveleid!'
usage_changepassword: 'Használat: /changepassword <régi Jelszó> <új Jelszó>'
name_len: '&4A felhasználó neved túl hosszú, vagy túl rövid! Válassz másikat!'
regex: '&4A felhasználóneved nem használható karaktereket tartalmaz. Elfogadott karakterek: REG_EX'
add_email: '&3Kérlek add hozzá a felhasználódhoz az email címedet "/email add <Email címed> <Email címed ismét>"'
recovery_email: '&3Ha elfelejtetted a jelszavad, használd az: "/email recovery <regisztrált Email címed>"'
usage_captcha: '&3A bejelentkezéshez CAPTCHA szükséges, kérem használd a következő parancsot "/captcha <Captcha>"'
wrong_captcha: '&cHibás captcha, kérlek írd be a következő parancsot "/captcha THE_CAPTCHA" a chat-be!'
valid_captcha: '&2Captcha sikeresen feloldva!'
kick_forvip: '&3VIP játékos csatlakozott a szerverhez!'
kick_fullserver: '&4A szerver megtelt, próbálj csatlakozni később!'
usage_email_add: '&cHasználat: /email add <email> <Email újra>'
usage_email_change: '&cHasználat: /email change <régi Email> <új Email>'
usage_email_recovery: '&cHasználat: /email recovery <email>'
new_email_invalid: '&cHibás az új email cím, próbáld újra!'
old_email_invalid: '&cHibás a régi email cím, próbáld újra!'
email_invalid: '&cHibás az email cím, próbáld újra!'
email_added: '&2Az email címed rögzítése sikeresen megtörtént!'
email_confirm: '&cKérlek ellenőrízd az email címedet!'
email_changed: '&2Az email cím cseréje sikeresen megtörtént!'
email_send: '&2A jelszó visszaállításhoz szükséges emailt elküldtük! Ellenőrízd a leveleidet!'
email_exists: '&cA visszaállító emailt elküldtük! Hiba esetén újkérheted az alábbi parancs segítségével:'
country_banned: '&4Az országod tiltólistán van ezen a szerveren!'
antibot_auto_enabled: '&4[AntiBot] Az AntiBot védelem bekapcsolt a nagy számú hálózati kapcsolat miatt!'
antibot_auto_disabled: '&2[AntiBot] Az AntiBot kikapcsol %m múlva!'
kick_antibot: 'Az AntiBot védelem bekapcsolva! Kérünk várj pár másodpercet a csatlakozáshoz.'

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

@ -2,6 +2,7 @@ package fr.xephi.authme.command.executable.email;
import fr.xephi.authme.command.CommandService;
import fr.xephi.authme.process.Management;
import fr.xephi.authme.settings.NewSetting;
import fr.xephi.authme.util.WrapperMock;
import org.bukkit.command.BlockCommandSender;
import org.bukkit.command.CommandSender;
@ -51,6 +52,8 @@ public class AddEmailCommandTest {
AddEmailCommand command = new AddEmailCommand();
Management management = mock(Management.class);
given(commandService.getManagement()).willReturn(management);
NewSetting settings = mock(NewSetting.class);
given(commandService.getSettings()).willReturn(settings);
// when
command.executeCommand(sender, Arrays.asList("mail@example", "mail@example"), commandService);

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

@ -6,6 +6,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
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.WrapperMock;
import org.bukkit.entity.Player;
@ -29,6 +30,7 @@ public class AsyncAddEmailTest {
private Player player;
private DataSource dataSource;
private PlayerCache playerCache;
private NewSetting settings;
@BeforeClass
public static void setUp() {
@ -184,7 +186,8 @@ public class AsyncAddEmailTest {
player = mock(Player.class);
dataSource = mock(DataSource.class);
playerCache = mock(PlayerCache.class);
return new AsyncAddEmail(authMe, player, email, dataSource, playerCache);
settings = mock(NewSetting.class);
return new AsyncAddEmail(authMe, player, email, dataSource, playerCache, settings);
}
}

View File

@ -6,6 +6,7 @@ import fr.xephi.authme.cache.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
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.WrapperMock;
import org.bukkit.entity.Player;
@ -29,6 +30,7 @@ public class AsyncChangeEmailTest {
private Messages messages;
private PlayerCache playerCache;
private DataSource dataSource;
private NewSetting settings;
@BeforeClass
public static void setUp() {
@ -221,6 +223,7 @@ public class AsyncChangeEmailTest {
when(authMe.getMessages()).thenReturn(messages);
playerCache = mock(PlayerCache.class);
dataSource = mock(DataSource.class);
return new AsyncChangeEmail(player, authMe, oldEmail, newEmail, dataSource, playerCache);
settings = mock(NewSetting.class);
return new AsyncChangeEmail(player, authMe, oldEmail, newEmail, dataSource, playerCache, settings);
}
}

View File

@ -11,7 +11,6 @@ import fr.xephi.authme.util.WrapperMock;
import org.bukkit.event.Event;
import org.bukkit.plugin.PluginManager;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
@ -25,7 +24,6 @@ import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.argThat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;

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,22 @@
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.Ignore;
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 +41,7 @@ public class UtilsTest {
public static void setUpMocks() {
WrapperMock wrapperMock = WrapperMock.createInstance();
authMeMock = wrapperMock.getAuthMe();
ConsoleLoggerTestInitializer.setupLogger();
}
@Before
@ -64,6 +71,10 @@ public class UtilsTest {
}
@Test
@Ignore
// TODO ljacqu 20160206: Running this test with all others results in an error
// because Utils is used elsewhere. The AuthMe field is set in a static block
// so creating the WrapperMock here will have no effect
public void shouldNotAddToNormalGroupIfPermManagerIsNull() {
// given
Settings.isPermissionCheckEnabled = true;
@ -92,8 +103,96 @@ 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
@SuppressWarnings("unused")
public static Player[] onlinePlayersImpl() {
return new Player[]{
mock(Player.class), mock(Player.class)

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: