Merge pull request 'Made Server Less Error Prone' (#107) from f/secure-server into develop
Reviewed-on: https://git.kske.dev/zdm/envoy/pulls/107 Reviewed-by: kske <kai@kske.dev>
This commit is contained in:
commit
f6c772a655
@ -21,7 +21,6 @@
|
|||||||
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-11">
|
||||||
<attributes>
|
<attributes>
|
||||||
<attribute name="maven.pomderived" value="true"/>
|
<attribute name="maven.pomderived" value="true"/>
|
||||||
<attribute name="module" value="true"/>
|
|
||||||
</attributes>
|
</attributes>
|
||||||
</classpathentry>
|
</classpathentry>
|
||||||
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
|
||||||
|
@ -586,7 +586,7 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
// IsTyping#millisecondsActive
|
// IsTyping#millisecondsActive
|
||||||
if (client.isOnline() && currentChat.getLastWritingEvent()
|
if (client.isOnline() && currentChat.getLastWritingEvent()
|
||||||
+ IsTyping.millisecondsActive <= System.currentTimeMillis()) {
|
+ IsTyping.millisecondsActive <= System.currentTimeMillis()) {
|
||||||
client.send(new IsTyping(getChatID(), currentChat.getRecipient().getID()));
|
client.send(new IsTyping(currentChat.getRecipient().getID()));
|
||||||
currentChat.lastWritingEventWasNow();
|
currentChat.lastWritingEventWasNow();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -600,19 +600,6 @@ public final class ChatScene implements EventListener, Restorable {
|
|||||||
checkPostConditions(false);
|
checkPostConditions(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the id that should be used to send things to the server: the id of 'our' {@link User}
|
|
||||||
* if the recipient of that object is another User, else the id of the {@link Group} 'our' user
|
|
||||||
* is sending to.
|
|
||||||
*
|
|
||||||
* @return an id that can be sent to the server
|
|
||||||
* @since Envoy Client v0.2-beta
|
|
||||||
*/
|
|
||||||
private long getChatID() {
|
|
||||||
return currentChat.getRecipient() instanceof User ? client.getSender().getID()
|
|
||||||
: currentChat.getRecipient().getID();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param e the keys that have been pressed
|
* @param e the keys that have been pressed
|
||||||
* @since Envoy Client v0.1-beta
|
* @since Envoy Client v0.1-beta
|
||||||
|
@ -137,7 +137,7 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
|
|||||||
|
|
||||||
// Displaying the save button
|
// Displaying the save button
|
||||||
saveButton
|
saveButton
|
||||||
.setOnAction(e -> save(client.getSender().getID(), currentPasswordField.getText()));
|
.setOnAction(e -> save(currentPasswordField.getText()));
|
||||||
saveButton.setAlignment(Pos.BOTTOM_RIGHT);
|
saveButton.setAlignment(Pos.BOTTOM_RIGHT);
|
||||||
getChildren().add(saveButton);
|
getChildren().add(saveButton);
|
||||||
}
|
}
|
||||||
@ -148,11 +148,11 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
|
|||||||
* @param username the new username
|
* @param username the new username
|
||||||
* @since Envoy Client v0.2-beta
|
* @since Envoy Client v0.2-beta
|
||||||
*/
|
*/
|
||||||
private void save(long userID, String oldPassword) {
|
private void save(String oldPassword) {
|
||||||
|
|
||||||
// The profile pic was changed
|
// The profile pic was changed
|
||||||
if (profilePicChanged) {
|
if (profilePicChanged) {
|
||||||
final var profilePicChangeEvent = new ProfilePicChange(currentImageBytes, userID);
|
final var profilePicChangeEvent = new ProfilePicChange(currentImageBytes);
|
||||||
eventBus.dispatch(profilePicChangeEvent);
|
eventBus.dispatch(profilePicChangeEvent);
|
||||||
client.send(profilePicChangeEvent);
|
client.send(profilePicChangeEvent);
|
||||||
logger.log(Level.INFO, "The user just changed his profile pic.");
|
logger.log(Level.INFO, "The user just changed his profile pic.");
|
||||||
@ -161,7 +161,7 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
|
|||||||
// The username was changed
|
// The username was changed
|
||||||
final var validContactName = Bounds.isValidContactName(newUsername);
|
final var validContactName = Bounds.isValidContactName(newUsername);
|
||||||
if (usernameChanged && validContactName) {
|
if (usernameChanged && validContactName) {
|
||||||
final var nameChangeEvent = new NameChange(userID, newUsername);
|
final var nameChangeEvent = new NameChange(client.getSender().getID(), newUsername);
|
||||||
eventBus.dispatch(nameChangeEvent);
|
eventBus.dispatch(nameChangeEvent);
|
||||||
client.send(nameChangeEvent);
|
client.send(nameChangeEvent);
|
||||||
logger.log(Level.INFO, "The user just changed his name to " + newUsername + ".");
|
logger.log(Level.INFO, "The user just changed his name to " + newUsername + ".");
|
||||||
@ -178,7 +178,7 @@ public final class UserSettingsPane extends OnlineOnlySettingsPane {
|
|||||||
|
|
||||||
// The password was changed
|
// The password was changed
|
||||||
if (validPassword) {
|
if (validPassword) {
|
||||||
client.send(new PasswordChangeRequest(newPassword, oldPassword, userID));
|
client.send(new PasswordChangeRequest(newPassword, oldPassword));
|
||||||
logger.log(Level.INFO, "The user just tried to change his password!");
|
logger.log(Level.INFO, "The user just tried to change his password!");
|
||||||
} else if (!(validPassword || newPassword.isBlank())) {
|
} else if (!(validPassword || newPassword.isBlank())) {
|
||||||
final var alert = new Alert(AlertType.ERROR);
|
final var alert = new Alert(AlertType.ERROR);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package envoy.data;
|
package envoy.data;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface should be used for any type supposed to be a {@link Message} attachment (i.e.
|
* This interface should be used for any type supposed to be a {@link Message} attachment (i.e.
|
||||||
@ -63,9 +64,9 @@ public final class Attachment implements Serializable {
|
|||||||
* @since Envoy Common v0.1-beta
|
* @since Envoy Common v0.1-beta
|
||||||
*/
|
*/
|
||||||
public Attachment(byte[] data, String name, AttachmentType type) {
|
public Attachment(byte[] data, String name, AttachmentType type) {
|
||||||
this.data = data;
|
this.data = Objects.requireNonNull(data);
|
||||||
this.name = name;
|
this.name = Objects.requireNonNull(name);
|
||||||
this.type = type;
|
this.type = Objects.requireNonNull(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,8 +29,8 @@ public abstract class Contact implements Serializable {
|
|||||||
*/
|
*/
|
||||||
public Contact(long id, String name, Set<? extends Contact> contacts) {
|
public Contact(long id, String name, Set<? extends Contact> contacts) {
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.name = name;
|
this.name = Objects.requireNonNull(name);
|
||||||
this.contacts = contacts;
|
this.contacts = contacts == null ? new HashSet<>() : contacts;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +38,8 @@ public final class GroupMessage extends Message {
|
|||||||
Map<Long, MessageStatus> memberStatuses) {
|
Map<Long, MessageStatus> memberStatuses) {
|
||||||
super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status,
|
super(id, senderID, groupID, creationDate, receivedDate, readDate, text, attachment, status,
|
||||||
forwarded);
|
forwarded);
|
||||||
this.memberStatuses = memberStatuses;
|
this.memberStatuses =
|
||||||
|
memberStatuses == null ? new HashMap<>() : memberStatuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2,6 +2,7 @@ package envoy.data;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains a {@link User}'s login / registration information as well as the client version.
|
* Contains a {@link User}'s login / registration information as well as the client version.
|
||||||
@ -20,15 +21,14 @@ public final class LoginCredentials implements Serializable {
|
|||||||
private static final long serialVersionUID = 4;
|
private static final long serialVersionUID = 4;
|
||||||
|
|
||||||
private LoginCredentials(String identifier, String password, boolean registration,
|
private LoginCredentials(String identifier, String password, boolean registration,
|
||||||
boolean token, boolean requestToken, String clientVersion,
|
boolean token, boolean requestToken, String clientVersion, Instant lastSync) {
|
||||||
Instant lastSync) {
|
this.identifier = Objects.requireNonNull(identifier);
|
||||||
this.identifier = identifier;
|
this.password = Objects.requireNonNull(password);
|
||||||
this.password = password;
|
|
||||||
this.registration = registration;
|
this.registration = registration;
|
||||||
this.token = token;
|
this.token = token;
|
||||||
this.requestToken = requestToken;
|
this.requestToken = requestToken;
|
||||||
this.clientVersion = clientVersion;
|
this.clientVersion = Objects.requireNonNull(clientVersion);
|
||||||
this.lastSync = lastSync;
|
this.lastSync = lastSync == null ? Instant.EPOCH : lastSync;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -75,7 +75,8 @@ public final class LoginCredentials implements Serializable {
|
|||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
*/
|
*/
|
||||||
public static LoginCredentials registration(String identifier, String password,
|
public static LoginCredentials registration(String identifier, String password,
|
||||||
boolean requestToken, String clientVersion, Instant lastSync) {
|
boolean requestToken,
|
||||||
|
String clientVersion, Instant lastSync) {
|
||||||
return new LoginCredentials(identifier, password, true, false, requestToken, clientVersion,
|
return new LoginCredentials(identifier, password, true, false, requestToken, clientVersion,
|
||||||
lastSync);
|
lastSync);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package envoy.data;
|
|||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import dev.kske.eventbus.IEvent;
|
import dev.kske.eventbus.IEvent;
|
||||||
|
|
||||||
@ -80,9 +81,9 @@ public class Message implements Serializable, IEvent {
|
|||||||
this.creationDate = creationDate;
|
this.creationDate = creationDate;
|
||||||
this.receivedDate = receivedDate;
|
this.receivedDate = receivedDate;
|
||||||
this.readDate = readDate;
|
this.readDate = readDate;
|
||||||
this.text = text;
|
this.text = text == null ? "" : text;
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
this.status = status;
|
this.status = Objects.requireNonNull(status);
|
||||||
this.forwarded = forwarded;
|
this.forwarded = forwarded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +86,7 @@ public final class User extends Contact {
|
|||||||
*/
|
*/
|
||||||
public User(long id, String name, UserStatus status, Set<Contact> contacts) {
|
public User(long id, String name, UserStatus status, Set<Contact> contacts) {
|
||||||
super(id, name, contacts);
|
super(id, name, contacts);
|
||||||
this.status = status;
|
this.status = Objects.requireNonNull(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package envoy.event;
|
package envoy.event;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import dev.kske.eventbus.IEvent;
|
import dev.kske.eventbus.IEvent;
|
||||||
|
|
||||||
@ -20,7 +21,16 @@ public abstract class Event<T> implements IEvent, Serializable {
|
|||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
protected Event(T value) {
|
protected Event(T value) {
|
||||||
this.value = value;
|
this(value, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This constructor is reserved for {@link Valueless} events. No other event should contain null
|
||||||
|
* values. Only use if really necessary. Using this constructor with {@code true} implies that
|
||||||
|
* the user has to manually check if the value of the event is null.
|
||||||
|
*/
|
||||||
|
protected Event(T value, boolean canBeNull) {
|
||||||
|
this.value = canBeNull ? value : Objects.requireNonNull(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,7 +56,7 @@ public abstract class Event<T> implements IEvent, Serializable {
|
|||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
protected Valueless() {
|
protected Valueless() {
|
||||||
super(null);
|
super(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -20,7 +20,7 @@ public class GroupCreationResult extends Event<Group> {
|
|||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
*/
|
*/
|
||||||
public GroupCreationResult() {
|
public GroupCreationResult() {
|
||||||
super(null);
|
super(null, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,7 +30,7 @@ public final class GroupMessageStatusChange extends MessageStatusChange {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the memberID which the user who sends this event has
|
* @return the ID of the sender of this event
|
||||||
* @since Envoy Common v0.1-beta
|
* @since Envoy Common v0.1-beta
|
||||||
*/
|
*/
|
||||||
public long getMemberID() { return memberID; }
|
public long getMemberID() { return memberID; }
|
||||||
|
@ -2,6 +2,8 @@ package envoy.event;
|
|||||||
|
|
||||||
import static envoy.event.ElementOperation.*;
|
import static envoy.event.ElementOperation.*;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import envoy.data.*;
|
import envoy.data.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +32,7 @@ public final class GroupResize extends Event<User> {
|
|||||||
*/
|
*/
|
||||||
public GroupResize(User user, Group group, ElementOperation operation) {
|
public GroupResize(User user, Group group, ElementOperation operation) {
|
||||||
super(user);
|
super(user);
|
||||||
this.operation = operation;
|
this.operation = Objects.requireNonNull(operation);
|
||||||
final var contained = group.getContacts().contains(user);
|
final var contained = group.getContacts().contains(user);
|
||||||
if (contained && operation.equals(ADD))
|
if (contained && operation.equals(ADD))
|
||||||
throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group));
|
throw new IllegalArgumentException(String.format("Cannot add %s to %s!", user, group));
|
||||||
|
@ -8,8 +8,6 @@ package envoy.event;
|
|||||||
*/
|
*/
|
||||||
public final class IsTyping extends Event<Long> {
|
public final class IsTyping extends Event<Long> {
|
||||||
|
|
||||||
private final long destinationID;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -22,20 +20,13 @@ public final class IsTyping extends Event<Long> {
|
|||||||
public static final int millisecondsActive = 3500;
|
public static final int millisecondsActive = 3500;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new {@code IsTyping} event with originator and recipient.
|
* Creates a new {@code IsTyping}. The client will only send the contact that should receive
|
||||||
|
* this event. The server will send the id of the contact who sent this event.
|
||||||
*
|
*
|
||||||
* @param sourceID the ID of the originator
|
* @param id the ID of the recipient (client)/ originator(server)
|
||||||
* @param destinationID the ID of the contact the user wrote to
|
|
||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
*/
|
*/
|
||||||
public IsTyping(Long sourceID, long destinationID) {
|
public IsTyping(long id) {
|
||||||
super(sourceID);
|
super(id);
|
||||||
this.destinationID = destinationID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the ID of the contact in whose chat the user typed something
|
|
||||||
* @since Envoy Common v0.2-beta
|
|
||||||
*/
|
|
||||||
public long getDestinationID() { return destinationID; }
|
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ public final class IssueProposal extends Event<String> {
|
|||||||
*/
|
*/
|
||||||
public IssueProposal(String title, String description, boolean isBug) {
|
public IssueProposal(String title, String description, boolean isBug) {
|
||||||
super(escape(title));
|
super(escape(title));
|
||||||
this.description = sanitizeDescription(description);
|
this.description = description == null ? "" : sanitizeDescription(description);
|
||||||
bug = isBug;
|
bug = isBug;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,8 +37,8 @@ public final class IssueProposal extends Event<String> {
|
|||||||
*/
|
*/
|
||||||
public IssueProposal(String title, String description, String user, boolean isBug) {
|
public IssueProposal(String title, String description, String user, boolean isBug) {
|
||||||
super(escape(title));
|
super(escape(title));
|
||||||
this.description =
|
this.description = description == null ? ""
|
||||||
sanitizeDescription(description) + String.format("<br>Submitted by user %s.", user);
|
: sanitizeDescription(description) + String.format("<br>Submitted by user %s.", user);
|
||||||
bug = isBug;
|
bug = isBug;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package envoy.event;
|
package envoy.event;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import envoy.data.Message;
|
import envoy.data.Message;
|
||||||
|
|
||||||
@ -26,7 +27,7 @@ public class MessageStatusChange extends Event<Message.MessageStatus> {
|
|||||||
public MessageStatusChange(long id, Message.MessageStatus status, Instant date) {
|
public MessageStatusChange(long id, Message.MessageStatus status, Instant date) {
|
||||||
super(status);
|
super(status);
|
||||||
this.id = id;
|
this.id = id;
|
||||||
this.date = date;
|
this.date = Objects.requireNonNull(date);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package envoy.event;
|
package envoy.event;
|
||||||
|
|
||||||
import envoy.data.Contact;
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Leon Hofmeister
|
* @author Leon Hofmeister
|
||||||
@ -8,29 +8,20 @@ import envoy.data.Contact;
|
|||||||
*/
|
*/
|
||||||
public final class PasswordChangeRequest extends Event<String> {
|
public final class PasswordChangeRequest extends Event<String> {
|
||||||
|
|
||||||
private final long id;
|
private final String oldPassword;
|
||||||
private final String oldPassword;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param newPassword the new password of that user
|
* @param newPassword the new password of that user
|
||||||
* @param oldPassword the old password of that user
|
* @param oldPassword the old password of that user
|
||||||
* @param userID the ID of the user who wants to change his password
|
|
||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
*/
|
*/
|
||||||
public PasswordChangeRequest(String newPassword, String oldPassword, long userID) {
|
public PasswordChangeRequest(String newPassword, String oldPassword) {
|
||||||
super(newPassword);
|
super(newPassword);
|
||||||
this.oldPassword = oldPassword;
|
this.oldPassword = Objects.requireNonNull(oldPassword);
|
||||||
id = userID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the ID of the {@link Contact} this event is related to
|
|
||||||
* @since Envoy Common v0.2-alpha
|
|
||||||
*/
|
|
||||||
public long getID() { return id; }
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return the old password of the underlying user
|
* @return the old password of the underlying user
|
||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
@ -39,6 +30,6 @@ public final class PasswordChangeRequest extends Event<String> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "PasswordChangeRequest[id=" + id + "]";
|
return "PasswordChangeRequest[]";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,23 +6,13 @@ package envoy.event;
|
|||||||
*/
|
*/
|
||||||
public final class ProfilePicChange extends Event<byte[]> {
|
public final class ProfilePicChange extends Event<byte[]> {
|
||||||
|
|
||||||
private final long id;
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 0L;
|
private static final long serialVersionUID = 0L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param value the byte[] of the new image
|
* @param value the byte[] of the new image
|
||||||
* @param userID the ID of the user who changed his profile pic
|
|
||||||
* @since Envoy Common v0.2-beta
|
* @since Envoy Common v0.2-beta
|
||||||
*/
|
*/
|
||||||
public ProfilePicChange(byte[] value, long userID) {
|
public ProfilePicChange(byte[] value) {
|
||||||
super(value);
|
super(value);
|
||||||
id = userID;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return the ID of the user changing his profile pic
|
|
||||||
* @since Envoy Common v0.2-beta
|
|
||||||
*/
|
|
||||||
public long getId() { return id; }
|
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package envoy.event.contact;
|
package envoy.event.contact;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import envoy.data.User;
|
import envoy.data.User;
|
||||||
import envoy.event.*;
|
import envoy.event.*;
|
||||||
|
|
||||||
@ -24,7 +26,7 @@ public final class UserOperation extends Event<User> {
|
|||||||
*/
|
*/
|
||||||
public UserOperation(User contact, ElementOperation operationType) {
|
public UserOperation(User contact, ElementOperation operationType) {
|
||||||
super(contact);
|
super(contact);
|
||||||
this.operationType = operationType;
|
this.operationType = Objects.requireNonNull(operationType);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package envoy.server.data;
|
package envoy.server.data;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.List;
|
import java.util.*;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
@ -223,6 +223,9 @@ public final class PersistenceManager {
|
|||||||
* @since Envoy Server Standalone v0.2-beta
|
* @since Envoy Server Standalone v0.2-beta
|
||||||
*/
|
*/
|
||||||
public List<Message> getPendingMessages(User user, Instant lastSync) {
|
public List<Message> getPendingMessages(User user, Instant lastSync) {
|
||||||
|
if (user == null)
|
||||||
|
return new ArrayList<>();
|
||||||
|
lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH);
|
||||||
return entityManager.createNamedQuery(Message.getPending).setParameter("user", user)
|
return entityManager.createNamedQuery(Message.getPending).setParameter("user", user)
|
||||||
.setParameter("lastSeen", lastSync).getResultList();
|
.setParameter("lastSeen", lastSync).getResultList();
|
||||||
}
|
}
|
||||||
@ -236,6 +239,9 @@ public final class PersistenceManager {
|
|||||||
* @since Envoy Server Standalone v0.2-beta
|
* @since Envoy Server Standalone v0.2-beta
|
||||||
*/
|
*/
|
||||||
public List<GroupMessage> getPendingGroupMessages(User user, Instant lastSync) {
|
public List<GroupMessage> getPendingGroupMessages(User user, Instant lastSync) {
|
||||||
|
if (user == null)
|
||||||
|
return new ArrayList<>();
|
||||||
|
lastSync = Objects.requireNonNullElse(lastSync, Instant.EPOCH);
|
||||||
return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg)
|
return entityManager.createNamedQuery(GroupMessage.getPendingGroupMsg)
|
||||||
.setParameter("userId", user.getID())
|
.setParameter("userId", user.getID())
|
||||||
.setParameter("lastSeen", lastSync)
|
.setParameter("lastSeen", lastSync)
|
||||||
@ -277,16 +283,18 @@ public final class PersistenceManager {
|
|||||||
* @since Envoy Server v0.3-beta
|
* @since Envoy Server v0.3-beta
|
||||||
*/
|
*/
|
||||||
public void addContactBidirectional(Contact contact1, Contact contact2) {
|
public void addContactBidirectional(Contact contact1, Contact contact2) {
|
||||||
|
if (!(contact1 == null || contact2 == null)) {
|
||||||
|
|
||||||
// Add users to each others contact list
|
// Add users to each others contact list
|
||||||
contact1.getContacts().add(contact2);
|
contact1.getContacts().add(contact2);
|
||||||
contact2.getContacts().add(contact1);
|
contact2.getContacts().add(contact1);
|
||||||
|
|
||||||
// Synchronize changes with the database
|
// Synchronize changes with the database
|
||||||
transaction(() -> {
|
transaction(() -> {
|
||||||
entityManager.merge(contact1);
|
entityManager.merge(contact1);
|
||||||
entityManager.merge(contact2);
|
entityManager.merge(contact2);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -308,16 +316,18 @@ public final class PersistenceManager {
|
|||||||
* @since Envoy Server v0.3-beta
|
* @since Envoy Server v0.3-beta
|
||||||
*/
|
*/
|
||||||
public void removeContactBidirectional(Contact contact1, Contact contact2) {
|
public void removeContactBidirectional(Contact contact1, Contact contact2) {
|
||||||
|
if (!(contact1 == null || contact2 == null)) {
|
||||||
|
|
||||||
// Remove users from each others contact list
|
// Remove users from each others contact list
|
||||||
contact1.getContacts().remove(contact2);
|
contact1.getContacts().remove(contact2);
|
||||||
contact2.getContacts().remove(contact1);
|
contact2.getContacts().remove(contact1);
|
||||||
|
|
||||||
// Synchronize changes with the database
|
// Synchronize changes with the database
|
||||||
transaction(() -> {
|
transaction(() -> {
|
||||||
entityManager.merge(contact1);
|
entityManager.merge(contact1);
|
||||||
entityManager.merge(contact2);
|
entityManager.merge(contact2);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -331,15 +341,36 @@ public final class PersistenceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void persist(Object obj) {
|
private void persist(Object obj) {
|
||||||
transaction(() -> entityManager.persist(obj));
|
try {
|
||||||
|
transaction(() -> entityManager.persist(obj));
|
||||||
|
} catch (EntityExistsException e) {
|
||||||
|
if (transaction.isActive())
|
||||||
|
transaction.rollback();
|
||||||
|
EnvoyLog.getLogger(PersistenceManager.class).log(Level.WARNING,
|
||||||
|
String.format("Could not persist %s: entity exists already.", obj));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void merge(Object obj) {
|
private void merge(Object obj) {
|
||||||
transaction(() -> entityManager.merge(obj));
|
try {
|
||||||
|
transaction(() -> entityManager.merge(obj));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
if (transaction.isActive())
|
||||||
|
transaction.rollback();
|
||||||
|
EnvoyLog.getLogger(PersistenceManager.class).log(Level.WARNING,
|
||||||
|
String.format("Could not merge %s: entity doesn't exist.", obj));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void remove(Object obj) {
|
private void remove(Object obj) {
|
||||||
transaction(() -> entityManager.remove(obj));
|
try {
|
||||||
|
transaction(() -> entityManager.remove(obj));
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
if (transaction.isActive())
|
||||||
|
transaction.rollback();
|
||||||
|
EnvoyLog.getLogger(PersistenceManager.class).log(Level.WARNING,
|
||||||
|
String.format("Could not remove %s: entity didn't exist (for the database).", obj));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -33,7 +33,6 @@ public final class ObjectMessageProcessor implements IMessageProcessor {
|
|||||||
this.processors = processors;
|
this.processors = processors;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Message message, WriteProxy writeProxy) {
|
public void process(Message message, WriteProxy writeProxy) {
|
||||||
try (ObjectInputStream in =
|
try (ObjectInputStream in =
|
||||||
@ -45,23 +44,34 @@ public final class ObjectMessageProcessor implements IMessageProcessor {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.fine("Received " + obj);
|
logger.log(Level.INFO, "Received " + obj);
|
||||||
|
|
||||||
// Get processor and input class and process object
|
refer(message.socketId, writeProxy, obj);
|
||||||
for (@SuppressWarnings("rawtypes")
|
|
||||||
ObjectProcessor p : processors) {
|
|
||||||
Class<?> c = (Class<?>) ((ParameterizedType) p.getClass().getGenericInterfaces()[0])
|
|
||||||
.getActualTypeArguments()[0];
|
|
||||||
if (c.equals(obj.getClass()))
|
|
||||||
try {
|
|
||||||
p.process(c.cast(obj), message.socketId, new ObjectWriteProxy(writeProxy));
|
|
||||||
break;
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.log(Level.SEVERE, "Exception during processor execution: ", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (IOException | ClassNotFoundException e) {
|
} catch (IOException | ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
logger.log(Level.WARNING,
|
||||||
|
"An exception occurred when reading in an object: " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes the appropriate {@link ObjectProcessor} for the given input ({@code obj}), if any is
|
||||||
|
* present.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private void refer(long socketID, WriteProxy writeProxy, Object obj) {
|
||||||
|
|
||||||
|
// Get processor and input class and process object
|
||||||
|
for (@SuppressWarnings("rawtypes")
|
||||||
|
ObjectProcessor p : processors) {
|
||||||
|
Class<?> c = (Class<?>) ((ParameterizedType) p.getClass().getGenericInterfaces()[0])
|
||||||
|
.getActualTypeArguments()[0];
|
||||||
|
if (c.equals(obj.getClass()))
|
||||||
|
try {
|
||||||
|
p.process(c.cast(obj), socketID, new ObjectWriteProxy(writeProxy));
|
||||||
|
break;
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.log(Level.SEVERE, "Exception during processor execution: ", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@ import static envoy.server.Startup.config;
|
|||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.logging.Logger;
|
import java.util.logging.*;
|
||||||
|
|
||||||
import javax.persistence.EntityExistsException;
|
import javax.persistence.EntityExistsException;
|
||||||
|
|
||||||
@ -15,6 +15,7 @@ import envoy.util.EnvoyLog;
|
|||||||
|
|
||||||
import envoy.server.data.PersistenceManager;
|
import envoy.server.data.PersistenceManager;
|
||||||
import envoy.server.net.*;
|
import envoy.server.net.*;
|
||||||
|
import envoy.server.util.UserAuthenticationUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
@ -29,6 +30,15 @@ public final class GroupMessageProcessor implements ObjectProcessor<GroupMessage
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(GroupMessage groupMessage, long socketID, ObjectWriteProxy writeProxy) {
|
public void process(GroupMessage groupMessage, long socketID, ObjectWriteProxy writeProxy) {
|
||||||
|
|
||||||
|
// Check whether the message has the expected parameters
|
||||||
|
if (!UserAuthenticationUtil.isExpectedUser(groupMessage.getSenderID(), socketID)
|
||||||
|
|| persistenceManager.getContactByID(groupMessage.getRecipientID()) == null) {
|
||||||
|
logger.log(Level.INFO,
|
||||||
|
"Received a group message with invalid parameters");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
groupMessage.nextStatus();
|
groupMessage.nextStatus();
|
||||||
|
|
||||||
// Update statuses to SENT / RECEIVED depending on online status
|
// Update statuses to SENT / RECEIVED depending on online status
|
||||||
|
@ -12,6 +12,7 @@ import envoy.util.EnvoyLog;
|
|||||||
|
|
||||||
import envoy.server.data.*;
|
import envoy.server.data.*;
|
||||||
import envoy.server.net.*;
|
import envoy.server.net.*;
|
||||||
|
import envoy.server.util.UserAuthenticationUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Maximilian Käfer
|
* @author Maximilian Käfer
|
||||||
@ -28,6 +29,14 @@ public final class GroupMessageStatusChangeProcessor
|
|||||||
@Override
|
@Override
|
||||||
public void process(GroupMessageStatusChange statusChange, long socketID,
|
public void process(GroupMessageStatusChange statusChange, long socketID,
|
||||||
ObjectWriteProxy writeProxy) {
|
ObjectWriteProxy writeProxy) {
|
||||||
|
|
||||||
|
// Check whether the message has the expected parameters
|
||||||
|
if (!UserAuthenticationUtil.isExpectedUser(statusChange.getMemberID(), socketID)) {
|
||||||
|
logger.log(Level.INFO,
|
||||||
|
"Received a group message with invalid parameters");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
GroupMessage gmsg = (GroupMessage) persistenceManager.getMessageByID(statusChange.getID());
|
GroupMessage gmsg = (GroupMessage) persistenceManager.getMessageByID(statusChange.getID());
|
||||||
|
|
||||||
// Any other status than READ is not supposed to be sent to the server
|
// Any other status than READ is not supposed to be sent to the server
|
||||||
|
@ -23,10 +23,11 @@ public final class IsTypingProcessor implements ObjectProcessor<IsTyping> {
|
|||||||
throws IOException {
|
throws IOException {
|
||||||
final var contact = persistenceManager.getContactByID(event.get());
|
final var contact = persistenceManager.getContactByID(event.get());
|
||||||
if (contact instanceof User) {
|
if (contact instanceof User) {
|
||||||
final var destinationID = event.getDestinationID();
|
if (connectionManager.isOnline(event.get()))
|
||||||
if (connectionManager.isOnline(destinationID))
|
writeProxy.write(connectionManager.getSocketID(event.get()),
|
||||||
writeProxy.write(connectionManager.getSocketID(destinationID), event);
|
new IsTyping(connectionManager.getUserIDBySocketID(socketID)));
|
||||||
} else
|
} else
|
||||||
writeProxy.writeToOnlineContacts(contact.getContacts(), event);
|
writeProxy.writeToOnlineContacts(contact.getContacts(),
|
||||||
|
new IsTyping(connectionManager.getUserIDBySocketID(socketID)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -123,7 +123,6 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
|||||||
// Process token request
|
// Process token request
|
||||||
if (credentials.requestToken()) {
|
if (credentials.requestToken()) {
|
||||||
String token;
|
String token;
|
||||||
|
|
||||||
if (user.getAuthToken() != null && user.getAuthTokenExpiration().isAfter(Instant.now()))
|
if (user.getAuthToken() != null && user.getAuthTokenExpiration().isAfter(Instant.now()))
|
||||||
|
|
||||||
// Reuse existing token and delay expiration date
|
// Reuse existing token and delay expiration date
|
||||||
@ -139,7 +138,6 @@ public final class LoginCredentialProcessor implements ObjectProcessor<LoginCred
|
|||||||
persistenceManager.updateContact(user);
|
persistenceManager.updateContact(user);
|
||||||
writeProxy.write(socketID, new NewAuthToken(token));
|
writeProxy.write(socketID, new NewAuthToken(token));
|
||||||
}
|
}
|
||||||
|
|
||||||
final var pendingMessages =
|
final var pendingMessages =
|
||||||
PersistenceManager.getInstance().getPendingMessages(user, credentials.getLastSync());
|
PersistenceManager.getInstance().getPendingMessages(user, credentials.getLastSync());
|
||||||
pendingMessages.removeIf(GroupMessage.class::isInstance);
|
pendingMessages.removeIf(GroupMessage.class::isInstance);
|
||||||
|
@ -12,6 +12,7 @@ import envoy.util.EnvoyLog;
|
|||||||
|
|
||||||
import envoy.server.data.PersistenceManager;
|
import envoy.server.data.PersistenceManager;
|
||||||
import envoy.server.net.*;
|
import envoy.server.net.*;
|
||||||
|
import envoy.server.util.UserAuthenticationUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This {@link ObjectProcessor} handles incoming {@link Message}s.
|
* This {@link ObjectProcessor} handles incoming {@link Message}s.
|
||||||
@ -29,6 +30,15 @@ public final class MessageProcessor implements ObjectProcessor<Message> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void process(Message message, long socketID, ObjectWriteProxy writeProxy) {
|
public void process(Message message, long socketID, ObjectWriteProxy writeProxy) {
|
||||||
|
|
||||||
|
// Check whether the message has the expected parameters
|
||||||
|
if (!UserAuthenticationUtil.isExpectedUser(message.getSenderID(), socketID)
|
||||||
|
|| persistenceManager.getContactByID(message.getRecipientID()) == null) {
|
||||||
|
logger.log(Level.INFO,
|
||||||
|
"Received a message with invalid parameters");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
message.nextStatus();
|
message.nextStatus();
|
||||||
|
|
||||||
// Convert to server message
|
// Convert to server message
|
||||||
|
@ -7,7 +7,7 @@ import envoy.event.*;
|
|||||||
import envoy.util.EnvoyLog;
|
import envoy.util.EnvoyLog;
|
||||||
|
|
||||||
import envoy.server.data.PersistenceManager;
|
import envoy.server.data.PersistenceManager;
|
||||||
import envoy.server.net.ObjectWriteProxy;
|
import envoy.server.net.*;
|
||||||
import envoy.server.util.PasswordUtil;
|
import envoy.server.util.PasswordUtil;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,7 +21,8 @@ public final class PasswordChangeRequestProcessor
|
|||||||
public void process(PasswordChangeRequest event, long socketID, ObjectWriteProxy writeProxy)
|
public void process(PasswordChangeRequest event, long socketID, ObjectWriteProxy writeProxy)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final var persistenceManager = PersistenceManager.getInstance();
|
final var persistenceManager = PersistenceManager.getInstance();
|
||||||
final var user = persistenceManager.getUserByID(event.getID());
|
final var user = persistenceManager
|
||||||
|
.getUserByID(ConnectionManager.getInstance().getUserIDBySocketID(socketID));
|
||||||
final var logger =
|
final var logger =
|
||||||
EnvoyLog.getLogger(PasswordChangeRequestProcessor.class);
|
EnvoyLog.getLogger(PasswordChangeRequestProcessor.class);
|
||||||
final var correctAuthentication =
|
final var correctAuthentication =
|
||||||
|
@ -0,0 +1,24 @@
|
|||||||
|
package envoy.server.util;
|
||||||
|
|
||||||
|
import envoy.server.net.ConnectionManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Leon Hofmeister
|
||||||
|
* @since Envoy Server v0.3-beta
|
||||||
|
*/
|
||||||
|
public final class UserAuthenticationUtil {
|
||||||
|
|
||||||
|
private UserAuthenticationUtil() {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a user is really who he claims to be.
|
||||||
|
*
|
||||||
|
* @param expectedID the expected user ID
|
||||||
|
* @param socketID the socket ID of the user making a request
|
||||||
|
* @return whether this user is who he claims to be
|
||||||
|
* @since Envoy Server v0.3-beta
|
||||||
|
*/
|
||||||
|
public static boolean isExpectedUser(long expectedID, long socketID) {
|
||||||
|
return ConnectionManager.getInstance().getUserIDBySocketID(socketID) == expectedID;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user