Do additional validation on incoming private group messages

This commit is contained in:
Torsten Grote
2016-10-24 10:25:14 -02:00
parent 679b54b2b4
commit 0caabda303
3 changed files with 110 additions and 26 deletions

View File

@@ -8,11 +8,11 @@ interface Constants {
String KEY_TYPE = "type";
String KEY_TIMESTAMP = "timestamp";
String KEY_READ = MSG_KEY_READ;
String KEY_PARENT_ID = "parentId";
String KEY_PARENT_MSG_ID = "parentMsgId";
String KEY_NEW_MEMBER_MSG_ID = "newMemberMsgId";
String KEY_PREVIOUS_MSG_ID = "previousMsgId";
String KEY_AUTHOR_ID = "authorId";
String KEY_AUTHOR_NAME = "authorName";
String KEY_AUTHOR_PUBLIC_KEY = "authorPublicKey";
// Messaging Group Metadata
String KEY_PREVIOUS_MSG_ID = "previousMsgId";
}

View File

@@ -29,7 +29,9 @@ import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_ID;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_NAME;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_PUBLIC_KEY;
import static org.briarproject.privategroup.Constants.KEY_PARENT_ID;
import static org.briarproject.privategroup.Constants.KEY_NEW_MEMBER_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_PARENT_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_PREVIOUS_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_READ;
import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP;
import static org.briarproject.privategroup.Constants.KEY_TYPE;
@@ -80,6 +82,8 @@ class GroupMessageValidator extends BdfMessageValidator {
break;
case POST:
c = validatePost(m, g, body, member_name, member_public_key);
addMessageMetadata(c, member_name, member_public_key,
m.getTimestamp());
break;
default:
throw new InvalidMessageException("Unknown Message Type");
@@ -141,6 +145,7 @@ class GroupMessageValidator extends BdfMessageValidator {
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_NEW_MEMBER_MSG_ID, new_member_id);
return new BdfMessageContext(meta, dependencies);
}
@@ -185,7 +190,8 @@ class GroupMessageValidator extends BdfMessageValidator {
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();
if (parent_id != null) meta.put(KEY_PARENT_ID, parent_id);
if (parent_id != null) meta.put(KEY_PARENT_MSG_ID, parent_id);
meta.put(KEY_PREVIOUS_MSG_ID, previous_message_id);
return new BdfMessageContext(meta, dependencies);
}

View File

