Del all files

This commit is contained in:
HaHaWTH
2023-07-11 20:42:24 +08:00
parent 912e607144
commit b014da245d
475 changed files with 0 additions and 93277 deletions
@@ -1,223 +0,0 @@
package fr.xephi.authme.mail;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.initialization.DataFolder;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.settings.properties.SecuritySettings;
import fr.xephi.authme.util.FileUtils;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.imageio.ImageIO;
import javax.inject.Inject;
import java.io.File;
import java.io.IOException;
/**
* Creates emails and sends them.
*/
public class EmailService {
private final ConsoleLogger logger = ConsoleLoggerFactory.get(EmailService.class);
private final File dataFolder;
private final Settings settings;
private final SendMailSsl sendMailSsl;
@Inject
EmailService(@DataFolder File dataFolder, Settings settings, SendMailSsl sendMailSsl) {
this.dataFolder = dataFolder;
this.settings = settings;
this.sendMailSsl = sendMailSsl;
}
public boolean hasAllInformation() {
return sendMailSsl.hasAllInformation();
}
public boolean sendNewPasswordMail(String name, String mailAddress, String newPass,String ip,String time) {
HtmlEmail email;
try {
email = sendMailSsl.initializeMail(mailAddress);
} catch (EmailException e) {
logger.logException("Failed to create email with the given settings:", e);
return false;
}
String mailText = replaceTagsForPasswordMail(settings.getNewPasswordEmailMessage(), name, newPass,ip,time);
File file = null;
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
file = generatePasswordImage(name, newPass);
mailText = embedImageIntoEmailContent(file, email, mailText);
} catch (IOException | EmailException e) {
logger.logException(
"Unable to send new password as image for email " + mailAddress + ":", e);
}
}
boolean couldSendEmail = sendMailSsl.sendEmail(mailText, email);
FileUtils.delete(file);
return couldSendEmail;
}
/**
* Sends an email to the user with his new password.
*
* @param name the name of the player
* @param mailAddress the player's email
* @param newPass the new password
* @return true if email could be sent, false otherwise
*/
public boolean sendPasswordMail(String name, String mailAddress, String newPass, String time) {
if (!hasAllInformation()) {
logger.warning("Cannot perform email registration: not all email settings are complete");
return false;
}
HtmlEmail email;
try {
email = sendMailSsl.initializeMail(mailAddress);
} catch (EmailException e) {
logger.logException("Failed to create email with the given settings:", e);
return false;
}
String mailText = replaceTagsForPasswordMail(settings.getPasswordEmailMessage(), name, newPass,time);
// Generate an image?
File file = null;
if (settings.getProperty(EmailSettings.PASSWORD_AS_IMAGE)) {
try {
file = generatePasswordImage(name, newPass);
mailText = embedImageIntoEmailContent(file, email, mailText);
} catch (IOException | EmailException e) {
logger.logException(
"Unable to send new password as image for email " + mailAddress + ":", e);
}
}
boolean couldSendEmail = sendMailSsl.sendEmail(mailText, email);
FileUtils.delete(file);
return couldSendEmail;
}
/**
* Sends an email to the user with the temporary verification code.
*
* @param name the name of the player
* @param mailAddress the player's email
* @param code the verification code
*/
public void sendVerificationMail(String name, String mailAddress, String code, String time) {
if (!hasAllInformation()) {
logger.warning("Cannot send verification email: not all email settings are complete");
return;
}
HtmlEmail email;
try {
email = sendMailSsl.initializeMail(mailAddress);
} catch (EmailException e) {
logger.logException("Failed to create verification email with the given settings:", e);
return;
}
String mailText = replaceTagsForVerificationEmail(settings.getVerificationEmailMessage(), name, code,
settings.getProperty(SecuritySettings.VERIFICATION_CODE_EXPIRATION_MINUTES),time);
sendMailSsl.sendEmail(mailText, email);
}
/**
* Sends an email to the user with a recovery code for the password recovery process.
*
* @param name the name of the player
* @param email the player's email address
* @param code the recovery code
* @return true if email could be sent, false otherwise
*/
public boolean sendRecoveryCode(String name, String email, String code, String time) {
HtmlEmail htmlEmail;
try {
htmlEmail = sendMailSsl.initializeMail(email);
} catch (EmailException e) {
logger.logException("Failed to create email for recovery code:", e);
return false;
}
String message = replaceTagsForRecoveryCodeMail(settings.getRecoveryCodeEmailMessage(),
name, code, settings.getProperty(SecuritySettings.RECOVERY_CODE_HOURS_VALID),time);
return sendMailSsl.sendEmail(message, htmlEmail);
}
public void sendShutDown(String email, String time) {
HtmlEmail htmlEmail;
try {
htmlEmail = sendMailSsl.initializeMail(email);
} catch (EmailException e) {
logger.logException("Failed to create email for recovery code:", e);
return;
}
String message = replaceTagsForShutDownMail(settings.getShutdownEmailMessage(), time);
sendMailSsl.sendEmail(message, htmlEmail);
}
private File generatePasswordImage(String name, String newPass) throws IOException {
ImageGenerator gen = new ImageGenerator(newPass);
File file = new File(dataFolder, name + "_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("<image />", "<img src=\"cid:" + tag + "\">");
}
private String replaceTagsForPasswordMail(String mailText, String name, String newPass,String ip,String time) {
return mailText
.replace("<playername />", name)
.replace("<servername />", settings.getProperty(PluginSettings.SERVER_NAME))
.replace("<generatedpass />", newPass)
.replace("<playerip />", ip)
.replace("<time />", time);
}
private String replaceTagsForPasswordMail(String mailText, String name, String newPass, String time) {
return mailText
.replace("<playername />", name)
.replace("<servername />", settings.getProperty(PluginSettings.SERVER_NAME))
.replace("<generatedpass />", newPass)
.replace("<time />", time);
}
private String replaceTagsForVerificationEmail(String mailText, String name, String code, int minutesValid, String time) {
return mailText
.replace("<playername />", name)
.replace("<servername />", settings.getProperty(PluginSettings.SERVER_NAME))
.replace("<generatedcode />", code)
.replace("<minutesvalid />", String.valueOf(minutesValid))
.replace("<time />", time);
}
private String replaceTagsForRecoveryCodeMail(String mailText, String name, String code, int hoursValid, String time) {
return mailText
.replace("<playername />", name)
.replace("<servername />", settings.getProperty(PluginSettings.SERVER_NAME))
.replace("<recoverycode />", code)
.replace("<hoursvalid />", String.valueOf(hoursValid))
.replace("<time />", time);
}
private String replaceTagsForShutDownMail(String mailText, String time) {
return mailText
.replace("<servername />", settings.getProperty(PluginSettings.SERVER_NAME))
.replace("<time />", time);
}
}
@@ -1,40 +0,0 @@
package fr.xephi.authme.mail;
import java.awt.*;
import java.awt.image.BufferedImage;
/**
*/
public class ImageGenerator {
private final String pass;
/**
* Constructor for ImageGenerator.
*
* @param pass String
*/
public ImageGenerator(String pass) {
this.pass = pass;
}
/**
* Method generateImage.
*
* @return BufferedImage
*/
public BufferedImage generateImage() {
BufferedImage image = new BufferedImage(200, 60, BufferedImage.TYPE_BYTE_INDEXED);
Graphics2D graphics = image.createGraphics();
graphics.setColor(Color.BLACK);
graphics.fillRect(0, 0, 200, 40);
GradientPaint gradientPaint = new GradientPaint(10, 5, Color.WHITE, 20, 10, Color.WHITE, true);
graphics.setPaint(gradientPaint);
Font font = new Font("Comic Sans MS", Font.BOLD, 30);
graphics.setFont(font);
graphics.drawString(pass, 5, 30);
graphics.dispose();
image.flush();
return image;
}
}
@@ -1,28 +0,0 @@
package fr.xephi.authme.mail;
import java.security.Provider;
/* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
public class OAuth2Provider extends Provider {
private static final long serialVersionUID = 1L;
public OAuth2Provider() {
super("Google OAuth2 Provider", 1.0,
"Provides the XOAUTH2 SASL Mechanism");
put("SaslClientFactory.XOAUTH2",
"fr.xephi.authme.mail.OAuth2SaslClientFactory");
}
}
@@ -1,98 +0,0 @@
/* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package fr.xephi.authme.mail;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import java.io.IOException;
/**
* An OAuth2 implementation of SaslClient.
*/
class OAuth2SaslClient implements SaslClient {
private final String oauthToken;
private final CallbackHandler callbackHandler;
private boolean isComplete = false;
/**
* Creates a new instance of the OAuth2SaslClient. This will ordinarily only
* be called from OAuth2SaslClientFactory.
*/
public OAuth2SaslClient(String oauthToken,
CallbackHandler callbackHandler) {
this.oauthToken = oauthToken;
this.callbackHandler = callbackHandler;
}
public String getMechanismName() {
return "XOAUTH2";
}
public boolean hasInitialResponse() {
return true;
}
public byte[] evaluateChallenge(byte[] challenge) throws SaslException {
if (isComplete) {
// Empty final response from server, just ignore it.
return new byte[] { };
}
NameCallback nameCallback = new NameCallback("Enter name");
Callback[] callbacks = new Callback[] { nameCallback };
try {
callbackHandler.handle(callbacks);
} catch (UnsupportedCallbackException e) {
throw new SaslException("Unsupported callback: " + e);
} catch (IOException e) {
throw new SaslException("Failed to execute callback: " + e);
}
String email = nameCallback.getName();
byte[] response = String.format("user=%s\1auth=Bearer %s\1\1", email,
oauthToken).getBytes();
isComplete = true;
return response;
}
public boolean isComplete() {
return isComplete;
}
public byte[] unwrap(byte[] incoming, int offset, int len)
throws SaslException {
throw new IllegalStateException();
}
public byte[] wrap(byte[] outgoing, int offset, int len)
throws SaslException {
throw new IllegalStateException();
}
public Object getNegotiatedProperty(String propName) {
if (!isComplete()) {
throw new IllegalStateException();
}
return null;
}
public void dispose() throws SaslException {
}
}
@@ -1,57 +0,0 @@
/*
* Copyright 2012 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*/
package fr.xephi.authme.mail;
import javax.security.auth.callback.CallbackHandler;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslClientFactory;
import java.util.Map;
import java.util.logging.Logger;
/**
* A SaslClientFactory that returns instances of OAuth2SaslClient.
*
* <p>
* Only the "XOAUTH2" mechanism is supported. The {@code callbackHandler} is
* passed to the OAuth2SaslClient. Other parameters are ignored.
*/
public class OAuth2SaslClientFactory implements SaslClientFactory {
private static final Logger logger = Logger.getLogger(OAuth2SaslClientFactory.class.getName());
public static final String OAUTH_TOKEN_PROP = "mail.smpt.sasl.mechanisms.oauth2.oauthToken";
public SaslClient createSaslClient(String[] mechanisms,
String authorizationId, String protocol, String serverName,
Map<String, ?> props, CallbackHandler callbackHandler) {
boolean matchedMechanism = false;
for (int i = 0; i < mechanisms.length; ++i) {
if ("XOAUTH2".equalsIgnoreCase(mechanisms[i])) {
matchedMechanism = true;
break;
}
}
if (!matchedMechanism) {
logger.info("Failed to match any mechanisms");
return null;
}
return new OAuth2SaslClient((String) props.get(OAUTH_TOKEN_PROP), callbackHandler);
}
public String[] getMechanismNames(Map<String, ?> props) {
return new String[] { "XOAUTH2" };
}
}
@@ -1,158 +0,0 @@
package fr.xephi.authme.mail;
import fr.xephi.authme.ConsoleLogger;
import fr.xephi.authme.output.ConsoleLoggerFactory;
import fr.xephi.authme.output.LogLevel;
import fr.xephi.authme.settings.Settings;
import fr.xephi.authme.settings.properties.EmailSettings;
import fr.xephi.authme.settings.properties.PluginSettings;
import fr.xephi.authme.util.StringUtils;
import org.apache.commons.mail.EmailConstants;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.HtmlEmail;
import javax.activation.CommandMap;
import javax.activation.MailcapCommandMap;
import javax.inject.Inject;
import javax.mail.Session;
import java.security.Security;
import java.util.Properties;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_ACCOUNT;
import static fr.xephi.authme.settings.properties.EmailSettings.MAIL_PASSWORD;
/**
* Sends emails to players on behalf of the server.
*/
public class SendMailSsl {
private ConsoleLogger logger = ConsoleLoggerFactory.get(SendMailSsl.class);
@Inject
private Settings settings;
/**
* Returns whether all necessary settings are set for sending mails.
*
* @return true if the necessary email settings are set, false otherwise
*/
public boolean hasAllInformation() {
return !settings.getProperty(MAIL_ACCOUNT).isEmpty()
&& !settings.getProperty(MAIL_PASSWORD).isEmpty();
}
/**
* Creates a {@link HtmlEmail} object configured as per the AuthMe config
* with the given email address as recipient.
*
* @param emailAddress the email address the email is destined for
* @return the created HtmlEmail object
* @throws EmailException if the mail is invalid
*/
public HtmlEmail initializeMail(String emailAddress) throws EmailException {
String senderMail = StringUtils.isBlank(settings.getProperty(EmailSettings.MAIL_ADDRESS))
? settings.getProperty(EmailSettings.MAIL_ACCOUNT)
: settings.getProperty(EmailSettings.MAIL_ADDRESS);
String senderName = StringUtils.isBlank(settings.getProperty(EmailSettings.MAIL_SENDER_NAME))
? senderMail
: settings.getProperty(EmailSettings.MAIL_SENDER_NAME);
String mailPassword = settings.getProperty(EmailSettings.MAIL_PASSWORD);
int port = settings.getProperty(EmailSettings.SMTP_PORT);
HtmlEmail email = new HtmlEmail();
email.setCharset(EmailConstants.UTF_8);
email.setSmtpPort(port);
email.setHostName(settings.getProperty(EmailSettings.SMTP_HOST));
email.addTo(emailAddress);
email.setFrom(senderMail, senderName);
email.setSubject(settings.getProperty(EmailSettings.RECOVERY_MAIL_SUBJECT));
email.setAuthentication(settings.getProperty(EmailSettings.MAIL_ACCOUNT), mailPassword);
if (settings.getProperty(PluginSettings.LOG_LEVEL).includes(LogLevel.DEBUG)) {
email.setDebug(true);
}
setPropertiesForPort(email, port);
return email;
}
/**
* Sets the given content to the HtmlEmail object and sends it.
*
* @param content the content to set
* @param email the email object to send
* @return true upon success, false otherwise
*/
public boolean sendEmail(String content, HtmlEmail email) {
Thread.currentThread().setContextClassLoader(SendMailSsl.class.getClassLoader());
// Issue #999: Prevent UnsupportedDataTypeException: no object DCH for MIME type multipart/alternative
// cf. http://stackoverflow.com/questions/21856211/unsupporteddatatypeexception-no-object-dch-for-mime-type
MailcapCommandMap mc = (MailcapCommandMap) CommandMap.getDefaultCommandMap();
mc.addMailcap("text/html;; x-java-content-handler=com.sun.mail.handlers.text_html");
mc.addMailcap("text/xml;; x-java-content-handler=com.sun.mail.handlers.text_xml");
mc.addMailcap("text/plain;; x-java-content-handler=com.sun.mail.handlers.text_plain");
mc.addMailcap("multipart/*;; x-java-content-handler=com.sun.mail.handlers.multipart_mixed");
mc.addMailcap("message/rfc822;; x-java-content- handler=com.sun.mail.handlers.message_rfc822");
try {
email.setHtmlMsg(content);
email.setTextMsg(content);
} catch (EmailException e) {
logger.logException("Your email.html config contains an error and cannot be sent:", e);
return false;
}
try {
email.send();
return true;
} catch (EmailException e) {
logger.logException("Failed to send a mail to " + email.getToAddresses() + ":", e);
return false;
}
}
/**
* Sets properties to the given HtmlEmail object based on the port from which it will be sent.
*
* @param email the email object to configure
* @param port the configured outgoing port
*/
private void setPropertiesForPort(HtmlEmail email, int port) throws EmailException {
switch (port) {
case 587:
String oAuth2Token = settings.getProperty(EmailSettings.OAUTH2_TOKEN);
if (!oAuth2Token.isEmpty()) {
if (Security.getProvider("Google OAuth2 Provider") == null) {
Security.addProvider(new OAuth2Provider());
}
Properties mailProperties = email.getMailSession().getProperties();
mailProperties.setProperty("mail.smtp.ssl.enable", "true");
mailProperties.setProperty("mail.smtp.auth.mechanisms", "XOAUTH2");
mailProperties.setProperty("mail.smtp.sasl.enable", "true");
mailProperties.setProperty("mail.smtp.sasl.mechanisms", "XOAUTH2");
mailProperties.setProperty("mail.smtp.auth.login.disable", "true");
mailProperties.setProperty("mail.smtp.auth.plain.disable", "true");
mailProperties.setProperty(OAuth2SaslClientFactory.OAUTH_TOKEN_PROP, oAuth2Token);
email.setMailSession(Session.getInstance(mailProperties));
} else {
email.setStartTLSEnabled(true);
email.setStartTLSRequired(true);
}
break;
case 25:
if (settings.getProperty(EmailSettings.PORT25_USE_TLS)) {
email.setStartTLSEnabled(true);
email.setSSLCheckServerIdentity(true);
}
break;
case 465:
email.setSslSmtpPort(Integer.toString(port));
email.setSSLOnConnect(true);
break;
default:
email.setStartTLSEnabled(true);
email.setSSLOnConnect(true);
email.setSSLCheckServerIdentity(true);
}
}
}