diff --git a/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java b/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java index 86697191..f37c2c65 100644 --- a/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java +++ b/src/main/java/fr/xephi/authme/listener/AuthMeServerStop.java @@ -9,15 +9,16 @@ public class AuthMeServerStop extends Thread { private AuthMe plugin; - public AuthMeServerStop(AuthMe plugin) - { + public AuthMeServerStop(AuthMe plugin) { this.plugin = plugin; } public void run() { // TODO: add a MessageKey - if (Settings.kickPlayersBeforeStoping) - for (Player p : plugin.getServer().getOnlinePlayers()) - p.kickPlayer("Server is restarting"); + if (Settings.kickPlayersBeforeStopping) { + for (Player p : plugin.getServer().getOnlinePlayers()) { + p.kickPlayer("Server is restarting"); + } + } } } diff --git a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java index 3433bd14..b2903f0e 100644 --- a/src/main/java/fr/xephi/authme/mail/SendMailSSL.java +++ b/src/main/java/fr/xephi/authme/mail/SendMailSSL.java @@ -6,6 +6,7 @@ import fr.xephi.authme.ImageGenerator; import fr.xephi.authme.cache.auth.PlayerAuth; import fr.xephi.authme.settings.Settings; +import fr.xephi.authme.util.StringUtils; import org.apache.commons.mail.DefaultAuthenticator; import org.apache.commons.mail.EmailException; import org.apache.commons.mail.HtmlEmail; @@ -15,130 +16,153 @@ import javax.activation.DataSource; import javax.activation.FileDataSource; import javax.imageio.ImageIO; import java.io.File; +import java.io.IOException; import java.security.Security; +import java.util.Properties; /** * @author Xephi59 - * @version $Revision: 1.0 $ */ public class SendMailSSL { - public final AuthMe plugin; + private final AuthMe plugin; - /** - * Constructor for SendMailSSL. - * - * @param plugin AuthMe - */ public SendMailSSL(AuthMe plugin) { this.plugin = plugin; } - /** - * Method main. - * - * @param auth PlayerAuth - * @param newPass String - */ public void main(final PlayerAuth auth, final String newPass) { - String senderName; - - if (Settings.getmailSenderName == null || Settings.getmailSenderName.isEmpty()) { - senderName = Settings.getmailAccount; - } else { - senderName = Settings.getmailSenderName; - } - - final String sender = senderName; final int port = Settings.getMailPort; - final String acc = Settings.getmailAccount; - final String subject = Settings.getMailSubject; - final String smtp = Settings.getmailSMTP; - final String password = Settings.getmailPassword; - final String mailText = Settings.getMailText.replace("", auth.getNickname()).replace("", plugin.getServer().getServerName()).replace("", newPass); - final String mail = auth.getEmail(); + final String mailText = replaceMailTags(Settings.getMailText, plugin, auth, newPass); Bukkit.getScheduler().runTaskAsynchronously(plugin, new Runnable() { @Override public void run() { + Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); + HtmlEmail email; try { - Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader()); - HtmlEmail email = new HtmlEmail(); - email.setSmtpPort(port); - email.setHostName(smtp); - email.addTo(mail); - email.setFrom(acc, sender); - email.setSubject(subject); - if (acc != null && !acc.isEmpty() && password != null && !password.isEmpty()) - email.setAuthenticator(new DefaultAuthenticator(acc, !Settings.emailOauth2Token.isEmpty() ? "" : password)); - switch (port) { - case 587: - email.setStartTLSEnabled(true); - email.setStartTLSRequired(true); - if (!Settings.emailOauth2Token.isEmpty()) - { - if (Security.getProvider("Google OAuth2 Provider") == null) - Security.addProvider(new OAuth2Provider()); - email.getMailSession().getProperties().setProperty("mail.smtp.starttls.enable", "true"); - email.getMailSession().getProperties().setProperty("mail.smtp.starttls.required", "true"); - email.getMailSession().getProperties().setProperty("mail.smtp.sasl.enable", "true"); - email.getMailSession().getProperties().setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2"); - email.getMailSession().getProperties().setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, password); - } - break; - case 25: - email.setStartTLSEnabled(true); - email.setSSLCheckServerIdentity(true); - break; - case 465: - email.setSSLOnConnect(true); - email.setSSLCheckServerIdentity(true); - break; - default: - email.setStartTLSEnabled(true); - email.setSSLOnConnect(true); - email.setSSLCheckServerIdentity(true); - break; - } - String content = mailText; - // Generate an image ? - File file = null; - if (Settings.generateImage) { - try { - ImageGenerator gen = new ImageGenerator(newPass); - file = new File(plugin.getDataFolder() + File.separator + auth.getNickname() + "_new_pass.jpg"); - ImageIO.write(gen.generateImage(), "jpg", file); - DataSource source = new FileDataSource(file); - String tag = email.embed(source, auth.getNickname() + "_new_pass.jpg"); - content = content.replace("%image%", ""); - } catch (Exception e) { - ConsoleLogger.showError("Unable to send new password as image! Using normal text! Dest: " + mail); - } - } - try { - email.setHtmlMsg(content); - email.setTextMsg(content); - } catch (EmailException e) - { - ConsoleLogger.showError("Your email.html config contains some error and cannot be send!"); - return; - } - try { - email.send(); - } catch (Exception e) { - ConsoleLogger.showError("Fail to send a mail to " + mail + " cause " + e.getLocalizedMessage()); - } - if (file != null) - //noinspection ResultOfMethodCallIgnored - file.delete(); + email = initializeMail(auth); + setPropertiesForPort(port, email); + } catch (EmailException e) { + ConsoleLogger.showError("Failed to create email with the given settings: " + + StringUtils.formatException(e)); + return; + } - } catch (Exception e) { - // Print the stack trace - e.printStackTrace(); - ConsoleLogger.showError("Some error occurred while trying to send a email to " + mail); + String content = mailText; + // Generate an image? + File file = null; + if (Settings.generateImage) { + 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)); + } + } + + sendEmail(content, email); + if (file != null) { + file.delete(); } } }); } + + 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"); + ImageIO.write(gen.generateImage(), "jpg", file); + return file; + } + + 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("", ""); + } + + private static HtmlEmail initializeMail(PlayerAuth auth) throws EmailException { + String senderName; + if (Settings.getmailSenderName == null || Settings.getmailSenderName.isEmpty()) { + senderName = Settings.getmailAccount; + } else { + senderName = Settings.getmailSenderName; + } + String senderMail = Settings.getmailAccount; + String mailPassword = Settings.getmailPassword; + + HtmlEmail email = new HtmlEmail(); + email.setSmtpPort(Settings.getMailPort); + email.setHostName(Settings.getmailSMTP); + email.addTo(auth.getEmail()); + email.setFrom(senderMail, senderName); + email.setSubject(Settings.getMailSubject); + if (!StringUtils.isEmpty(senderMail) && !StringUtils.isEmpty(mailPassword)) { + String password = !Settings.emailOauth2Token.isEmpty() ? "" : mailPassword; + email.setAuthenticator(new DefaultAuthenticator(senderMail, password)); + } + return email; + } + + private static boolean sendEmail(String content, HtmlEmail email) { + try { + 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)); + return false; + } + try { + email.send(); + return true; + } catch (EmailException e) { + ConsoleLogger.showError("Failed to send a mail to " + email.getToAddresses() + ": " + e.getMessage()); + return false; + } + } + + private static String replaceMailTags(String mailText, AuthMe plugin, PlayerAuth auth, String newPass) { + return mailText + .replace("", auth.getNickname()) + .replace("", plugin.getServer().getServerName()) + .replace("", newPass); + } + + private static void setPropertiesForPort(int port, HtmlEmail email) throws EmailException { + switch (port) { + case 587: + email.setStartTLSEnabled(true); + email.setStartTLSRequired(true); + if (!Settings.emailOauth2Token.isEmpty()) { + if (Security.getProvider("Google OAuth2 Provider") == null) { + Security.addProvider(new OAuth2Provider()); + } + + Properties mailProperties = email.getMailSession().getProperties(); + mailProperties.setProperty("mail.smtp.starttls.enable", "true"); + mailProperties.setProperty("mail.smtp.starttls.required", "true"); + mailProperties.setProperty("mail.smtp.sasl.enable", "true"); + mailProperties.setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2"); + mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, Settings.getmailPassword); + } + break; + case 25: + email.setStartTLSEnabled(true); + email.setSSLCheckServerIdentity(true); + break; + case 465: + email.setSSLOnConnect(true); + email.setSSLCheckServerIdentity(true); + break; + default: + email.setStartTLSEnabled(true); + email.setSSLOnConnect(true); + email.setSSLCheckServerIdentity(true); + } + } } diff --git a/src/main/java/fr/xephi/authme/settings/Settings.java b/src/main/java/fr/xephi/authme/settings/Settings.java index 89067af0..ba0496a0 100644 --- a/src/main/java/fr/xephi/authme/settings/Settings.java +++ b/src/main/java/fr/xephi/authme/settings/Settings.java @@ -79,7 +79,7 @@ public final class Settings { enableProtection, enableAntiBot, recallEmail, useWelcomeMessage, broadcastWelcomeMessage, forceRegKick, forceRegLogin, checkVeryGames, delayJoinLeaveMessages, noTeleport, applyBlindEffect, - kickPlayersBeforeStoping, + kickPlayersBeforeStopping, customAttributes, generateImage, isRemoveSpeedEnabled, preventOtherCase; public static String helpHeader, getNickRegex, getUnloggedinGroup, getMySQLHost, getMySQLPort, getMySQLUsername, getMySQLPassword, getMySQLDatabase, @@ -301,7 +301,7 @@ public final class Settings { customAttributes = configFile.getBoolean("Hooks.customAttributes"); generateImage = configFile.getBoolean("Email.generateImage", false); preventOtherCase = configFile.getBoolean("settings.preventOtherCase", false); - kickPlayersBeforeStoping = configFile.getBoolean("Security.stop.kickPlayersBeforeStoping", true); + kickPlayersBeforeStopping = configFile.getBoolean("Security.stop.kickPlayersBeforeStopping", true); emailOauth2Token = configFile.getString("Email.emailOauth2Token", ""); // Load the welcome message @@ -730,8 +730,8 @@ public final class Settings { ConsoleLogger.showError("Remove Email.mailText from config, we now use the email.html file"); } - if (!contains("Security.stop.kickPlayersBeforeStoping")) { - set("Security.stop.kickPlayersBeforeStoping", true); + if (!contains("Security.stop.kickPlayersBeforeStopping")) { + set("Security.stop.kickPlayersBeforeStopping", true); changes = true; } diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 25988de2..966039ff 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -102,7 +102,7 @@ settings: # - playername;127.0.0.1 AllowedRestrictedUser: - playername;127.0.0.1 - # Should unregistered players be kicked immediatly? + # Should unregistered players be kicked immediately? kickNonRegistered: false # Should players be kicked on wrong password? kickOnWrongPassword: false @@ -150,7 +150,7 @@ settings: maxJoinPerIp: 0 # AuthMe will NEVER teleport players ! noTeleport: false - # Regex sintax for allowed Chars in passwords. + # Regex syntax for allowed Chars in passwords. allowedPasswordCharacters: '[\x21-\x7E]*' GameMode: # ForceSurvivalMode to player when join ? @@ -158,7 +158,7 @@ settings: # if player join with CreativeMode and ForceSurvivalMode: true # inventory will be wipped ResetInventoryIfCreative: false - # Do we need to force the survival mode ONLY after /login process ? + # Do we need to force the survival mode ONLY after /login process? ForceOnlyAfterLogin: false security: # minimum Length of password @@ -192,9 +192,9 @@ settings: passwordHash: SHA256 # salt length for the SALTED2MD5 MD5(MD5(password)+salt) doubleMD5SaltLength: 8 - # If password checking return false , do we need to check with all - # other password algorithm to check an old password ? - # AuthMe will update the password to the new passwordHash ! + # If password checking return false, do we need to check with all + # other password algorithm to check an old password? + # AuthMe will update the password to the new passwordHash! supportOldPasswordHash: false # Cancel unsafe passwords for being used, put them on lowercase! #unsafePasswords: @@ -215,19 +215,19 @@ settings: # Only registered and logged in players can play. # See restrictions for exceptions force: true - # Does we replace password registration by an Email registration method ? + # Does we replace password registration by an Email registration method? enableEmailRegistrationSystem: false # Enable double check of email when you register # when it's true, registration require that kind of command: # /register doubleEmailCheck: false - # Do we force kicking player after a successful registration ? + # Do we force kicking player after a successful registration? # Do not use with login feature below forceKickAfterRegister: false - # Does AuthMe need to enforce a /login after a successful registration ? + # Does AuthMe need to enforce a /login after a successful registration? forceLoginAfterRegister: false unrestrictions: - # below you can list all your account name, that + # below you can list all account names that # AuthMe will ignore for registration or login, configure it # at your own risk!! Remember that if you are going to add # nickname with [], you have to delimit name with ' '. @@ -255,10 +255,10 @@ settings: broadcastWelcomeMessage: false # Do we need to delay the join/leave message to be displayed only when the player is authenticated ? delayJoinLeaveMessages: true - # Do we need to add potion effect Blinding before login/register ? + # Do we need to add potion effect Blinding before login/register? applyBlindEffect: false - # Do we need to prevent people to login without another case ? - # Xephi is registered, also Xephi can login, but not XEPHI/xephi/XePhI + # Do we need to prevent people to login with another case? + # If Xephi is registered, then Xephi can login, but not XEPHI/xephi/XePhI preventOtherCase: false ExternalBoardOptions: # MySQL column for the salt , needed for some forum/cms support @@ -317,9 +317,9 @@ Security: # Captcha length captchaLength: 5 stop: - # Kick players before stoping the server, that allow us to save position of players, and all needed - # informations correctly without any corruption. - kickPlayersBeforeStoping: true + # Kick players before stopping the server, that allow us to save position of players, and all needed + # information correctly without any corruption. + kickPlayersBeforeStopping: true Converter: Rakamak: # Rakamak file name @@ -350,7 +350,7 @@ Email: mailText: 'Dear ,

This is your new AuthMe password for the server

:



Do not forget to change password after login!
/changepassword newPassword' # Like maxRegPerIp but with email maxRegPerEmail: 1 - # Recall players to add an email ? + # Recall players to add an email? recallPlayers: false # Delay in minute for the recall scheduler delayRecall: 5 @@ -359,35 +359,35 @@ Email: - 10minutemail.com # WhiteList only these domains for emails emailWhitelisted: [] - # Do we need to send new password draw in an image ? + # Do we need to send new password draw in an image? generateImage: false Hooks: # Do we need to hook with multiverse for spawn checking? multiverse: true - # Do we need to hook with BungeeCord for get the real Player ip ? + # Do we need to hook with BungeeCord for get the real Player ip? bungeecord: false - # Do we need to disable Essentials SocialSpy on join ? + # Do we need to disable Essentials SocialSpy on join? disableSocialSpy: true - # Do we need to force /motd Essentials command on join ? + # Do we need to force /motd Essentials command on join? useEssentialsMotd: false - # Do we need to cache custom Attributes ? + # Do we need to cache custom Attributes? customAttributes: false Purge: - # On Enable , does AuthMe need to purge automatically old accounts unused ? + # If enabled, AuthMe automatically purges old, unused accounts useAutoPurge: false # Number of Days an account become Unused daysBeforeRemovePlayer: 60 - # Do we need to remove the player.dat file during purge process ? + # Do we need to remove the player.dat file during purge process? removePlayerDat: false - # Do we need to remove the Essentials/users/player.yml file during purge process ? + # Do we need to remove the Essentials/users/player.yml file during purge process? removeEssentialsFile: false # World where are players.dat stores defaultWorld: 'world' - # Do we need to remove LimitedCreative/inventories/player.yml , player_creative.yml files during purge process ? + # Do we need to remove LimitedCreative/inventories/player.yml, player_creative.yml files during purge process ? removeLimitedCreativesInventories: false - # Do we need to remove the AntiXRayData/PlayerData/player file during purge process ? + # Do we need to remove the AntiXRayData/PlayerData/player file during purge process? removeAntiXRayFile: false - # Do we need to remove permissions ? + # Do we need to remove permissions? removePermissions: false Protection: # Enable some servers protection ( country based login, antibot ) @@ -397,7 +397,7 @@ Protection: countries: - 'US' - 'GB' - # Countries blacklisted automatically ( without any needed to enable protection ) + # Countries blacklisted automatically (without any needed to enable protection) # PLEASE USE QUOTES! countriesBlacklist: - 'A1'