package fr.xephi.authme.process.login; import fr.xephi.authme.AuthMe; import fr.xephi.authme.ConsoleLogger; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.cache.auth.PlayerCache; import fr.xephi.authme.cache.limbo.LimboCache; import fr.xephi.authme.cache.limbo.LimboPlayer; import fr.xephi.authme.datasource.DataSource; import fr.xephi.authme.events.AuthMeAsyncPreLoginEvent; import fr.xephi.authme.output.MessageKey; import fr.xephi.authme.permission.AdminPermission; import fr.xephi.authme.permission.PlayerPermission; import fr.xephi.authme.permission.PlayerStatePermission; import fr.xephi.authme.process.Process; import fr.xephi.authme.process.ProcessService; import fr.xephi.authme.security.RandomString; import fr.xephi.authme.settings.Settings; import fr.xephi.authme.settings.properties.DatabaseSettings; import fr.xephi.authme.settings.properties.EmailSettings; import fr.xephi.authme.settings.properties.RegistrationSettings; import fr.xephi.authme.settings.properties.RestrictionSettings; import fr.xephi.authme.settings.properties.SecuritySettings; 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; import org.bukkit.scheduler.BukkitTask; import java.util.List; /** */ public class AsynchronousLogin implements Process { private final Player player; private final String name; private final String realName; private final String password; private final boolean forceLogin; private final AuthMe plugin; private final DataSource database; private final String ip; private final ProcessService service; public AsynchronousLogin(Player player, String password, boolean forceLogin, AuthMe plugin, DataSource data, ProcessService service) { this.player = player; this.name = player.getName().toLowerCase(); this.password = password; this.realName = player.getName(); this.forceLogin = forceLogin; this.plugin = plugin; this.database = data; this.ip = Utils.getPlayerIp(player); this.service = service; } private boolean needsCaptcha() { if (service.getProperty(SecuritySettings.USE_CAPTCHA)) { if (!plugin.captcha.containsKey(name)) { plugin.captcha.putIfAbsent(name, 1); } else { int i = plugin.captcha.get(name) + 1; plugin.captcha.remove(name); plugin.captcha.putIfAbsent(name, i); } if (plugin.captcha.containsKey(name) && plugin.captcha.get(name) > Settings.maxLoginTry) { plugin.cap.putIfAbsent(name, RandomString.generate(Settings.captchaLength)); service.send(player, MessageKey.USAGE_CAPTCHA, plugin.cap.get(name)); return true; } } return false; } /** * Checks the precondition for authentication (like user known) and returns * the playerAuth-State * * @return PlayerAuth */ private PlayerAuth preAuth() { if (PlayerCache.getInstance().isAuthenticated(name)) { service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); return null; } PlayerAuth pAuth = database.getAuth(name); if (pAuth == null) { service.send(player, MessageKey.USER_NOT_REGISTERED); LimboPlayer limboPlayer = LimboCache.getInstance().getLimboPlayer(name); if (limboPlayer != null) { limboPlayer.getMessageTask().cancel(); String[] msg = service.getProperty(RegistrationSettings.USE_EMAIL_REGISTRATION) ? service.retrieveMessage(MessageKey.REGISTER_EMAIL_MESSAGE) : service.retrieveMessage(MessageKey.REGISTER_MESSAGE); BukkitTask messageTask = service.runTask(new MessageTask(service.getBukkitService(), name, msg, service.getProperty(RegistrationSettings.MESSAGE_INTERVAL))); limboPlayer.setMessageTask(messageTask); } return null; } if (!service.getProperty(DatabaseSettings.MYSQL_COL_GROUP).isEmpty() && pAuth.getGroupId() == Settings.getNonActivatedGroup) { service.send(player, MessageKey.ACCOUNT_NOT_ACTIVATED); return null; } if (Settings.getMaxLoginPerIp > 0 && !plugin.getPermissionsManager().hasPermission(player, PlayerStatePermission.ALLOW_MULTIPLE_ACCOUNTS) && !ip.equalsIgnoreCase("127.0.0.1") && !ip.equalsIgnoreCase("localhost")) { if (plugin.isLoggedIp(name, ip)) { service.send(player, MessageKey.ALREADY_LOGGED_IN_ERROR); return null; } } AuthMeAsyncPreLoginEvent event = new AuthMeAsyncPreLoginEvent(player); Bukkit.getServer().getPluginManager().callEvent(event); if (!event.canLogin()) { return null; } return pAuth; } @Override public void run() { PlayerAuth pAuth = preAuth(); if (pAuth == null || needsCaptcha()) { return; } if ("127.0.0.1".equals(pAuth.getIp()) && !pAuth.getIp().equals(ip)) { pAuth.setIp(ip); database.updateIp(pAuth.getNickname(), ip); } String email = pAuth.getEmail(); boolean passwordVerified = forceLogin || plugin.getPasswordSecurity() .comparePassword(password, pAuth.getPassword(), realName); if (passwordVerified && player.isOnline()) { PlayerAuth auth = PlayerAuth.builder() .name(name) .realName(realName) .ip(ip) .email(email) .password(pAuth.getPassword()) .build(); database.updateSession(auth); if (service.getProperty(SecuritySettings.USE_CAPTCHA)) { if (plugin.captcha.containsKey(name)) { plugin.captcha.remove(name); } if (plugin.cap.containsKey(name)) { plugin.cap.remove(name); } } player.setNoDamageTicks(0); if (!forceLogin) service.send(player, MessageKey.LOGIN_SUCCESS); displayOtherAccounts(auth); if (service.getProperty(EmailSettings.RECALL_PLAYERS) && (StringUtils.isEmpty(email) || "your@email.com".equalsIgnoreCase(email))) { service.send(player, MessageKey.ADD_EMAIL_MESSAGE); } if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info(realName + " logged in!"); } // makes player isLoggedin via API PlayerCache.getInstance().addPlayer(auth); database.setLogged(name); // 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. ProcessSyncPlayerLogin syncPlayerLogin = new ProcessSyncPlayerLogin(player, plugin, database, service); if (syncPlayerLogin.getLimbo() != null) { if (syncPlayerLogin.getLimbo().getTimeoutTask() != null) { syncPlayerLogin.getLimbo().getTimeoutTask().cancel(); } if (syncPlayerLogin.getLimbo().getMessageTask() != null) { syncPlayerLogin.getLimbo().getMessageTask().cancel(); } } Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, syncPlayerLogin); } else if (player.isOnline()) { if (!service.getProperty(SecuritySettings.REMOVE_SPAM_FROM_CONSOLE)) { ConsoleLogger.info(realName + " used the wrong password"); } if (service.getProperty(RestrictionSettings.KICK_ON_WRONG_PASSWORD)) { service.scheduleSyncDelayedTask(new Runnable() { @Override public void run() { player.kickPlayer(service.retrieveSingleMessage(MessageKey.WRONG_PASSWORD)); } }); } else { service.send(player, MessageKey.WRONG_PASSWORD); } } else { ConsoleLogger.showError("Player " + name + " wasn't online during login process, aborted... "); } } private void displayOtherAccounts(PlayerAuth auth) { if (!service.getProperty(RestrictionSettings.DISPLAY_OTHER_ACCOUNTS) || auth == null) { return; } List auths = this.database.getAllAuthsByIp(auth.getIp()); if (auths.size() < 2) { return; } String message = "[AuthMe] " + StringUtils.join(", ", auths) + "."; for (Player player : service.getOnlinePlayers()) { if (plugin.getPermissionsManager().hasPermission(player, AdminPermission.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); } } } }