Apply suggestions from code review
This commit is contained in:
		
							
								
								
									
										94
									
								
								src/main/java/enovy/server/util/VersionUtils.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								src/main/java/enovy/server/util/VersionUtils.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,94 @@ | ||||
| package enovy.server.util; | ||||
|  | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| /** | ||||
|  * Implements a comparison algorithm between Envoy versions and defines minimal | ||||
|  * and maximal client versions compatible with this server. | ||||
|  * <p> | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>VersionUtils.java</strong><br> | ||||
|  * Created: <strong>23.06.2020</strong><br> | ||||
|  *  | ||||
|  * @author KSKE | ||||
|  * @since Envoy Server Standalone v0.1-beta | ||||
|  */ | ||||
| public class VersionUtils { | ||||
|  | ||||
| 	/** | ||||
| 	 * The minimal client version compatible with this server. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static final String MIN_CLIENT_VERSION = "0.1-beta"; | ||||
|  | ||||
| 	/** | ||||
| 	 * The maximal client version compatible with this server. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static final String MAX_CLIENT_VERSION = "0.1-beta"; | ||||
|  | ||||
| 	private static final Pattern versionPattern = Pattern.compile("(?<major>\\d).(?<minor>\\d)(?:-(?<suffix>\\w+))?"); | ||||
|  | ||||
| 	private VersionUtils() {} | ||||
|  | ||||
| 	/** | ||||
| 	 * Parses an Envoy Client version string and checks whether that version is | ||||
| 	 * compatible with this server. | ||||
| 	 *  | ||||
| 	 * @param version the version string to parse | ||||
| 	 * @return {@code true} if the given version is compatible with this server | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static boolean verifyCompatibility(String version) { | ||||
| 		final var currentMatcher = versionPattern.matcher(version); | ||||
|  | ||||
| 		if (!currentMatcher.matches()) return false; | ||||
|  | ||||
| 		final var	minMatcher	= versionPattern.matcher(MIN_CLIENT_VERSION); | ||||
| 		final var	maxMatcher	= versionPattern.matcher(MAX_CLIENT_VERSION); | ||||
|  | ||||
| 		if (!minMatcher.matches() || !maxMatcher.matches()) throw new RuntimeException("Invalid min or max client version configured!"); | ||||
|  | ||||
| 		// Compare suffixes | ||||
| 		{ | ||||
| 			final var	currentSuffix	= convertSuffix(currentMatcher.group("suffix")); | ||||
| 			final var	minSuffix		= convertSuffix(minMatcher.group("suffix")); | ||||
| 			final var	maxSuffix		= convertSuffix(maxMatcher.group("suffix")); | ||||
|  | ||||
| 			if (currentSuffix < minSuffix || currentSuffix > maxSuffix) return false; | ||||
| 		} | ||||
|  | ||||
| 		// Compare major | ||||
| 		{ | ||||
| 			final var	currentMajor	= Integer.parseInt(currentMatcher.group("major")); | ||||
| 			final var	minMajor		= Integer.parseInt(minMatcher.group("major")); | ||||
| 			final var	maxMajor		= Integer.parseInt(maxMatcher.group("major")); | ||||
|  | ||||
| 			if (currentMajor < minMajor || currentMajor > maxMajor) return false; | ||||
| 		} | ||||
|  | ||||
| 		// Compare minor | ||||
| 		{ | ||||
| 			final var	currentMinor	= Integer.parseInt(currentMatcher.group("minor")); | ||||
| 			final var	minMinor		= Integer.parseInt(minMatcher.group("minor")); | ||||
| 			final var	maxMinor		= Integer.parseInt(maxMatcher.group("minor")); | ||||
|  | ||||
| 			if (currentMinor < minMinor || currentMinor > maxMinor) return false; | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	private static int convertSuffix(String suffix) { | ||||
| 		switch (suffix == null ? "" : suffix) { | ||||
| 			case "alpha": | ||||
| 				return 0; | ||||
| 			case "beta": | ||||
| 				return 1; | ||||
| 			default: | ||||
| 				return 2; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										11
									
								
								src/main/java/enovy/server/util/package-info.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/main/java/enovy/server/util/package-info.java
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| /** | ||||
|  * This package contains utility classes used in Envoy Server. | ||||
|  * <p> | ||||
|  * Project: <strong>envoy-server-standalone</strong><br> | ||||
|  * File: <strong>package-info.java</strong><br> | ||||
|  * Created: <strong>23.06.2020</strong><br> | ||||
|  *  | ||||
|  * @author Kai S. K. Engelbart | ||||
|  * @since Envoy Server Standalone v0.1-beta | ||||
|  */ | ||||
| package enovy.server.util; | ||||
| @@ -29,20 +29,6 @@ import envoy.util.EnvoyLog; | ||||
|  */ | ||||
| public class Startup { | ||||
|  | ||||
| 	/** | ||||
| 	 * The minimal client version compatible with this server. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static final String	MIN_CLIENT_VERSION	= "0.1-beta"; | ||||
|  | ||||
| 	/** | ||||
| 	 * The maximal client version compatible with this server. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static final String	MAX_CLIENT_VERSION	= "0.1-beta"; | ||||
|  | ||||
| 	/** | ||||
| 	 * Initializes the logger with a new config instance. | ||||
| 	 *  | ||||
|   | ||||
| @@ -1,5 +1,7 @@ | ||||
| package envoy.server.data; | ||||
|  | ||||
| import static envoy.data.Message.MessageStatus.*; | ||||
|  | ||||
| import java.time.LocalDateTime; | ||||
|  | ||||
| import javax.persistence.*; | ||||
| @@ -38,7 +40,7 @@ public class Message { | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public static final String getPending = "Message.getPending"; | ||||
| 	 | ||||
|  | ||||
| 	@Id | ||||
| 	protected long id; | ||||
|  | ||||
| @@ -111,9 +113,26 @@ public class Message { | ||||
| 		return message; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the message status to {@link MessageStatus#RECEIVED} and sets the | ||||
| 	 * current time stamp as the received date. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public void received() { | ||||
| 		receivedDate	= LocalDateTime.now(); | ||||
| 		status			= MessageStatus.RECEIVED; | ||||
| 		status			= RECEIVED; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
| 	 * Sets the message status to {@link MessageStatus#READ} and sets the | ||||
| 	 * current time stamp as the read date. | ||||
| 	 *  | ||||
| 	 * @since Envoy Server Standalone v0.1-beta | ||||
| 	 */ | ||||
| 	public void read() { | ||||
| 		readDate	= LocalDateTime.now(); | ||||
| 		status		= READ; | ||||
| 	} | ||||
|  | ||||
| 	/** | ||||
|   | ||||
| @@ -8,15 +8,14 @@ import java.time.LocalDateTime; | ||||
| import java.util.Arrays; | ||||
| import java.util.HashSet; | ||||
| import java.util.logging.Logger; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| import javax.persistence.NoResultException; | ||||
|  | ||||
| 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.Startup; | ||||
| import envoy.server.data.PersistenceManager; | ||||
| import envoy.server.data.User; | ||||
| import envoy.server.net.ConnectionManager; | ||||
| @@ -40,7 +39,6 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred | ||||
| 	private final ConnectionManager		connectionManager	= ConnectionManager.getInstance(); | ||||
|  | ||||
| 	private static final Logger		logger			= EnvoyLog.getLogger(LoginCredentialProcessor.class); | ||||
| 	private static final Pattern	versionPattern	= Pattern.compile("(?<major>\\d).(?<minor>\\d)(?:-(?<suffix>\\w+))?"); | ||||
|  | ||||
| 	@Override | ||||
| 	public void process(LoginCredentials credentials, long socketID, ObjectWriteProxy writeProxy) throws IOException { | ||||
| @@ -48,10 +46,9 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred | ||||
| 		// Cache this write proxy for user-independant notifications | ||||
| 		UserStatusChangeProcessor.setWriteProxy(writeProxy); | ||||
|  | ||||
| 		// TODO: Verify compatibility | ||||
| 		if (!verifyCompatibility(credentials.getClientVersion())) { | ||||
| 		if (!VersionUtils.verifyCompatibility(credentials.getClientVersion())) { | ||||
| 			logger.info("The client has the wrong version."); | ||||
| 			writeProxy.write(socketID, new HandshakeRejection("Wrong version")); | ||||
| 			writeProxy.write(socketID, new HandshakeRejection(WRONG_VERSION)); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| @@ -85,7 +82,7 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred | ||||
|  | ||||
| 				// This code only gets executed if this user already exists | ||||
| 				logger.info("The requested user already exists."); | ||||
| 				writeProxy.write(socketID, new HandshakeRejection(INTERNAL_ERROR)); | ||||
| 				writeProxy.write(socketID, new HandshakeRejection(USERNAME_TAKEN)); | ||||
| 				return; | ||||
| 			} catch (NoResultException e) { | ||||
| 				// Creation of a new user | ||||
| @@ -101,7 +98,6 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred | ||||
| 		} | ||||
|  | ||||
| 		logger.info(user + " successfully authenticated."); | ||||
|  | ||||
| 		connectionManager.registerUser(user.getID(), socketID); | ||||
|  | ||||
| 		// Change status and notify contacts about it | ||||
| @@ -125,57 +121,6 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	private boolean verifyCompatibility(String version) { | ||||
| 		final var currentMatcher = versionPattern.matcher(version); | ||||
|  | ||||
| 		if (!currentMatcher.matches()) return false; | ||||
|  | ||||
| 		final var	minMatcher	= versionPattern.matcher(Startup.MIN_CLIENT_VERSION); | ||||
| 		final var	maxMatcher	= versionPattern.matcher(Startup.MAX_CLIENT_VERSION); | ||||
|  | ||||
| 		if (!minMatcher.matches() || !maxMatcher.matches()) throw new RuntimeException("Invalid min or max client version configured!"); | ||||
|  | ||||
| 		// Compare suffixes | ||||
| 		{ | ||||
| 			final var	currentSuffix	= convertSuffix(currentMatcher.group("suffix")); | ||||
| 			final var	minSuffix		= convertSuffix(minMatcher.group("suffix")); | ||||
| 			final var	maxSuffix		= convertSuffix(maxMatcher.group("suffix")); | ||||
|  | ||||
| 			if (currentSuffix < minSuffix || currentSuffix > maxSuffix) return false; | ||||
| 		} | ||||
|  | ||||
| 		// Compare major | ||||
| 		{ | ||||
| 			final var	currentMajor	= Integer.parseInt(currentMatcher.group("major")); | ||||
| 			final var	minMajor		= Integer.parseInt(minMatcher.group("major")); | ||||
| 			final var	maxMajor		= Integer.parseInt(maxMatcher.group("major")); | ||||
|  | ||||
| 			if (currentMajor < minMajor || currentMajor > maxMajor) return false; | ||||
| 		} | ||||
|  | ||||
| 		// Compare minor | ||||
| 		{ | ||||
| 			final var	currentMinor	= Integer.parseInt(currentMatcher.group("minor")); | ||||
| 			final var	minMinor		= Integer.parseInt(minMatcher.group("minor")); | ||||
| 			final var	maxMinor		= Integer.parseInt(maxMatcher.group("minor")); | ||||
|  | ||||
| 			if (currentMinor < minMinor || currentMinor > maxMinor) return false; | ||||
| 		} | ||||
|  | ||||
| 		return true; | ||||
| 	} | ||||
|  | ||||
| 	private int convertSuffix(String suffix) { | ||||
| 		switch (suffix == null ? "" : suffix) { | ||||
| 			case "alpha": | ||||
| 				return 0; | ||||
| 			case "beta": | ||||
| 				return 1; | ||||
| 			default: | ||||
| 				return 2; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	@Override | ||||
| 	public Class<LoginCredentials> getInputClass() { return LoginCredentials.class; } | ||||
| } | ||||
|   | ||||
| @@ -35,7 +35,7 @@ public class MessageProcessor implements ObjectProcessor<Message> { | ||||
| 			return; | ||||
| 		} | ||||
| 		message.nextStatus(); | ||||
| 		ConnectionManager	connectionManager	= ConnectionManager.getInstance(); | ||||
| 		ConnectionManager connectionManager = ConnectionManager.getInstance(); | ||||
|  | ||||
| 		sendToUser(connectionManager, message, writeProxy); | ||||
| 		try { | ||||
|   | ||||
| @@ -28,8 +28,7 @@ public class MessageStatusChangeProcessor implements ObjectProcessor<MessageStat | ||||
| 		if (statusChange.get() != MessageStatus.READ) throw new IOException(new EnvoyException(statusChange + " has an invalid status")); | ||||
|  | ||||
| 		final var msg = persistenceManager.getMessageByID(statusChange.getID()); | ||||
| 		msg.setStatus(statusChange.get()); | ||||
| 		msg.setReadDate(statusChange.getDate()); | ||||
| 		msg.read(); | ||||
| 		persistenceManager.updateMessage(msg); | ||||
|  | ||||
| 		// Notifies the sender of the message about the status-update to READ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user