Remove all files

This commit is contained in:
HaHaWTH
2023-09-20 02:10:19 +08:00
parent 62f27f8231
commit ed320196fe
478 changed files with 0 additions and 94591 deletions
@@ -1,10 +0,0 @@
package fr.xephi.authme.process;
/**
* Marker interface for asynchronous AuthMe processes.
* <p>
* These processes handle intensive (I/O or otherwise) actions and are
* therefore scheduled to run asynchronously.
*/
public interface AsynchronousProcess {
}
@@ -1,107 +0,0 @@
package fr.xephi.authme.process;
import fr.xephi.authme.process.changepassword.AsyncChangePassword;
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;
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.register.executors.RegistrationMethod;
import fr.xephi.authme.process.register.executors.RegistrationParameters;
import fr.xephi.authme.process.unregister.AsynchronousUnregister;
import fr.xephi.authme.service.BukkitService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Performs auth actions, e.g. when a player joins, registers or wants to change his password.
*/
public class Management {
@Inject
private BukkitService bukkitService;
// Processes
@Inject
private AsyncAddEmail asyncAddEmail;
@Inject
private AsyncChangeEmail asyncChangeEmail;
@Inject
private AsynchronousLogout asynchronousLogout;
@Inject
private AsynchronousQuit asynchronousQuit;
@Inject
private AsynchronousJoin asynchronousJoin;
@Inject
private AsyncRegister asyncRegister;
@Inject
private AsynchronousLogin asynchronousLogin;
@Inject
private AsynchronousUnregister asynchronousUnregister;
@Inject
private AsyncChangePassword asyncChangePassword;
Management() {
}
public void performLogin(Player player, String password) {
runTask(() -> asynchronousLogin.login(player, password));
}
public void forceLogin(Player player) {
runTask(() -> asynchronousLogin.forceLogin(player));
}
public void forceLogin(Player player, boolean quiet) {
runTask(() -> asynchronousLogin.forceLogin(player, quiet));
}
public void performLogout(Player player) {
runTask(() -> asynchronousLogout.logout(player));
}
public <P extends RegistrationParameters> void performRegister(RegistrationMethod<P> variant, P parameters) {
runTask(() -> asyncRegister.register(variant, parameters));
}
public void performUnregister(Player player, String password) {
runTask(() -> asynchronousUnregister.unregister(player, password));
}
public void performUnregisterByAdmin(CommandSender initiator, String name, Player player) {
runTask(() -> asynchronousUnregister.adminUnregister(initiator, name, player));
}
public void performJoin(Player player) {
runTask(() -> asynchronousJoin.processJoin(player));
}
public void performQuit(Player player) {
runTask(() -> asynchronousQuit.processQuit(player));
}
public void performAddEmail(Player player, String newEmail) {
runTask(() -> asyncAddEmail.addEmail(player, newEmail));
}
public void performChangeEmail(Player player, String oldEmail, String newEmail) {
runTask(() -> asyncChangeEmail.changeEmail(player, oldEmail, newEmail));
}
public void performPasswordChange(Player player, String oldPassword, String newPassword) {
runTask(() -> asyncChangePassword.changePassword(player, oldPassword, newPassword));
}
public void performPasswordChangeAsAdmin(CommandSender sender, String playerName, String newPassword) {
runTask(() -> asyncChangePassword.changePasswordAsAdmin(sender, playerName, newPassword));
}
private void runTask(Runnable runnable) {
bukkitService.runTaskOptionallyAsync(runnable);
}
}
@@ -1,62 +0,0 @@
package fr.xephi.authme.process;
import fr.xephi.authme.process.login.ProcessSyncPlayerLogin;
import fr.xephi.authme.process.logout.ProcessSyncPlayerLogout;
import fr.xephi.authme.process.quit.ProcessSyncPlayerQuit;
import fr.xephi.authme.process.register.ProcessSyncEmailRegister;
import fr.xephi.authme.process.register.ProcessSyncPasswordRegister;
import fr.xephi.authme.service.BukkitService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
/**
* Manager for scheduling synchronous processes internally from the asynchronous processes.
* These synchronous processes are a continuation of the associated async processes; they only
* contain certain tasks which may only be run synchronously (most interactions with Bukkit).
* These synchronous tasks should never be called aside from the asynchronous processes.
*
* @see Management
*/
public class SyncProcessManager {
@Inject
private BukkitService bukkitService;
@Inject
private ProcessSyncEmailRegister processSyncEmailRegister;
@Inject
private ProcessSyncPasswordRegister processSyncPasswordRegister;
@Inject
private ProcessSyncPlayerLogin processSyncPlayerLogin;
@Inject
private ProcessSyncPlayerLogout processSyncPlayerLogout;
@Inject
private ProcessSyncPlayerQuit processSyncPlayerQuit;
public void processSyncEmailRegister(Player player) {
runTask(() -> processSyncEmailRegister.processEmailRegister(player));
}
public void processSyncPasswordRegister(Player player) {
runTask(() -> processSyncPasswordRegister.processPasswordRegister(player));
}
public void processSyncPlayerLogout(Player player) {
runTask(() -> processSyncPlayerLogout.processSyncLogout(player));
}
public void processSyncPlayerLogin(Player player, boolean isFirstLogin, List<String> authsWithSameIp) {
runTask(() -> processSyncPlayerLogin.processPlayerLogin(player, isFirstLogin, authsWithSameIp));
}
public void processSyncPlayerQuit(Player player, boolean wasLoggedIn) {
runTask(() -> processSyncPlayerQuit.processSyncQuit(player, wasLoggedIn));
}
private void runTask(Runnable runnable) {
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(runnable);
}
}
@@ -1,10 +0,0 @@
package fr.xephi.authme.process;
/**
* Marker interface for synchronous processes.
* <p>
* Such processes are scheduled by {@link AsynchronousProcess asynchronous tasks} to perform tasks
* which are required to be executed synchronously (e.g. interactions with the Bukkit API).
*/
public interface SynchronousProcess {
}
@@ -1,102 +0,0 @@
package fr.xephi.authme.process.changepassword;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.CommonService;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Locale;
public class AsyncChangePassword implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncChangePassword.class);
@Inject
private DataSource dataSource;
@Inject
private CommonService commonService;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private PlayerCache playerCache;
AsyncChangePassword() {
}
/**
* Change password for an online player
*
* @param player the player
* @param oldPassword the old password used by the player
* @param newPassword the new password chosen by the player
*/
public void changePassword(Player player, String oldPassword, String newPassword) {
String name = player.getName().toLowerCase(Locale.ROOT);
PlayerAuth auth = playerCache.getAuth(name);
if (passwordSecurity.comparePassword(oldPassword, auth.getPassword(), player.getName())) {
HashedPassword hashedPassword = passwordSecurity.computeHash(newPassword, name);
auth.setPassword(hashedPassword);
if (!dataSource.updatePassword(auth)) {
commonService.send(player, MessageKey.ERROR);
return;
}
// TODO: send an update when a messaging service will be implemented (PASSWORD_CHANGED)
playerCache.updatePlayer(auth);
commonService.send(player, MessageKey.PASSWORD_CHANGED_SUCCESS);
logger.info(player.getName() + " changed his password");
} else {
commonService.send(player, MessageKey.WRONG_PASSWORD);
}
}
/**
* Change a user's password as an administrator, without asking for the previous one
*
* @param sender who is performing the operation, null if called by other plugins
* @param playerName the player name
* @param newPassword the new password chosen for the player
*/
public void changePasswordAsAdmin(CommandSender sender, String playerName, String newPassword) {
String lowerCaseName = playerName.toLowerCase(Locale.ROOT);
if (!(playerCache.isAuthenticated(lowerCaseName) || dataSource.isAuthAvailable(lowerCaseName))) {
if (sender == null) {
logger.warning("Tried to change password for user " + lowerCaseName + " but it doesn't exist!");
} else {
commonService.send(sender, MessageKey.UNKNOWN_USER);
}
return;
}
HashedPassword hashedPassword = passwordSecurity.computeHash(newPassword, lowerCaseName);
if (dataSource.updatePassword(lowerCaseName, hashedPassword)) {
// TODO: send an update when a messaging service will be implemented (PASSWORD_CHANGED)
if (sender != null) {
commonService.send(sender, MessageKey.PASSWORD_CHANGED_SUCCESS);
logger.info(sender.getName() + " changed password of " + lowerCaseName);
} else {
logger.info("Changed password of " + lowerCaseName);
}
} else {
if (sender != null) {
commonService.send(sender, MessageKey.ERROR);
}
logger.warning("An error occurred while changing password for user " + lowerCaseName + "!");
}
}
}
@@ -1,95 +0,0 @@
package fr.xephi.authme.process.email;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.EmailChangedEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.util.Utils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Locale;
/**
* Async task to add an email to an account.
*/
public class AsyncAddEmail implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncAddEmail.class);
@Inject
private CommonService service;
@Inject
private DataSource dataSource;
@Inject
private PlayerCache playerCache;
@Inject
private ValidationService validationService;
@Inject
private BukkitService bukkitService;
AsyncAddEmail() {
}
/**
* Handles the request to add the given email to the player's account.
*
* @param player the player to add the email to
* @param email the email to add
*/
public void addEmail(Player player, String email) {
String playerName = player.getName().toLowerCase(Locale.ROOT);
if (playerCache.isAuthenticated(playerName)) {
PlayerAuth auth = playerCache.getAuth(playerName);
String currentEmail = auth.getEmail();
if (!Utils.isEmailEmpty(currentEmail)) {
service.send(player, MessageKey.USAGE_CHANGE_EMAIL);
} else if (!validationService.validateEmail(email)) {
service.send(player, MessageKey.INVALID_EMAIL);
} else if (!validationService.isEmailFreeForRegistration(email, player)) {
service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else {
EmailChangedEvent event = bukkitService.createAndCallEvent(isAsync
-> new EmailChangedEvent(player, null, email, isAsync));
if (event.isCancelled()) {
logger.info("Could not add email to player '" + player + "' event was cancelled");
service.send(player, MessageKey.EMAIL_ADD_NOT_ALLOWED);
return;
}
auth.setEmail(email);
if (dataSource.updateEmail(auth)) {
playerCache.updatePlayer(auth);
// TODO: send an update when a messaging service will be implemented (ADD_MAIL)
service.send(player, MessageKey.EMAIL_ADDED_SUCCESS);
} else {
logger.warning("Could not save email for player '" + player + "'");
service.send(player, MessageKey.ERROR);
}
}
} else {
sendUnloggedMessage(player);
}
}
private void sendUnloggedMessage(Player player) {
if (dataSource.isAuthAvailable(player.getName())) {
service.send(player, MessageKey.LOGIN_MESSAGE);
} else {
service.send(player, MessageKey.REGISTER_MESSAGE);
}
}
}
@@ -1,107 +0,0 @@
package fr.xephi.authme.process.email;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.EmailChangedEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Locale;
/**
* Async task for changing the email.
*/
public class AsyncChangeEmail implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsyncChangeEmail.class);
@Inject
private CommonService service;
@Inject
private PlayerCache playerCache;
@Inject
private DataSource dataSource;
@Inject
private ValidationService validationService;
@Inject
private BukkitService bukkitService;
AsyncChangeEmail() {
}
/**
* Handles the request to change the player's email address.
*
* @param player the player to change the email for
* @param oldEmail provided old email
* @param newEmail provided new email
*/
public void changeEmail(Player player, String oldEmail, String newEmail) {
String playerName = player.getName().toLowerCase(Locale.ROOT);
if (playerCache.isAuthenticated(playerName)) {
PlayerAuth auth = playerCache.getAuth(playerName);
String currentEmail = auth.getEmail();
if (currentEmail == null) {
service.send(player, MessageKey.USAGE_ADD_EMAIL);
} else if (newEmail == null || !validationService.validateEmail(newEmail)) {
service.send(player, MessageKey.INVALID_NEW_EMAIL);
} else if (!oldEmail.equalsIgnoreCase(currentEmail)) {
service.send(player, MessageKey.INVALID_OLD_EMAIL);
} else if (!validationService.isEmailFreeForRegistration(newEmail, player)) {
service.send(player, MessageKey.EMAIL_ALREADY_USED_ERROR);
} else {
saveNewEmail(auth, player, oldEmail, newEmail);
}
} else {
outputUnloggedMessage(player);
}
}
/**
* Saves the new email value into the database and informs services.
*
* @param auth the player auth object
* @param player the player object
* @param oldEmail the old email value
* @param newEmail the new email value
*/
private void saveNewEmail(PlayerAuth auth, Player player, String oldEmail, String newEmail) {
EmailChangedEvent event = bukkitService.createAndCallEvent(isAsync
-> new EmailChangedEvent(player, oldEmail, newEmail, isAsync));
if (event.isCancelled()) {
logger.info("Could not change email for player '" + player + "' event was cancelled");
service.send(player, MessageKey.EMAIL_CHANGE_NOT_ALLOWED);
return;
}
auth.setEmail(newEmail);
if (dataSource.updateEmail(auth)) {
playerCache.updatePlayer(auth);
// TODO: send an update when a messaging service will be implemented (CHANGE_MAIL)
service.send(player, MessageKey.EMAIL_CHANGED_SUCCESS);
} else {
service.send(player, MessageKey.ERROR);
}
}
private void outputUnloggedMessage(Player player) {
if (dataSource.isAuthAvailable(player.getName())) {
service.send(player, MessageKey.LOGIN_MESSAGE);
} else {
service.send(player, MessageKey.REGISTER_MESSAGE);
}
}
}
@@ -1,229 +0,0 @@
package fr.xephi.authme.process.join;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.ProxySessionManager;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.ProtectInventoryEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.PluginHookService;
import fr.xephi.authme.service.SessionService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.HooksSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.InternetProtocolUtils;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.GameMode;
import org.bukkit.Server;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import java.util.Locale;
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
/**
* Asynchronous process for when a player joins.
*/
public class AsynchronousJoin implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousJoin.class);
@Inject
private Server server;
@Inject
private DataSource database;
@Inject
private CommonService service;
@Inject
private LimboService limboService;
@Inject
private PluginHookService pluginHookService;
@Inject
private BukkitService bukkitService;
@Inject
private AsynchronousLogin asynchronousLogin;
@Inject
private CommandManager commandManager;
@Inject
private ValidationService validationService;
@Inject
private SessionService sessionService;
@Inject
private BungeeSender bungeeSender;
@Inject
private ProxySessionManager proxySessionManager;
AsynchronousJoin() {
}
/**
* Processes the given player that has just joined.
*
* @param player the player to process
*/
public void processJoin(Player player) {
String name = player.getName().toLowerCase(Locale.ROOT);
String ip = PlayerUtils.getPlayerIp(player);
if (!validationService.fulfillsNameRestrictions(player)) {
handlePlayerWithUnmetNameRestriction(player, ip);
return;
}
if (service.getProperty(RestrictionSettings.UNRESTRICTED_NAMES).contains(name)) {
return;
}
if (service.getProperty(RestrictionSettings.FORCE_SURVIVAL_MODE)
&& player.getGameMode() != GameMode.SURVIVAL
&& !service.hasPermission(player, PlayerStatePermission.BYPASS_FORCE_SURVIVAL)) {
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> player.setGameMode(GameMode.SURVIVAL));
}
if (service.getProperty(HooksSettings.DISABLE_SOCIAL_SPY)) {
pluginHookService.setEssentialsSocialSpyStatus(player, false);
}
if (!validatePlayerCountForIp(player, ip)) {
return;
}
boolean isAuthAvailable = database.isAuthAvailable(name);
if (isAuthAvailable) {
// Protect inventory
if (service.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
ProtectInventoryEvent ev = bukkitService.createAndCallEvent(
isAsync -> new ProtectInventoryEvent(player, isAsync));
if (ev.isCancelled()) {
player.updateInventory();
logger.fine("ProtectInventoryEvent has been cancelled for " + player.getName() + "...");
}
}
// Session logic
if (sessionService.canResumeSession(player)) {
service.send(player, MessageKey.SESSION_RECONNECTION);
// Run commands
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(
() -> commandManager.runCommandsOnSessionLogin(player));
bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player));
return;
} else if (proxySessionManager.shouldResumeSession(name)) {
service.send(player, MessageKey.SESSION_RECONNECTION);
// Run commands
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(
() -> commandManager.runCommandsOnSessionLogin(player));
bukkitService.runTaskOptionallyAsync(() -> asynchronousLogin.forceLogin(player));
logger.info("The user " + player.getName() + " has been automatically logged in, "
+ "as present in autologin queue.");
return;
}
} else if (!service.getProperty(RegistrationSettings.FORCE)) {
// Skip if registration is optional
if (bungeeSender.isEnabled()) {
// As described at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/
// "Keep in mind that you can't send plugin messages directly after a player joins."
bukkitService.scheduleSyncDelayedTask(() ->
bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGIN), 5L);
}
return;
}
processJoinSync(player, isAuthAvailable);
}
private void handlePlayerWithUnmetNameRestriction(Player player, String ip) {
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.NOT_OWNER_ERROR));
if (service.getProperty(RestrictionSettings.BAN_UNKNOWN_IP)) {
server.banIP(ip);
}
});
}
/**
* Performs various operations in sync mode for an unauthenticated player (such as blindness effect and
* limbo player creation).
*
* @param player the player to process
* @param isAuthAvailable true if the player is registered, false otherwise
*/
private void processJoinSync(Player player, boolean isAuthAvailable) {
int registrationTimeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
limboService.createLimboPlayer(player, isAuthAvailable);
player.setNoDamageTicks(registrationTimeout);
if (pluginHookService.isEssentialsAvailable() && service.getProperty(HooksSettings.USE_ESSENTIALS_MOTD)) {
player.performCommand("motd");
}
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
// Allow infinite blindness effect
int blindTimeOut = (registrationTimeout <= 0) ? 99999 : registrationTimeout;
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, blindTimeOut, 2));
}
commandManager.runCommandsOnJoin(player);
});
}
/**
* Checks whether the maximum number of accounts has been exceeded for the given IP address (according to
* settings and permissions). If this is the case, the player is kicked.
*
* @param player the player to verify
* @param ip the ip address of the player
*
* @return true if the verification is OK (no infraction), false if player has been kicked
*/
private boolean validatePlayerCountForIp(Player player, String ip) {
if (service.getProperty(RestrictionSettings.MAX_JOIN_PER_IP) > 0
&& !service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
&& !InternetProtocolUtils.isLoopbackAddress(ip)
&& countOnlinePlayersByIp(ip) > service.getProperty(RestrictionSettings.MAX_JOIN_PER_IP)) {
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(
() -> player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.SAME_IP_ONLINE)));
return false;
}
return true;
}
private int countOnlinePlayersByIp(String ip) {
int count = 0;
for (Player player : bukkitService.getOnlinePlayers()) {
if (ip.equalsIgnoreCase(PlayerUtils.getPlayerIp(player))) {
++count;
}
}
return count;
}
}
@@ -1,390 +0,0 @@
package fr.xephi.authme.process.login;
import com.google.common.annotations.VisibleForTesting;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.TempbanManager;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.captcha.LoginCaptchaManager;
import fr.xephi.authme.data.limbo.LimboMessageType;
import fr.xephi.authme.data.limbo.LimboPlayerState;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent;
import fr.xephi.authme.events.FailedLoginEvent;
import fr.xephi.authme.mail.EmailService;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.permission.AdminPermission;
import fr.xephi.authme.permission.PlayerPermission;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SessionService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
import fr.xephi.authme.settings.properties.DatabaseSettings;
import fr.xephi.authme.settings.properties.EmailSettings;
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.util.InternetProtocolUtils;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.Utils;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
/**
* Asynchronous task for a player login.
*/
public class AsynchronousLogin implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousLogin.class);
@Inject
private DataSource dataSource;
@Inject
private CommonService service;
@Inject
private PlayerCache playerCache;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private BukkitService bukkitService;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private LoginCaptchaManager loginCaptchaManager;
@Inject
private TempbanManager tempbanManager;
@Inject
private LimboService limboService;
@Inject
private EmailService emailService;
@Inject
private SessionService sessionService;
@Inject
private BungeeSender bungeeSender;
AsynchronousLogin() {
}
/**
* Processes a player's login request.
*
* @param player the player to log in
* @param password the password to log in with
*/
public void login(Player player, String password) {
PlayerAuth auth = getPlayerAuth(player);
if (auth != null && checkPlayerInfo(player, auth, password)) {
if (auth.getTotpKey() != null) {
limboService.resetMessageTask(player, LimboMessageType.TOTP_CODE);
limboService.getLimboPlayer(player.getName()).setState(LimboPlayerState.TOTP_REQUIRED);
// TODO #1141: Check if we should check limbo state before processing password
} else {
performLogin(player, auth);
}
}
}
/**
* Logs a player in without requiring a password.
*
* @param player the player to log in
*/
public void forceLogin(Player player) {
PlayerAuth auth = getPlayerAuth(player);
if (auth != null) {
performLogin(player, auth);
}
}
/**
* Logs a player in without requiring a password.
*
* @param player the player to log in
* @param quiet if true no messages will be sent
*/
public void forceLogin(Player player, boolean quiet) {
PlayerAuth auth = getPlayerAuth(player, quiet);
if (auth != null) {
performLogin(player, auth);
}
}
/**
* Checks the precondition for authentication (like user known) and returns
* the player's {@link PlayerAuth} object.
*
* @param player the player to check
* @return the PlayerAuth object, or {@code null} if the player doesn't exist or may not log in
* (e.g. because he is already logged in)
*/
private PlayerAuth getPlayerAuth(Player player) {
return getPlayerAuth(player, false);
}
/**
* Checks the precondition for authentication (like user known) and returns
* the player's {@link PlayerAuth} object.
*
* @param player the player to check
* @param quiet don't send messages
* @return the PlayerAuth object, or {@code null} if the player doesn't exist or may not log in
* (e.g. because he is already logged in)
*/
private PlayerAuth getPlayerAuth(Player player, boolean quiet) {
String name = player.getName().toLowerCase(Locale.ROOT);
if (playerCache.isAuthenticated(name)) {
if (!quiet) {
service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
}
return null;
}
PlayerAuth auth = dataSource.getAuth(name);
if (auth == null) {
if (!quiet) {
service.send(player, MessageKey.UNKNOWN_USER);
}
// Recreate the message task to immediately send the message again as response
limboService.resetMessageTask(player, LimboMessageType.REGISTER);
return null;
}
if (!service.getProperty(DatabaseSettings.MYSQL_COL_GROUP).isEmpty()
&& auth.getGroupId() == service.getProperty(HooksSettings.NON_ACTIVATED_USERS_GROUP)) {
if (!quiet) {
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
}
return null;
}
String ip = PlayerUtils.getPlayerIp(player);
if (hasReachedMaxLoggedInPlayersForIp(player, ip)) {
if (!quiet) {
service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
}
return null;
}
boolean isAsync = service.getProperty(PluginSettings.USE_ASYNC_TASKS);
AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player, isAsync);
bukkitService.callEvent(event);
if (!event.canLogin()) {
return null;
}
return auth;
}
/**
* Checks various conditions for regular player login (not used in force login).
*
* @param player the player requesting to log in
* @param auth the PlayerAuth object of the player
* @param password the password supplied by the player
* @return true if the password matches and all other conditions are met (e.g. no captcha required),
* false otherwise
*/
private boolean checkPlayerInfo(Player player, PlayerAuth auth, String password) {
String name = player.getName().toLowerCase(Locale.ROOT);
// If captcha is required send a message to the player and deny to log in
if (loginCaptchaManager.isCaptchaRequired(name)) {
service.send(player, MessageKey.USAGE_CAPTCHA, loginCaptchaManager.getCaptchaCodeOrGenerateNew(name));
return false;
}
String ip = PlayerUtils.getPlayerIp(player);
// Increase the counts here before knowing the result of the login.
loginCaptchaManager.increaseLoginFailureCount(name);
tempbanManager.increaseCount(ip, name);
if (passwordSecurity.comparePassword(password, auth.getPassword(), player.getName())) {
return true;
} else {
handleWrongPassword(player, auth, ip);
return false;
}
}
/**
* Handles a login with wrong password.
*
* @param player the player who attempted to log in
* @param auth the PlayerAuth object of the player
* @param ip the ip address of the player
*/
private void handleWrongPassword(Player player, PlayerAuth auth, String ip) {
logger.fine(player.getName() + " used the wrong password");
bukkitService.createAndCallEvent(isAsync -> new FailedLoginEvent(player, isAsync));
if (tempbanManager.shouldTempban(ip)) {
tempbanManager.tempbanPlayer(player);
} else if (service.getProperty(RestrictionSettings.KICK_ON_WRONG_PASSWORD)) {
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(
() -> player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.WRONG_PASSWORD)));
} else {
service.send(player, MessageKey.WRONG_PASSWORD);
// If the authentication fails check if Captcha is required and send a message to the player
if (loginCaptchaManager.isCaptchaRequired(player.getName())) {
limboService.muteMessageTask(player);
service.send(player, MessageKey.USAGE_CAPTCHA,
loginCaptchaManager.getCaptchaCodeOrGenerateNew(player.getName()));
} else if (emailService.hasAllInformation() && !Utils.isEmailEmpty(auth.getEmail())) {
service.send(player, MessageKey.FORGOT_PASSWORD_MESSAGE);
}
}
}
/**
* Sets the player to the logged in state.
*
* @param player the player to log in
* @param auth the associated PlayerAuth object
*/
public void performLogin(Player player, PlayerAuth auth) {
if (player.isOnline()) {
boolean isFirstLogin = (auth.getLastLogin() == null);
// Update auth to reflect this new login
String ip = PlayerUtils.getPlayerIp(player);
auth.setRealName(player.getName());
auth.setLastLogin(System.currentTimeMillis());
auth.setLastIp(ip);
dataSource.updateSession(auth);
// TODO: send an update when a messaging service will be implemented (SESSION)
// Successful login, so reset the captcha & temp ban count
String name = player.getName();
loginCaptchaManager.resetLoginFailureCount(name);
tempbanManager.resetCount(ip, name);
player.setNoDamageTicks(0);
service.send(player, MessageKey.LOGIN_SUCCESS);
// Other auths
List<String> auths = dataSource.getAllAuthsByIp(auth.getLastIp());
displayOtherAccounts(auths, player);
String email = auth.getEmail();
if (service.getProperty(EmailSettings.RECALL_PLAYERS) && Utils.isEmailEmpty(email)) {
service.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
logger.fine(player.getName() + " logged in " + ip);
// makes player loggedin
playerCache.updatePlayer(auth);
dataSource.setLogged(name);
sessionService.grantSession(name);
if (bungeeSender.isEnabled()) {
// As described at https://www.spigotmc.org/wiki/bukkit-bungee-plugin-messaging-channel/
// "Keep in mind that you can't send plugin messages directly after a player joins."
bukkitService.scheduleSyncDelayedTask(() ->
bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGIN), 5L);
}
// As the scheduling executes the Task most likely after the current
// 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.
syncProcessManager.processSyncPlayerLogin(player, isFirstLogin, auths);
} else {
logger.warning("Player '" + player.getName() + "' wasn't online during login process, aborted...");
}
}
/**
* Sends info about the other accounts owned by the given player to the configured users.
*
* @param auths the names of the accounts also owned by the player
* @param player the player
*/
private void displayOtherAccounts(List<String> auths, Player player) {
if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auths.size() <= 1) {
return;
}
List<String> formattedNames = new ArrayList<>(auths.size());
for (String currentName : auths) {
Player currentPlayer = bukkitService.getPlayerExact(currentName);
if (currentPlayer != null && currentPlayer.isOnline()) {
formattedNames.add(ChatColor.GREEN + currentPlayer.getName() + ChatColor.GRAY);
} else {
formattedNames.add(currentName);
}
}
String message = ChatColor.GRAY + String.join(", ", formattedNames) + ".";
logger.fine("The user " + player.getName() + " has " + auths.size() + " accounts:");
logger.fine(message);
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
if (onlinePlayer.getName().equalsIgnoreCase(player.getName())
&& service.hasPermission(onlinePlayer, PlayerPermission.SEE_OWN_ACCOUNTS)) {
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_SELF, Integer.toString(auths.size()));
onlinePlayer.sendMessage(message);
} else if (service.hasPermission(onlinePlayer, AdminPermission.SEE_OTHER_ACCOUNTS)) {
service.send(onlinePlayer, MessageKey.ACCOUNTS_OWNED_OTHER,
player.getName(), Integer.toString(auths.size()));
onlinePlayer.sendMessage(message);
}
}
}
/**
* Checks whether the maximum threshold of logged in player per IP address has been reached
* for the given player and IP address.
*
* @param player the player to process
* @param ip the associated ip address
* @return true if the threshold has been reached, false otherwise
*/
@VisibleForTesting
boolean hasReachedMaxLoggedInPlayersForIp(Player player, String ip) {
// Do not perform the check if player has multiple accounts permission or if IP is localhost
if (service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP) <= 0
|| service.hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS)
|| InternetProtocolUtils.isLoopbackAddress(ip)) {
return false;
}
// Count logged in players with same IP address
String name = player.getName();
int count = 0;
for (Player onlinePlayer : bukkitService.getOnlinePlayers()) {
if (ip.equalsIgnoreCase(PlayerUtils.getPlayerIp(onlinePlayer))
&& !onlinePlayer.getName().equals(name)
&& dataSource.isLogged(onlinePlayer.getName().toLowerCase(Locale.ROOT))) {
++count;
}
}
return count >= service.getProperty(RestrictionSettings.MAX_LOGIN_PER_IP);
}
}
@@ -1,112 +0,0 @@
package fr.xephi.authme.process.login;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.limbo.LimboPlayer;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.events.LoginEvent;
import fr.xephi.authme.events.RestoreInventoryEvent;
import fr.xephi.authme.permission.PermissionsManager;
import fr.xephi.authme.permission.PlayerStatePermission;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.JoinMessageService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import java.util.List;
import java.util.Locale;
import static fr.xephi.authme.settings.properties.RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN;
public class ProcessSyncPlayerLogin implements SynchronousProcess {
@Inject
private BungeeSender bungeeSender;
@Inject
private LimboService limboService;
@Inject
private BukkitService bukkitService;
@Inject
private TeleportationService teleportationService;
@Inject
private PlayerCache playerCache;
@Inject
private CommandManager commandManager;
@Inject
private CommonService commonService;
@Inject
private JoinMessageService joinMessageService;
@Inject
private PermissionsManager permissionsManager;
ProcessSyncPlayerLogin() {
}
private void restoreInventory(Player player) {
RestoreInventoryEvent event = new RestoreInventoryEvent(player);
bukkitService.callEvent(event);
if (!event.isCancelled()) {
player.updateInventory();
}
}
/**
* Performs operations in sync mode for a player that has just logged in.
*
* @param player the player that was logged in
* @param isFirstLogin true if this is the first time the player logged in
* @param authsWithSameIp registered names with the same IP address as the player's
*/
public void processPlayerLogin(Player player, boolean isFirstLogin, List<String> authsWithSameIp) {
final String name = player.getName().toLowerCase(Locale.ROOT);
final LimboPlayer limbo = limboService.getLimboPlayer(name);
// Limbo contains the State of the Player before /login
if (limbo != null) {
limboService.restoreData(player);
}
if (commonService.getProperty(PROTECT_INVENTORY_BEFORE_LOGIN)) {
restoreInventory(player);
}
final PlayerAuth auth = playerCache.getAuth(name);
teleportationService.teleportOnLogin(player, auth, limbo);
// We can now display the join message (if delayed)
joinMessageService.sendMessage(name);
if (commonService.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
player.removePotionEffect(PotionEffectType.BLINDNESS);
}
// The Login event now fires (as intended) after everything is processed
bukkitService.callEvent(new LoginEvent(player));
// Login is now finished; we can force all commands
if (isFirstLogin) {
commandManager.runCommandsOnFirstLogin(player, authsWithSameIp);
}
commandManager.runCommandsOnLogin(player, authsWithSameIp);
if (!permissionsManager.hasPermission(player, PlayerStatePermission.BYPASS_BUNGEE_SEND)) {
// Send Bungee stuff. The service will check if it is enabled or not.
bungeeSender.connectPlayerOnLogin(player);
}
}
}
@@ -1,77 +0,0 @@
package fr.xephi.authme.process.logout;
import fr.xephi.authme.data.VerificationCodeManager;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SessionService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Locale;
/**
* Async task when a player wants to log out.
*/
public class AsynchronousLogout implements AsynchronousProcess {
@Inject
private DataSource database;
@Inject
private CommonService service;
@Inject
private PlayerCache playerCache;
@Inject
private VerificationCodeManager codeManager;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private SessionService sessionService;
@Inject
private BungeeSender bungeeSender;
AsynchronousLogout() {
}
/**
* Handles a player's request to log out.
*
* @param player the player wanting to log out
*/
public void logout(Player player) {
String name = player.getName().toLowerCase(Locale.ROOT);
if (!playerCache.isAuthenticated(name)) {
service.send(player, MessageKey.NOT_LOGGED_IN);
return;
}
PlayerAuth auth = playerCache.getAuth(name);
database.updateSession(auth);
// TODO: send an update when a messaging service will be implemented (SESSION)
if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
auth.setQuitLocation(player.getLocation());
database.updateQuitLoc(auth);
// TODO: send an update when a messaging service will be implemented (QUITLOC)
}
playerCache.removePlayer(name);
codeManager.unverify(name);
database.setUnlogged(name);
sessionService.revokeSession(name);
bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGOUT);
syncProcessManager.processSyncPlayerLogout(player);
}
}
@@ -1,85 +0,0 @@
package fr.xephi.authme.process.logout;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.events.LogoutEvent;
import fr.xephi.authme.listener.protocollib.ProtocolLibService;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
public class ProcessSyncPlayerLogout implements SynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncPlayerLogout.class);
@Inject
private CommonService service;
@Inject
private BukkitService bukkitService;
@Inject
private ProtocolLibService protocolLibService;
@Inject
private LimboService limboService;
@Inject
private TeleportationService teleportationService;
@Inject
private CommandManager commandManager;
ProcessSyncPlayerLogout() {
}
/**
* Processes a player which has been logged out.
*
* @param player the player logging out
*/
public void processSyncLogout(Player player) {
if (service.getProperty(RestrictionSettings.PROTECT_INVENTORY_BEFORE_LOGIN)) {
protocolLibService.sendBlankInventoryPacket(player);
}
applyLogoutEffect(player);
commandManager.runCommandsOnLogout(player);
// Player is now logout... Time to fire event !
bukkitService.callEvent(new LogoutEvent(player));
service.send(player, MessageKey.LOGOUT_SUCCESS);
logger.info(player.getName() + " logged out");
}
private void applyLogoutEffect(Player player) {
// dismount player
player.leaveVehicle();
teleportationService.teleportOnJoin(player);
// Apply Blindness effect
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
}
// Set player's data to unauthenticated
limboService.createLimboPlayer(player, true);
}
}
@@ -1,111 +0,0 @@
package fr.xephi.authme.process.quit;
import fr.xephi.authme.AuthMe;
import fr.xephi.authme.data.VerificationCodeManager;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.SessionService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.SpawnLoader;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.Locale;
/**
* Async process called when a player quits the server.
*/
public class AsynchronousQuit implements AsynchronousProcess {
@Inject
private AuthMe plugin;
@Inject
private DataSource database;
@Inject
private CommonService service;
@Inject
private PlayerCache playerCache;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private SpawnLoader spawnLoader;
@Inject
private ValidationService validationService;
@Inject
private VerificationCodeManager codeManager;
@Inject
private SessionService sessionService;
AsynchronousQuit() {
}
/**
* Processes that the given player has quit the server.
*
* @param player the player who left
*/
public void processQuit(Player player) {
if (player == null || validationService.isUnrestricted(player.getName())) {
return;
}
String name = player.getName().toLowerCase(Locale.ROOT);
boolean wasLoggedIn = playerCache.isAuthenticated(name);
if (wasLoggedIn) {
if (service.getProperty(RestrictionSettings.SAVE_QUIT_LOCATION)) {
Location loc = spawnLoader.getPlayerLocationOrSpawn(player);
PlayerAuth auth = PlayerAuth.builder()
.name(name).location(loc)
.realName(player.getName()).build();
database.updateQuitLoc(auth);
}
String ip = PlayerUtils.getPlayerIp(player);
PlayerAuth auth = PlayerAuth.builder()
.name(name)
.realName(player.getName())
.lastIp(ip)
.lastLogin(System.currentTimeMillis())
.build();
database.updateSession(auth);
// TODO: send an update when a messaging service will be implemented (QUITLOC)
}
//always unauthenticate the player - use session only for auto logins on the same ip
playerCache.removePlayer(name);
codeManager.unverify(name);
//always update the database when the player quit the game (if sessions are disabled)
if (wasLoggedIn) {
database.setUnlogged(name);
if (!service.getProperty(PluginSettings.SESSIONS_ENABLED)) {
sessionService.revokeSession(name);
}
}
if (plugin.isEnabled()) {
syncProcessManager.processSyncPlayerQuit(player, wasLoggedIn);
}
// remove player from cache
database.invalidateCache(name);
}
}
@@ -1,34 +0,0 @@
package fr.xephi.authme.process.quit;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import org.bukkit.entity.Player;
import javax.inject.Inject;
public class ProcessSyncPlayerQuit implements SynchronousProcess {
@Inject
private LimboService limboService;
@Inject
private CommandManager commandManager;
/**
* Processes a player having quit.
*
* @param player the player that left
* @param wasLoggedIn true if the player was logged in when leaving, false otherwise
*/
public void processSyncQuit(Player player, boolean wasLoggedIn) {
if (wasLoggedIn) {
commandManager.runCommandsOnLogout(player);
} else {
limboService.restoreData(player);
player.saveData(); // #1238: Speed is sometimes not restored properly
}
player.leaveVehicle();
}
}
@@ -1,131 +0,0 @@
package fr.xephi.authme.process.register;
import ch.jalu.injector.factory.SingletonStore;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.AuthMeAsyncPreRegisterEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.process.register.executors.RegistrationExecutor;
import fr.xephi.authme.process.register.executors.RegistrationMethod;
import fr.xephi.authme.process.register.executors.RegistrationParameters;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import fr.xephi.authme.util.InternetProtocolUtils;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.util.List;
import java.util.Locale;
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
/**
* Asynchronous processing of a request for registration.
*/
public class AsyncRegister implements AsynchronousProcess {
@Inject
private DataSource database;
@Inject
private PlayerCache playerCache;
@Inject
private BukkitService bukkitService;
@Inject
private CommonService service;
@Inject
private SingletonStore<RegistrationExecutor> registrationExecutorFactory;
AsyncRegister() {
}
/**
* Performs the registration process for the given player.
*
* @param variant the registration method
* @param parameters the parameters
* @param <P> parameters type
*/
public <P extends RegistrationParameters> void register(RegistrationMethod<P> variant, P parameters) {
if (preRegisterCheck(variant, parameters.getPlayer())) {
RegistrationExecutor<P> executor = registrationExecutorFactory.getSingleton(variant.getExecutorClass());
if (executor.isRegistrationAdmitted(parameters)) {
executeRegistration(parameters, executor);
}
}
}
/**
* Checks if the player is able to register, in that case the {@link AuthMeAsyncPreRegisterEvent} is invoked.
*
* @param variant the registration type variant.
* @param player the player which is trying to register.
*
* @return true if the checks are successful and the event hasn't marked the action as denied, false otherwise.
*/
private boolean preRegisterCheck(RegistrationMethod<?> variant, Player player) {
String name = player.getName().toLowerCase(Locale.ROOT);
if (playerCache.isAuthenticated(name)) {
service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR);
return false;
} else if (!service.getProperty(RegistrationSettings.IS_ENABLED)) {
service.send(player, MessageKey.REGISTRATION_DISABLED);
return false;
} else if (database.isAuthAvailable(name)) {
service.send(player, MessageKey.NAME_ALREADY_REGISTERED);
return false;
}
AuthMeAsyncPreRegisterEvent event = bukkitService.createAndCallEvent(
isAsync -> new AuthMeAsyncPreRegisterEvent(player, isAsync));
if (!event.canRegister()) {
return false;
}
return variant == RegistrationMethod.API_REGISTRATION || isPlayerIpAllowedToRegister(player);
}
/**
* Executes the registration.
*
* @param parameters the registration parameters
* @param executor the executor to perform the registration process with
* @param <P> registration params type
*/
private <P extends RegistrationParameters>
void executeRegistration(P parameters, RegistrationExecutor<P> executor) {
PlayerAuth auth = executor.buildPlayerAuth(parameters);
if (database.saveAuth(auth)) {
executor.executePostPersistAction(parameters);
} else {
service.send(parameters.getPlayer(), MessageKey.ERROR);
}
}
/**
* Checks whether the registration threshold has been exceeded for the given player's IP address.
*
* @param player the player to check
*
* @return true if registration may take place, false otherwise (IP check failed)
*/
private boolean isPlayerIpAllowedToRegister(Player player) {
int maxRegPerIp = service.getProperty(RestrictionSettings.MAX_REGISTRATION_PER_IP);
String ip = PlayerUtils.getPlayerIp(player);
if (maxRegPerIp > 0
&& !InternetProtocolUtils.isLoopbackAddress(ip)
&& !service.hasPermission(player, ALLOW_MULTIPLE_ACCOUNTS)) {
List<String> otherAccounts = database.getAllAuthsByIp(ip);
if (otherAccounts.size() >= maxRegPerIp) {
service.send(player, MessageKey.MAX_REGISTER_EXCEEDED, Integer.toString(maxRegPerIp),
Integer.toString(otherAccounts.size()), String.join(", ", otherAccounts));
return false;
}
}
return true;
}
}
@@ -1,48 +0,0 @@
package fr.xephi.authme.process.register;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.events.RegisterEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Performs synchronous tasks after a successful {@link RegistrationType#EMAIL email registration}.
*/
public class ProcessSyncEmailRegister implements SynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncEmailRegister.class);
@Inject
private BukkitService bukkitService;
@Inject
private CommonService service;
@Inject
private LimboService limboService;
ProcessSyncEmailRegister() {
}
/**
* Performs sync tasks for a player which has just registered by email.
*
* @param player the recently registered player
*/
public void processEmailRegister(Player player) {
service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED);
limboService.replaceTasksAfterRegistration(player);
bukkitService.callEvent(new RegisterEvent(player));
logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
}
}
@@ -1,91 +0,0 @@
package fr.xephi.authme.process.register;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.events.RegisterEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.SynchronousProcess;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Performs synchronous tasks after a successful {@link RegistrationType#PASSWORD password registration}.
*/
public class ProcessSyncPasswordRegister implements SynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(ProcessSyncPasswordRegister.class);
@Inject
private BungeeSender bungeeSender;
@Inject
private CommonService service;
@Inject
private LimboService limboService;
@Inject
private CommandManager commandManager;
@Inject
private BukkitService bukkitService;
ProcessSyncPasswordRegister() {
}
/**
* Request that the player log in.
*
* @param player the player
*/
private void requestLogin(Player player) {
limboService.replaceTasksAfterRegistration(player);
if (player.isInsideVehicle() && player.getVehicle() != null) {
player.getVehicle().eject();
}
}
/**
* Processes a player having registered with a password.
*
* @param player the newly registered player
*/
public void processPasswordRegister(Player player) {
service.send(player, MessageKey.REGISTER_SUCCESS);
if (!service.getProperty(EmailSettings.MAIL_ACCOUNT).isEmpty()) {
service.send(player, MessageKey.ADD_EMAIL_MESSAGE);
}
bukkitService.callEvent(new RegisterEvent(player));
logger.fine(player.getName() + " registered " + PlayerUtils.getPlayerIp(player));
// Kick Player after Registration is enabled, kick the player
if (service.getProperty(RegistrationSettings.FORCE_KICK_AFTER_REGISTER)) {
player.kickPlayer(service.retrieveSingleMessage(player, MessageKey.REGISTER_SUCCESS));
return;
}
// Register is now finished; we can force all commands
commandManager.runCommandsOnRegister(player);
// Request login after registration
if (service.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER)) {
requestLogin(player);
return;
}
// Send Bungee stuff. The service will check if it is enabled or not.
bungeeSender.connectPlayerOnLogin(player);
}
}
@@ -1,20 +0,0 @@
package fr.xephi.authme.process.register;
/**
* Type of the second argument of the {@code /register} command.
*/
public enum RegisterSecondaryArgument {
/** No second argument. */
NONE,
/** Confirmation of the first argument. */
CONFIRMATION,
/** For password registration, mandatory secondary argument is email. */
EMAIL_MANDATORY,
/** For password registration, optional secondary argument is email. */
EMAIL_OPTIONAL
}
@@ -1,19 +0,0 @@
package fr.xephi.authme.process.register;
/**
* Registration type.
*/
public enum RegistrationType {
/**
* Password registration: account is registered with a password supplied by the player.
*/
PASSWORD,
/**
* Email registration: account is registered with an email supplied by the player. A password
* is generated and sent to the email address.
*/
EMAIL
}
@@ -1,99 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.process.login.AsynchronousLogin;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.ValidationService;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import org.bukkit.entity.Player;
import javax.inject.Inject;
/**
* Registration executor for registration methods where the password
* is supplied by the user.
*
* @param <P> the parameters type
*/
abstract class AbstractPasswordRegisterExecutor<P extends AbstractPasswordRegisterParams>
implements RegistrationExecutor<P> {
/**
* Number of ticks to wait before running the login action when it is run synchronously.
* A small delay is necessary or the database won't return the newly saved PlayerAuth object
* and the login process thinks the user is not registered.
*/
private static final int SYNC_LOGIN_DELAY = 5;
@Inject
private ValidationService validationService;
@Inject
private CommonService commonService;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private BukkitService bukkitService;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private AsynchronousLogin asynchronousLogin;
@Override
public boolean isRegistrationAdmitted(P params) {
ValidationService.ValidationResult passwordValidation = validationService.validatePassword(
params.getPassword(), params.getPlayer().getName());
if (passwordValidation.hasError()) {
commonService.send(params.getPlayer(), passwordValidation.getMessageKey(), passwordValidation.getArgs());
return false;
}
return true;
}
@Override
public PlayerAuth buildPlayerAuth(P params) {
HashedPassword hashedPassword = passwordSecurity.computeHash(params.getPassword(), params.getPlayerName());
params.setHashedPassword(hashedPassword);
return createPlayerAuthObject(params);
}
/**
* Creates the PlayerAuth object to store into the database, based on the registration parameters.
*
* @param params the parameters
* @return the PlayerAuth representing the new account to register
*/
protected abstract PlayerAuth createPlayerAuthObject(P params);
/**
* Returns whether the player should be automatically logged in after registration.
*
* @param params the registration parameters
* @return true if the player should be logged in, false otherwise
*/
protected boolean performLoginAfterRegister(P params) {
return !commonService.getProperty(RegistrationSettings.FORCE_LOGIN_AFTER_REGISTER);
}
@Override
public void executePostPersistAction(P params) {
final Player player = params.getPlayer();
if (performLoginAfterRegister(params)) {
if (commonService.getProperty(PluginSettings.USE_ASYNC_TASKS)) {
bukkitService.runTaskAsynchronously(() -> asynchronousLogin.forceLogin(player));
} else {
bukkitService.scheduleSyncDelayedTask(() -> asynchronousLogin.forceLogin(player), SYNC_LOGIN_DELAY);
}
}
syncProcessManager.processSyncPasswordRegister(player);
}
}
@@ -1,48 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.security.crypts.HashedPassword;
import org.bukkit.entity.Player;
/**
* Common params type for implementors of {@link AbstractPasswordRegisterExecutor}.
* Password must be supplied on creation and cannot be changed later on. The {@link HashedPassword}
* is stored on the params object for later use.
*/
public abstract class AbstractPasswordRegisterParams extends RegistrationParameters {
private final String password;
private HashedPassword hashedPassword;
/**
* Constructor.
*
* @param player the player to register
* @param password the password to use
*/
public AbstractPasswordRegisterParams(Player player, String password) {
super(player);
this.password = password;
}
/**
* Constructor with no defined password. Use for registration methods which
* have no implicit password (like two factor authentication).
*
* @param player the player to register
*/
public AbstractPasswordRegisterParams(Player player) {
this(player, null);
}
public String getPassword() {
return password;
}
void setHashedPassword(HashedPassword hashedPassword) {
this.hashedPassword = hashedPassword;
}
HashedPassword getHashedPassword() {
return hashedPassword;
}
}
@@ -1,20 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
/**
* Executor for password registration via API call.
*/
class ApiPasswordRegisterExecutor extends AbstractPasswordRegisterExecutor<ApiPasswordRegisterParams> {
@Override
protected PlayerAuth createPlayerAuthObject(ApiPasswordRegisterParams params) {
return PlayerAuthBuilderHelper
.createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null);
}
@Override
protected boolean performLoginAfterRegister(ApiPasswordRegisterParams params) {
return params.getLoginAfterRegister();
}
}
@@ -1,35 +0,0 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
/**
* Parameters for {@link ApiPasswordRegisterExecutor}.
*/
public class ApiPasswordRegisterParams extends PasswordRegisterParams {
private final boolean loginAfterRegister;
protected ApiPasswordRegisterParams(Player player, String password, boolean loginAfterRegister) {
super(player, password, null);
this.loginAfterRegister = loginAfterRegister;
}
/**
* Creates a parameters object.
*
* @param player the player to register
* @param password the password to register with
* @param loginAfterRegister whether the player should be logged in after registration
* @return params object with the given data
*/
public static ApiPasswordRegisterParams of(Player player, String password, boolean loginAfterRegister) {
return new ApiPasswordRegisterParams(player, password, loginAfterRegister);
}
/**
* @return true if the player should be logged in after being registered, false otherwise
*/
public boolean getLoginAfterRegister() {
return loginAfterRegister;
}
}
@@ -1,81 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.mail.EmailService;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.process.SyncProcessManager;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.util.PlayerUtils;
import fr.xephi.authme.util.RandomStringUtils;
import org.bukkit.entity.Player;
import javax.inject.Inject;
import java.text.SimpleDateFormat;
import java.util.Date;
import static fr.xephi.authme.permission.PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS;
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
import static fr.xephi.authme.settings.properties.EmailSettings.RECOVERY_PASSWORD_LENGTH;
/**
* Executor for email registration: the player only provides his email address,
* to which a generated password is sent.
*/
class EmailRegisterExecutor implements RegistrationExecutor<EmailRegisterParams> {
@Inject
private DataSource dataSource;
@Inject
private CommonService commonService;
@Inject
private EmailService emailService;
@Inject
private SyncProcessManager syncProcessManager;
@Inject
private PasswordSecurity passwordSecurity;
@Override
public boolean isRegistrationAdmitted(EmailRegisterParams params) {
final int maxRegPerEmail = commonService.getProperty(EmailSettings.MAX_REG_PER_EMAIL);
if (maxRegPerEmail > 0 && !commonService.hasPermission(params.getPlayer(), ALLOW_MULTIPLE_ACCOUNTS)) {
int otherAccounts = dataSource.countAuthsByEmail(params.getEmail());
if (otherAccounts >= maxRegPerEmail) {
commonService.send(params.getPlayer(), MessageKey.MAX_REGISTER_EXCEEDED,
Integer.toString(maxRegPerEmail), Integer.toString(otherAccounts), "@");
return false;
}
}
return true;
}
@Override
public PlayerAuth buildPlayerAuth(EmailRegisterParams params) {
String password = RandomStringUtils.generate(commonService.getProperty(RECOVERY_PASSWORD_LENGTH));
HashedPassword hashedPassword = passwordSecurity.computeHash(password, params.getPlayer().getName());
params.setPassword(password);
return createPlayerAuth(params.getPlayer(), hashedPassword, params.getEmail());
}
@Override
public void executePostPersistAction(EmailRegisterParams params) {
Player player = params.getPlayer();
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy'年'MM'月'dd'日' HH:mm:ss");
Date date = new Date(System.currentTimeMillis());
boolean couldSendMail = emailService.sendNewPasswordMail(
player.getName(), params.getEmail(), params.getPassword(), PlayerUtils.getPlayerIp(player), dateFormat.format(date));
if (couldSendMail) {
syncProcessManager.processSyncEmailRegister(player);
} else {
commonService.send(player, MessageKey.EMAIL_SEND_FAILURE);
}
}
}
@@ -1,43 +0,0 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
/**
* Parameters for email registration.
*/
public class EmailRegisterParams extends RegistrationParameters {
private final String email;
private String password;
protected EmailRegisterParams(Player player, String email) {
super(player);
this.email = email;
}
/**
* Creates a params object for email registration.
*
* @param player the player to register
* @param email the player's email
* @return params object with the given data
*/
public static EmailRegisterParams of(Player player, String email) {
return new EmailRegisterParams(player, email);
}
public String getEmail() {
return email;
}
void setPassword(String password) {
this.password = password;
}
/**
* @return the password generated for the player
*/
String getPassword() {
return password;
}
}
@@ -1,17 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
/**
* Registration executor for password registration.
*/
class PasswordRegisterExecutor extends AbstractPasswordRegisterExecutor<PasswordRegisterParams> {
@Override
public PlayerAuth createPlayerAuthObject(PasswordRegisterParams params) {
return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), params.getEmail());
}
}
@@ -1,32 +0,0 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
/**
* Parameters for registration with a given password, and optionally an email address.
*/
public class PasswordRegisterParams extends AbstractPasswordRegisterParams {
private final String email;
protected PasswordRegisterParams(Player player, String password, String email) {
super(player, password);
this.email = email;
}
/**
* Creates a params object.
*
* @param player the player to register
* @param password the password to register with
* @param email the email of the player (may be null)
* @return params object with the given data
*/
public static PasswordRegisterParams of(Player player, String password, String email) {
return new PasswordRegisterParams(player, password, email);
}
public String getEmail() {
return email;
}
}
@@ -1,37 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.security.crypts.HashedPassword;
import fr.xephi.authme.util.PlayerUtils;
import org.bukkit.entity.Player;
import java.util.Locale;
/**
* Helper for constructing PlayerAuth objects.
*/
final class PlayerAuthBuilderHelper {
private PlayerAuthBuilderHelper() {
}
/**
* Creates a {@link PlayerAuth} object with the given data.
*
* @param player the player to create a PlayerAuth for
* @param hashedPassword the hashed password
* @param email the email address (nullable)
* @return the generated PlayerAuth object
*/
static PlayerAuth createPlayerAuth(Player player, HashedPassword hashedPassword, String email) {
return PlayerAuth.builder()
.name(player.getName().toLowerCase(Locale.ROOT))
.realName(player.getName())
.password(hashedPassword)
.email(email)
.registrationIp(PlayerUtils.getPlayerIp(player))
.registrationDate(System.currentTimeMillis())
.uuid(player.getUniqueId())
.build();
}
}
@@ -1,39 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
/**
* Performs the registration action.
*
* @param <P> the registration parameters type
*/
public interface RegistrationExecutor<P extends RegistrationParameters> {
/**
* Returns whether the registration may take place. Use this method to execute
* checks specific to the registration method.
* <p>
* If this method returns {@code false}, it is expected that the executor inform
* the player about the error within this method call.
*
* @param params the parameters for the registration
* @return true if registration may be performed, false otherwise
*/
boolean isRegistrationAdmitted(P params);
/**
* Constructs the PlayerAuth object to persist into the database.
*
* @param params the parameters for the registration
* @return the player auth to register in the data source
*/
PlayerAuth buildPlayerAuth(P params);
/**
* Follow-up method called after the player auth could be added into the database.
*
* @param params the parameters for the registration
*/
void executePostPersistAction(P params);
}
@@ -1,53 +0,0 @@
package fr.xephi.authme.process.register.executors;
/**
* Methods with which a player can be registered.
* <p>
* These constants each define a different way of registering a player and define the
* {@link RegistrationParameters parameters} and {@link RegistrationExecutor executor}
* classes which perform this registration method. This is essentially a <i>typed enum</i>
* as passing a constant of this class along with a parameters object to a method can
* be restricted to the correct parameters type.
*
* @param <P> the registration parameters type the method uses
*/
public final class RegistrationMethod<P extends RegistrationParameters> {
/**
* Password registration.
*/
public static final RegistrationMethod<PasswordRegisterParams> PASSWORD_REGISTRATION =
new RegistrationMethod<>(PasswordRegisterExecutor.class);
/**
* Registration with two-factor authentication as login means.
*/
public static final RegistrationMethod<TwoFactorRegisterParams> TWO_FACTOR_REGISTRATION =
new RegistrationMethod<>(TwoFactorRegisterExecutor.class);
/**
* Email registration: an email address is provided, to which a generated password is sent.
*/
public static final RegistrationMethod<EmailRegisterParams> EMAIL_REGISTRATION =
new RegistrationMethod<>(EmailRegisterExecutor.class);
/**
* API registration: player and password are provided via an API method.
*/
public static final RegistrationMethod<ApiPasswordRegisterParams> API_REGISTRATION =
new RegistrationMethod<>(ApiPasswordRegisterExecutor.class);
private final Class<? extends RegistrationExecutor<P>> executorClass;
private RegistrationMethod(Class<? extends RegistrationExecutor<P>> executorClass) {
this.executorClass = executorClass;
}
/**
* @return the executor class to perform the registration method
*/
public Class<? extends RegistrationExecutor<P>> getExecutorClass() {
return executorClass;
}
}
@@ -1,28 +0,0 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
/**
* Parent of all registration parameters.
*/
public abstract class RegistrationParameters {
private final Player player;
/**
* Constructor.
*
* @param player the player to perform the registration for
*/
public RegistrationParameters(Player player) {
this.player = player;
}
public Player getPlayer() {
return player;
}
public String getPlayerName() {
return player.getName();
}
}
@@ -1,43 +0,0 @@
package fr.xephi.authme.process.register.executors;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.security.crypts.TwoFactor;
import fr.xephi.authme.service.CommonService;
import org.bukkit.Bukkit;
import javax.inject.Inject;
import static fr.xephi.authme.process.register.executors.PlayerAuthBuilderHelper.createPlayerAuth;
/**
* Executor for two-factor registration.
*/
class TwoFactorRegisterExecutor extends AbstractPasswordRegisterExecutor<TwoFactorRegisterParams> {
@Inject
private CommonService commonService;
@Override
public boolean isRegistrationAdmitted(TwoFactorRegisterParams params) {
// nothing to check
return true;
}
@Override
protected PlayerAuth createPlayerAuthObject(TwoFactorRegisterParams params) {
return createPlayerAuth(params.getPlayer(), params.getHashedPassword(), null);
}
@Override
public void executePostPersistAction(TwoFactorRegisterParams params) {
super.executePostPersistAction(params);
// Note ljacqu 20170317: This two-factor registration type is only invoked when the password hash is configured
// to two-factor authentication. Therefore, the hashed password is the result of the TwoFactor EncryptionMethod
// implementation (contains the TOTP secret).
String hash = params.getHashedPassword().getHash();
String qrCodeUrl = TwoFactor.getQrBarcodeUrl(params.getPlayerName(), Bukkit.getIp(), hash);
commonService.send(params.getPlayer(), MessageKey.TWO_FACTOR_CREATE, hash, qrCodeUrl);
}
}
@@ -1,23 +0,0 @@
package fr.xephi.authme.process.register.executors;
import org.bukkit.entity.Player;
/**
* Parameters for registration with two-factor authentication.
*/
public class TwoFactorRegisterParams extends AbstractPasswordRegisterParams {
protected TwoFactorRegisterParams(Player player) {
super(player);
}
/**
* Creates a parameters object.
*
* @param player the player to register
* @return params object with the given player
*/
public static TwoFactorRegisterParams of(Player player) {
return new TwoFactorRegisterParams(player);
}
}
@@ -1,151 +0,0 @@
package fr.xephi.authme.process.unregister;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.data.auth.PlayerAuth;
import fr.xephi.authme.data.auth.PlayerCache;
import fr.xephi.authme.data.limbo.LimboService;
import fr.xephi.authme.datasource.DataSource;
import fr.xephi.authme.events.UnregisterByAdminEvent;
import fr.xephi.authme.events.UnregisterByPlayerEvent;
import fr.xephi.authme.message.MessageKey;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.process.AsynchronousProcess;
import fr.xephi.authme.security.PasswordSecurity;
import fr.xephi.authme.service.BukkitService;
import fr.xephi.authme.service.CommonService;
import fr.xephi.authme.service.TeleportationService;
import fr.xephi.authme.service.bungeecord.BungeeSender;
import fr.xephi.authme.service.bungeecord.MessageType;
import fr.xephi.authme.settings.commandconfig.CommandManager;
import fr.xephi.authme.settings.properties.RegistrationSettings;
import fr.xephi.authme.settings.properties.RestrictionSettings;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.potion.PotionEffect;
import org.bukkit.potion.PotionEffectType;
import javax.inject.Inject;
import static fr.xephi.authme.service.BukkitService.TICKS_PER_SECOND;
public class AsynchronousUnregister implements AsynchronousProcess {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(AsynchronousUnregister.class);
@Inject
private DataSource dataSource;
@Inject
private CommonService service;
@Inject
private PasswordSecurity passwordSecurity;
@Inject
private PlayerCache playerCache;
@Inject
private BukkitService bukkitService;
@Inject
private LimboService limboService;
@Inject
private TeleportationService teleportationService;
@Inject
private CommandManager commandManager;
@Inject
private BungeeSender bungeeSender;
AsynchronousUnregister() {
}
/**
* Processes a player's request to unregister himself. Unregisters the player after
* successful password check.
*
* @param player the player
* @param password the input password to check before unregister
*/
public void unregister(Player player, String password) {
String name = player.getName();
PlayerAuth cachedAuth = playerCache.getAuth(name);
if (passwordSecurity.comparePassword(password, cachedAuth.getPassword(), name)) {
if (dataSource.removeAuth(name)) {
performPostUnregisterActions(name, player);
logger.info(name + " unregistered himself");
bukkitService.createAndCallEvent(isAsync -> new UnregisterByPlayerEvent(player, isAsync));
} else {
service.send(player, MessageKey.ERROR);
}
} else {
service.send(player, MessageKey.WRONG_PASSWORD);
}
}
/**
* Unregisters a player as administrator or console.
*
* @param initiator the initiator of this process (nullable)
* @param name the name of the player
* @param player the according Player object (nullable)
*/
// We need to have the name and the player separate because Player might be null in this case:
// we might have some player in the database that has never been online on the server
public void adminUnregister(CommandSender initiator, String name, Player player) {
if (dataSource.removeAuth(name)) {
performPostUnregisterActions(name, player);
bukkitService.createAndCallEvent(isAsync -> new UnregisterByAdminEvent(player, name, isAsync, initiator));
if (initiator == null) {
logger.info(name + " was unregistered");
} else {
logger.info(name + " was unregistered by " + initiator.getName());
service.send(initiator, MessageKey.UNREGISTERED_SUCCESS);
}
} else if (initiator != null) {
service.send(initiator, MessageKey.ERROR);
}
}
/**
* Process the post unregister actions. Makes the user status consistent.
*
* @param name the name of the player
* @param player the according Player object (nullable)
*/
private void performPostUnregisterActions(String name, Player player) {
if (player != null && playerCache.isAuthenticated(name)) {
bungeeSender.sendAuthMeBungeecordMessage(player, MessageType.LOGOUT);
}
playerCache.removePlayer(name);
// TODO: send an update when a messaging service will be implemented (UNREGISTER)
if (player == null || !player.isOnline()) {
return;
}
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() ->
commandManager.runCommandsOnUnregister(player));
if (service.getProperty(RegistrationSettings.FORCE)) {
teleportationService.teleportOnJoin(player);
bukkitService.scheduleSyncTaskFromOptionallyAsyncTask(() -> {
limboService.createLimboPlayer(player, false);
applyBlindEffect(player);
});
}
service.send(player, MessageKey.UNREGISTERED_SUCCESS);
}
private void applyBlindEffect(Player player) {
if (service.getProperty(RegistrationSettings.APPLY_BLIND_EFFECT)) {
int timeout = service.getProperty(RestrictionSettings.TIMEOUT) * TICKS_PER_SECOND;
player.addPotionEffect(new PotionEffect(PotionEffectType.BLINDNESS, timeout, 2));
}
}
}