This repository has been archived on 2021-12-05. You can view files and clone it, but cannot push or open issues or pull requests.
envoy/src/main/java/envoy/server/processors/LoginCredentialProcessor.java

167 lines
6.2 KiB
Java
Raw Normal View History

package envoy.server.processors;
import static envoy.data.User.UserStatus.ONLINE;
import static envoy.event.HandshakeRejection.INTERNAL_ERROR;
import static envoy.event.HandshakeRejection.USERNAME_TAKEN;
import static envoy.event.HandshakeRejection.WRONG_PASSWORD_OR_USER;
import static envoy.event.HandshakeRejection.WRONG_VERSION;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Logger;
import javax.persistence.NoResultException;
2020-06-23 09:08:57 +02:00
import enovy.server.util.VersionUtils;
import envoy.data.LoginCredentials;
import envoy.data.Message.MessageStatus;
import envoy.event.HandshakeRejection;
import envoy.event.MessageStatusChange;
import envoy.server.data.GroupMessage;
import envoy.server.data.PersistenceManager;
import envoy.server.data.User;
import envoy.server.net.ConnectionManager;
import envoy.server.net.ObjectWriteProxy;
2020-06-26 22:04:40 +02:00
import envoy.util.Bounds;
import envoy.util.EnvoyLog;
/**
2019-12-30 15:15:25 +01:00
* This {@link ObjectProcessor} handles {@link LoginCredentials}.<br>
* <br>
* Project: <strong>envoy-server-standalone</strong><br>
* File: <strong>LoginCredentialProcessor.java</strong><br>
* Created: <strong>30.12.2019</strong><br>
2019-12-30 15:15:25 +01:00
*
* @author Kai S. K. Engelbart
* @author Maximilian K&auml;fer
2019-12-30 15:15:25 +01:00
* @since Envoy Server Standalone v0.1-alpha
*/
public final class LoginCredentialProcessor implements ObjectProcessor<LoginCredentials> {
2020-02-12 07:10:33 +01:00
private final PersistenceManager persistenceManager = PersistenceManager.getInstance();
private final ConnectionManager connectionManager = ConnectionManager.getInstance();
2019-12-30 15:15:25 +01:00
2020-06-26 22:04:40 +02:00
private static final Logger logger = EnvoyLog.getLogger(LoginCredentialProcessor.class);
@Override
public void process(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException {
// Cache this write proxy for user-independant notifications
UserStatusChangeProcessor.setWriteProxy(writeProxy);
2020-06-23 09:08:57 +02:00
if (!VersionUtils.verifyCompatibility(credentials.getClientVersion())) {
logger.info("The client has the wrong version.");
2020-06-23 09:08:57 +02:00
writeProxy.write(socketID, new HandshakeRejection(WRONG_VERSION));
return;
}
// Acquire a user object (or reject the handshake if that's impossible)
User user = null;
if (!credentials.isRegistration()) {
try {
user = persistenceManager.getUserByName(credentials.getIdentifier());
// Checking if user is already online
if (connectionManager.isOnline(user.getID())) {
logger.warning(user + " is already online!");
writeProxy.write(socketID, new HandshakeRejection(INTERNAL_ERROR));
return;
}
// Evaluating the correctness of the password hash
if (!Arrays.equals(credentials.getPasswordHash(), user.getPasswordHash())) {
logger.info(user + " has entered the wrong password.");
writeProxy.write(socketID, new HandshakeRejection(WRONG_PASSWORD_OR_USER));
return;
}
} catch (NoResultException e) {
logger.info("The requested user does not exist.");
writeProxy.write(socketID, new HandshakeRejection(WRONG_PASSWORD_OR_USER));
return;
}
} else {
2020-06-26 22:04:40 +02:00
// Validate user name
if (!Bounds.isValidContactName(credentials.getIdentifier())) {
logger.info("The requested user name is not valid.");
writeProxy.write(socketID, new HandshakeRejection(INTERNAL_ERROR));
return;
}
2020-06-26 22:04:40 +02:00
try {
// Checking that no user already has this identifier
PersistenceManager.getInstance().getUserByName(credentials.getIdentifier());
// This code only gets executed if this user already exists
logger.info("The requested user already exists.");
writeProxy.write(socketID, new HandshakeRejection(USERNAME_TAKEN));
return;
} catch (NoResultException e) {
// Creation of a new user
user = new User();
user.setName(credentials.getIdentifier());
user.setLastSeen(LocalDateTime.now());
user.setStatus(ONLINE);
user.setPasswordHash(credentials.getPasswordHash());
user.setContacts(new HashSet<>());
persistenceManager.addContact(user);
logger.info("Registered new " + user);
}
2020-02-12 07:10:33 +01:00
}
logger.info(user + " successfully authenticated.");
connectionManager.registerUser(user.getID(), socketID);
// Change status and notify contacts about it
user.setStatus(ONLINE);
UserStatusChangeProcessor.updateUserStatus(user);
// Complete the handshake
writeProxy.write(socketID, user.toCommon());
final var pendingMessages = PersistenceManager.getInstance().getPendingMessages(user);
logger.fine("Sending " + pendingMessages.size() + " pending messages to " + user + "...");
List<GroupMessage> pendingGroupMessages = PersistenceManager.getInstance().getPendingGroupMessages(user);
logger.fine("Sending " + pendingGroupMessages.size() + " pending group messages to " + user + "...");
for (var msg : pendingMessages) {
final var msgCommon = msg.toCommon();
if (msg.getStatus() == MessageStatus.SENT) {
// Send the message
writeProxy.write(socketID, msgCommon);
msg.received();
PersistenceManager.getInstance().updateMessage(msg);
// Notify the sender about the delivery
if (connectionManager.isOnline(msg.getSender().getID())) {
msgCommon.nextStatus();
writeProxy.write(connectionManager.getSocketID(msg.getSender().getID()), new MessageStatusChange(msgCommon));
}
} else writeProxy.write(socketID, new MessageStatusChange(msgCommon));
}
for (GroupMessage gmsg : pendingGroupMessages) {
if (gmsg.getMemberMessageStatus().get(user.getID()) == MessageStatus.SENT) {
gmsg.getMemberMessageStatus().replace(user.getID(), MessageStatus.RECEIVED);
envoy.data.GroupMessage groupMessage = gmsg.toCommon();
logger.info("Sending groupMessage" + groupMessage);
System.out.println(groupMessage.toString());
writeProxy.write(socketID, groupMessage);
// Sending memberStatusEvent to all members (event does not exist yet I think)
if (!gmsg.getMemberMessageStatus().containsValue(MessageStatus.SENT)) {
gmsg.setStatus(MessageStatus.RECEIVED);
// TODO: Sending MessageStatusChangeEvent to all other members
}
PersistenceManager.getInstance().updateMessage(gmsg);
} else {
// Sending memberStatusEvents and MessageStatusChange Events
}
}
}
2020-02-12 07:10:33 +01:00
@Override
public Class<LoginCredentials> getInputClass() { return LoginCredentials.class; }
}