/**
Creep Smash, a multiplayer towerdefence game
created as a project at the Hochschule fuer
Technik Stuttgart (University of Applied Science)
http://www.hft-stuttgart.de
Copyright (C) 2008 by
* Andreas Wittig
* Bernd Hietler
* Christoph Fritz
* Fabian Kessel
* Levin Fritz
* Nikolaj Langner
* Philipp Schulte-Hubbert
* Robert Rapczynski
* Ron Trautsch
* Sven Supper
http://creepsmash.sf.net/
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
**/
package de.creepsmash.server;
import java.util.HashSet;
import java.util.List;
import java.util.Properties;
import java.util.Random;
import java.util.Set;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.NoSuchProviderException;
import javax.mail.SendFailedException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.PersistenceException;
import javax.persistence.Query;
import org.apache.log4j.Logger;
import com.sun.mail.smtp.SMTPTransport;
import de.creepsmash.common.IConstants;
import de.creepsmash.server.model.Player;
/**
* Service for player-management. Persists player-data to the database.
*
* @author andreas
*
*/
public class AuthenticationService {
private final Lobby lobby;
private final String mailhostName;
private final String authMailUsername;
private final String authMailPassword;
private final Set<String> loggedIn;
private static Logger logger = Logger
.getLogger(AuthenticationService.class);
private static final String QUERY_ALL_PLAYERS =
"SELECT player FROM Player AS player";
private static final String QUERY_PLAYERS_ORDERBY_ELO =
"SELECT player FROM Player AS player ORDER BY player.elopoints DESC";
/**
* @param lobby the lobby.
* @param mailhostName mail server hostname.
* @param authMailUsername mail server username.
* @param authMailPassword mail server password.
*/
public AuthenticationService(Lobby lobby, String mailhostName,
String authMailUsername, String authMailPassword) {
super();
this.lobby = lobby;
this.mailhostName = mailhostName;
this.authMailUsername = authMailUsername;
this.authMailPassword = authMailPassword;
this.loggedIn = new HashSet<String>();
}
/**
* @param playerName the name of the player
* @param password the password of the player
* @param email the email of the player
* @return ok if successful, username if the username is in use, failed for
* other errors.
*/
public static IConstants.ResponseType create(
String playerName, String password, String email) {
if (AuthenticationService.getPlayer(playerName) != null) {
logger.error("registration failed (username used)");
return IConstants.ResponseType.username;
}
try {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
EntityTransaction entityTransaction = entityManager
.getTransaction();
entityTransaction.begin();
Player player = new Player();
player.setName(playerName);
player.setPassword(password);
player.setEmail(email);
player.setElopoints(500);
player.setOldElopoints(500);
entityManager.persist(player);
entityManager.flush();
entityTransaction.commit();
} catch (Exception e) {
logger.error("registration failed");
logger.debug(e.getLocalizedMessage());
return IConstants.ResponseType.failed;
}
logger.info("new player registered");
return IConstants.ResponseType.ok;
}
/**
* @param playerName the name of the player to update
* @param oldPassword the old password
* @param password the new password
* @param mail the new mailadress
* @return the response type for ResponseMessage
*/
public static IConstants.ResponseType update(
String playerName, String oldPassword,
String password, String mail) {
boolean update = false;
IConstants.ResponseType responseType = IConstants.ResponseType.failed;
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
EntityTransaction entityTransaction = entityManager
.getTransaction();
entityTransaction.begin();
Player player = entityManager.find(Player.class, playerName);
if (player != null) {
if ((oldPassword != null) && (oldPassword.length() > 0)
&& (password != null) && (password.length() > 0)) {
if (player.getPassword().equals(oldPassword)) {
player.setPassword(password);
update = true;
}
}
if ((mail != null) && (mail.length() > 0)) {
player.setEmail(mail);
update = true;
} else {
logger.error("password not changed, "
+ "because old password was wrong");
}
if (update) {
entityManager.merge(player);
entityManager.flush();
responseType = IConstants.ResponseType.ok;
logger.info("registartion data for player "
+ playerName + " changed.");
}
} else {
logger.error("player with playername "
+ playerName + " was not found.");
}
entityTransaction.commit();
return responseType;
}
/**
* @param playerName
* the name of the player
* @return the response type
*/
public static IConstants.ResponseType delete(String playerName) {
IConstants.ResponseType responseType = IConstants.ResponseType.failed;
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
EntityTransaction entityTransaction = entityManager.getTransaction();
entityTransaction.begin();
Player player = entityManager.find(Player.class, playerName);
if (player != null) {
entityManager.remove(player);
responseType = IConstants.ResponseType.ok;
}
entityTransaction.commit();
return responseType;
}
/**
* @param playerName the player's name
* @param password the password
* @return the lobby, of null if the login failed
*/
public Lobby login(String playerName, String password) {
Player player = null;
EntityManager entityManager = PersistenceManager.getInstance().getEntityManager();
try {
player = entityManager.find(Player.class, playerName);
} catch(PersistenceException e){
logger.info("Connection lost ? " + e.getMessage());
}
if ((player != null)) {
for (String UserName : this.loggedIn) {
if (UserName.equalsIgnoreCase(player.getName())) {
logger.info(player.getName() + " tried to log in twice");
return null;
}
}
}
if ((player != null) && (player.getPassword().equals(password)) && !player.isBlocked()) {
this.loggedIn.add(player.getName());
logger.info(player.getName() + " logged in successfully");
return this.lobby;
}
logger.info("login failed");
return null;
}
/**
* Log out.
* @param playerName the name of the player who wants to log out.
*/
public void logout(String playerName) {
if (this.loggedIn.remove(playerName)) {
logger.info(playerName + " logged out");
} else {
logger.warn(playerName
+ " tried to log out, but wasn't logged in!");
}
}
/**
* @return the name of all registered players.
*/
public static Set<String> getPlayerNames() {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
Set<String> playerNames = new HashSet<String>();
Query query = entityManager.createQuery(QUERY_ALL_PLAYERS);
List< ? > resultList = query.getResultList();
if ((resultList != null) && (resultList.size() > 0)) {
for (Object o : resultList) {
Player player = (Player) o;
playerNames.add(player.getName());
}
}
return playerNames;
}
/**
* @return all registered players.
*/
public static Set<Player> getPlayers() {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
Set<Player> players = new HashSet<Player>();
Query query = entityManager.createQuery(QUERY_ALL_PLAYERS);
List< ? > resultList = query.getResultList();
if ((resultList != null) && (resultList.size() > 0)) {
for (Object o : resultList) {
Player player = (Player) o;
players.add(player);
}
}
return players;
}
/**
* @param firstResult the index of the first result returned.
* @return 30 players sorted by elopoints starting with firstResult.
*/
public static Set<Player> getPlayers(int firstResult) {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
Set<Player> players = new HashSet<Player>();
List< ? > resultList = null;
Query query = entityManager.createQuery(QUERY_PLAYERS_ORDERBY_ELO);
query.setMaxResults(30);
query.setFirstResult(firstResult);
try {
resultList = query.getResultList();
}catch (PersistenceException e){
logger.error("error while Query getPlayers DB Connection lost?");
}
if ((resultList != null) && (resultList.size() > 0)) {
for (Object o : resultList) {
Player player = (Player) o;
players.add(player);
}
}
return players;
}
/**
* @param playerName the name of a player
* @return the player with playerName
*/
public static Player getPlayer(String playerName) {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
Player player = null;
try {
player = entityManager.find(Player.class, playerName);
}catch(PersistenceException e){
logger.error("DB Connection lost ?");
}
return player;
}
/**
* @param playerName the playername.
* @return true if the password was successfully reset.
*/
public boolean resetPassword(String playerName) {
boolean result = false;
Player player = getPlayer(playerName);
if ((player != null)
&& (player.getEmail() != null)
&& (player.getEmail().length() > 0)
&& (this.mailhostName != null)
&& (this.authMailUsername != null)
&& (this.authMailPassword != null)) {
EntityManager entityManager =
PersistenceManager.getInstance().getEntityManager();
EntityTransaction entityTransaction = entityManager
.getTransaction();
entityTransaction.begin();
player.setPassword(randomString(8));
entityManager.merge(player);
entityManager.flush();
entityTransaction.commit();
sendMail(player.getEmail(), "CreepSmash - new password for "
+ playerName, "Hi "
+ playerName
+ "! \n\r Here is Your new password "
+ "for playing CreepSmash on "
+ "www.creepsmash.de . "
+ "\n\r new password: "
+ player.getPassword(),
this.authMailUsername,
this.authMailUsername,
this.authMailPassword,
this.mailhostName);
result = true;
}
return result;
}
/**
* Send an email.
* @param recipient the recipient email address.
* @param subject the subject.
* @param message the message body.
* @param from the "from" address.
* @param authUsername the username to use for authentication.
* @param authPassword the password to use for authentication.
* @param mailhost the hostname of the mail server.
*/
private static void sendMail(String recipient, String subject,
String message, String from, String authUsername,
String authPassword, String mailhost) {
try {
if ((mailhost != null) && (authUsername != null)
&& (authPassword != null)) {
Properties props = new Properties();
MailAuthenticator auth = new MailAuthenticator(authUsername,
authPassword);
props.put("mail.transport.protocol", "smtps");
props.put("mail.smtps.host", mailhost);
props.put("mail.smtps.auth", "true");
props.put("mail.smtps.port", "465");
Session session = Session.getDefaultInstance(props, auth);
Message msg = new MimeMessage(session);
InternetAddress addressFrom = new InternetAddress(from);
msg.setFrom(addressFrom);
InternetAddress addressTo = new InternetAddress(recipient);
msg.setRecipient(Message.RecipientType.TO, addressTo);
msg.setSubject(subject);
msg.setContent(message, "text/plain");
SMTPTransport t = (SMTPTransport) session.getTransport("smtps");
t.connect(mailhost, authUsername, authPassword);
logger.debug("smtps: connected to " + mailhost);
t.sendMessage(msg, msg.getAllRecipients());
t.close();
logger.info("mail send to " + recipient);
}
} catch (NoSuchProviderException e) {
e.printStackTrace();
} catch (SendFailedException e) {
logger.error("error while sending a mail", e);
} catch (MessagingException e) {
logger.error("error while sending a mail", e);
}
}
/**
* @param length
* @return a string with random characters.
*/
public static String randomString(int length) {
String result = "";
for (int i = 0; i < length; i++) {
result += randomChar();
}
return result;
}
/**
* @return a random character.
*/
public static char randomChar() {
Random random = new Random();
random.nextInt(22);
return ((char) (random.nextInt(25) + 97));
}
}