@@ -16,6 +16,7 @@ import org.briarproject.api.identity.IdentityManager;
import org.briarproject.api.privategroup.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.privategroup.JoinMessageHeader;
import org.briarproject.api.privategroup.MessageType;
import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory;
import org.briarproject.api.privategroup.PrivateGroupManager;
@@ -28,6 +29,7 @@ import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -45,7 +47,8 @@ import static org.briarproject.api.privategroup.MessageType.POST;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_ID;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_NAME;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_PUBLIC_KEY;
import static org.briarproject.privategroup.Constants.KEY_PARENT_ID;
import static org.briarproject.privategroup.Constants.KEY_NEW_MEMBER_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_PARENT_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_PREVIOUS_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_READ;
import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP;
@@ -100,6 +103,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
throws DbException, FormatException {
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TYPE, NEW_MEMBER.getInt());
addMessageMetadata(meta, m, true);
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
}
@@ -166,9 +170,11 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
try {
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TYPE, POST.getInt());
if (m.getParent() != null) meta.put(KEY_PARENT_ID, m.getParent());
if (m.getParent() != null) meta.put(KEY_PARENT_MSG_ID, m.getParent());
addMessageMetadata(meta, m, true);
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
setPreviousMsgId(txn, m.getMessage().getGroupId(),
m.getMessage().getId());
trackOutgoingMessage(txn, m.getMessage());
txn.setComplete();
} catch (FormatException e) {
@@ -181,6 +187,15 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
m.getMessage().getTimestamp(), m.getMember(), OURSELVES, true);
}
private void addMessageMetadata(BdfDictionary meta, GroupMessage m,
boolean read) {
meta.put(KEY_TIMESTAMP, m.getMessage().getTimestamp());
meta.put(KEY_READ, read);
meta.put(KEY_AUTHOR_ID, m.getMember().getId());
meta.put(KEY_AUTHOR_NAME, m.getMember().getName());
meta.put(KEY_AUTHOR_PUBLIC_KEY, m.getMember().getPublicKey());
}
@Override
public PrivateGroup getPrivateGroup(GroupId g) throws DbException {
PrivateGroup privateGroup;
@@ -288,8 +303,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
throws DbException, FormatException {
MessageId parentId = null;
if (meta.containsKey(KEY_PARENT_ID)) {
parentId = new MessageId(meta.getRaw(KEY_PARENT_ID));
if (meta.containsKey(KEY_PARENT_MSG_ID)) {
parentId = new MessageId(meta.getRaw(KEY_PARENT_MSG_ID));
}
long timestamp = meta.getLong(KEY_TIMESTAMP);
@@ -318,23 +333,86 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary meta) throws DbException, FormatException {
trackIncomingMessage(txn, m);
// TODO POST timestamp must be greater than the timestamps of the parent post, if any, and the member's previous message
// TODO JOIN timestamp must be equal to the timestamp of the new member message.
// TODO JOIN new_member_id must be the identifier of a NEW_MEMBER message with the same member_name and member_public_key
return true;
}
private void addMessageMetadata(BdfDictionary meta, GroupMessage m,
boolean read) {
meta.put(KEY_TIMESTAMP, m.getMessage().getTimestamp());
meta.put(KEY_READ, read);
meta.put(KEY_AUTHOR_ID, m.getMember().getId());
meta.put(KEY_AUTHOR_NAME, m.getMember().getName());
meta.put(KEY_AUTHOR_PUBLIC_KEY, m.getMember().getPublicKey());
long timestamp = meta.getLong(KEY_TIMESTAMP);
MessageType type =
MessageType.valueOf(meta.getLong(KEY_TYPE).intValue());
switch (type) {
case NEW_MEMBER:
// don't track incoming message, because it won't show in the UI
return true;
case JOIN:
// new_member_id must be the identifier of a NEW_MEMBER message
byte[] newMemberIdBytes =
meta.getOptionalRaw(KEY_NEW_MEMBER_MSG_ID);
MessageId newMemberId = new MessageId(newMemberIdBytes);
BdfDictionary newMemberMeta = clientHelper
.getMessageMetadataAsDictionary(txn, newMemberId);
MessageType newMemberType = MessageType
.valueOf(newMemberMeta.getLong(KEY_TYPE).intValue());
if (newMemberType != NEW_MEMBER) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
// timestamp must be equal to timestamp of NEW_MEMBER message
if (timestamp != newMemberMeta.getLong(KEY_TIMESTAMP)) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
// NEW_MEMBER must have same member_name and member_public_key
if (!Arrays.equals(meta.getRaw(KEY_AUTHOR_ID),
newMemberMeta.getRaw(KEY_AUTHOR_ID))) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
// TODO add to member list
trackIncomingMessage(txn, m);
return true;
case POST:
// timestamp must be greater than the timestamps of parent post
byte[] parentIdBytes = meta.getOptionalRaw(KEY_PARENT_MSG_ID);
if (parentIdBytes != null) {
MessageId parentId = new MessageId(parentIdBytes);
BdfDictionary parentMeta = clientHelper
.getMessageMetadataAsDictionary(txn, parentId);
if (timestamp <= parentMeta.getLong(KEY_TIMESTAMP)) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
MessageType parentType = MessageType
.valueOf(parentMeta.getLong(KEY_TYPE).intValue());
if (parentType != POST) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
}
// and the member's previous message
byte[] previousMsgIdBytes = meta.getRaw(KEY_PREVIOUS_MSG_ID);
MessageId previousMsgId = new MessageId(previousMsgIdBytes);
BdfDictionary previousMeta = clientHelper
.getMessageMetadataAsDictionary(txn, previousMsgId);
if (timestamp <= previousMeta.getLong(KEY_TIMESTAMP)) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
// previous message must be from same member
if (!Arrays.equals(meta.getRaw(KEY_AUTHOR_ID),
previousMeta.getRaw(KEY_AUTHOR_ID))) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
trackIncomingMessage(txn, m);
return true;
default:
// the validator should only let valid types pass
throw new RuntimeException("Unknown MessageType");
}
}
}