Shorten event names, refactor, prepare compatibility verification

This commit is contained in:
2020-06-20 09:57:54 +02:00
parent 872b71fbe9
commit 3660dec859
16 changed files with 179 additions and 202 deletions

View File

@ -1,19 +1,23 @@
package envoy.server.processors;
import static envoy.data.User.UserStatus.ONLINE;
import static envoy.event.HandshakeRejection.*;
import java.io.IOException;
import java.util.*;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.HashSet;
import java.util.logging.Logger;
import javax.persistence.NoResultException;
import envoy.data.LoginCredentials;
import envoy.data.Message.MessageStatus;
import envoy.data.User;
import envoy.data.User.UserStatus;
import envoy.event.HandshakeRejectionEvent;
import envoy.event.MessageStatusChangeEvent;
import envoy.server.data.Message;
import envoy.event.HandshakeRejection;
import envoy.event.MessageStatusChange;
import envoy.server.Startup;
import envoy.server.data.PersistenceManager;
import envoy.server.data.User;
import envoy.server.net.ConnectionManager;
import envoy.server.net.ObjectWriteProxy;
import envoy.util.EnvoyLog;
@ -29,126 +33,98 @@ import envoy.util.EnvoyLog;
* @author Maximilian Käfer
* @since Envoy Server Standalone v0.1-alpha
*/
public class LoginCredentialProcessor implements ObjectProcessor<LoginCredentials> {
public final class LoginCredentialProcessor implements ObjectProcessor<LoginCredentials> {
private final PersistenceManager persistenceManager = PersistenceManager.getInstance();
private final ConnectionManager connectionManager = ConnectionManager.getInstance();
private static final Logger logger = EnvoyLog.getLogger(LoginCredentialProcessor.class);
// private static final Pattern versionPattern =
// Pattern.compile("v(?<major>\\d).(?<minor>\\d)(?:-(?<suffix>\\w+))?");
@Override
public void process(LoginCredentials input, long socketID, ObjectWriteProxy writeProxy) throws IOException {
public void process(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException {
// Cache this write proxy for user-independant notifications
UserStatusChangeProcessor.setWriteProxy(writeProxy);
logger.info(String.format("Received login credentials %s from socket ID %d", input, socketID));
envoy.server.data.User user = getUser(input, socketID, writeProxy);
// Not logged in successfully
if (user == null) {
logger.info("Rejecting handshake on socket " + socketID);
return;
// TODO: Verify compatibility
if (Startup.MIN_CLIENT_VERSION.compareTo(credentials.getClientVersion()) <= 0
&& Startup.MAX_CLIENT_VERSION.compareTo(credentials.getClientVersion()) >= 0) {
// writeProxy.write(socketID, new HandshakeRejectionEvent("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 {
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(INTERNAL_ERROR));
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);
}
}
logger.info(user + " successfully authenticated.");
connectionManager.registerUser(user.getID(), socketID);
// Notifies contacts of this users online-going and updates his status in the
// database
user.setStatus(UserStatus.ONLINE);
// Change status and notify contacts about it
user.setStatus(ONLINE);
UserStatusChangeProcessor.updateUserStatus(user);
// Complete handshake
logger.fine("Sending user...");
// Complete the handshake
writeProxy.write(socketID, user.toCommon());
logger.fine("Acquiring pending messages for the client...");
List<Message> pendingMessages = PersistenceManager.getInstance().getPendingMessages(user);
for (Message msg : pendingMessages)
final var pendingMessages = PersistenceManager.getInstance().getPendingMessages(user);
logger.fine("Sending " + pendingMessages.size() + " pending messages to " + user + "...");
for (var msg : pendingMessages) {
final var msgCommon = msg.toCommon();
if (msg.getStatus() == MessageStatus.SENT) {
logger.info("Sending message " + msg.toCommon());
writeProxy.write(socketID, msg.toCommon());
msg.setReceivedDate(new Date());
msg.setStatus(MessageStatus.RECEIVED);
if (connectionManager.isOnline(msg.getSender().getID())) {
var evt = new MessageStatusChangeEvent(msg.toCommon());
logger.info("Sending messageStatusChangeEvent to sender " + evt);
writeProxy.write(connectionManager.getSocketID(msg.getSender().getID()), evt);
}
writeProxy.write(socketID, msgCommon);
msg.received();
if (connectionManager.isOnline(msg.getSender().getID()))
writeProxy.write(connectionManager.getSocketID(msg.getSender().getID()), new MessageStatusChange(msgCommon));
PersistenceManager.getInstance().updateMessage(msg);
} else {
var evt = new MessageStatusChangeEvent(msg.toCommon());
logger.info("Sending messageStatusChangeEvent " + evt);
writeProxy.write(socketID, evt);
}
} else writeProxy.write(socketID, new MessageStatusChange(msgCommon));
}
}
@Override
public Class<LoginCredentials> getInputClass() { return LoginCredentials.class; }
private envoy.server.data.User getUser(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException {
return credentials.isRegistration() ? newUser(credentials, socketID, writeProxy) : checkForExistingUser(credentials, socketID, writeProxy);
}
/**
* @param credentials the input to evaluate
* @param socketID the socket ID at which the client performing the handshake
* is connected
* @param writeProxy the {@link ObjectWriteProxy} to use if login was not
* successful
* @return the database user matching the login credentials
* @throws IOException if sending the failed login back to the client failed
* @since Envoy Server Standalone v0.1-alpha
*/
private envoy.server.data.User checkForExistingUser(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException {
try {
envoy.server.data.User user = persistenceManager.getUserByName(credentials.getIdentifier());
// Checking if user is already online
if (connectionManager.isOnline(user.getID())) {
writeProxy.write(socketID, new HandshakeRejectionEvent(HandshakeRejectionEvent.INTERNAL_ERROR));
return null;
}
// Evaluating the correctness of the password hash
if (!Arrays.equals(credentials.getPasswordHash(), user.getPasswordHash())) {
writeProxy.write(socketID, new HandshakeRejectionEvent(HandshakeRejectionEvent.WRONG_PASSWORD_OR_USER));
return null;
}
return user;
} catch (NoResultException e) {
// Checking if user exists
writeProxy.write(socketID, new HandshakeRejectionEvent(HandshakeRejectionEvent.INTERNAL_ERROR));
} catch (InputMismatchException e) {
// Checking if the given password hash is correct
writeProxy.write(socketID, new HandshakeRejectionEvent(HandshakeRejectionEvent.WRONG_PASSWORD_OR_USER));
}
return null;
}
/**
* @param credentials the credentials upon which to create the new {@link User}
* @param socketID the socketID at which the client performing the handshake
* is connected
* @param writeProxy the write proxy used to notify the client about handshake
* rejection
* @return the newly created {@link User}
* @throws IOException if sending the failed login back to the client failed
* @since Envoy Server Standalone v0.1-alpha
*/
private envoy.server.data.User newUser(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException {
try {
// Checking that no user already has this identifier
PersistenceManager.getInstance().getUserByName(credentials.getIdentifier());
// this code only gets executed if this user already exists
writeProxy.write(socketID, new HandshakeRejectionEvent(HandshakeRejectionEvent.INTERNAL_ERROR));
return null;
} catch (NoResultException e) {
// Creation of a new user
envoy.server.data.User user;
user = new envoy.server.data.User();
user.setName(credentials.getIdentifier());
user.setLastSeen(new Date());
user.setStatus(User.UserStatus.ONLINE);
user.setPasswordHash(credentials.getPasswordHash());
user.setContacts(new HashSet<>());
persistenceManager.addContact(user);
return user;
}
}
}