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_TYPE = "type";
String KEY_TIMESTAMP = "timestamp"; String KEY_TIMESTAMP = "timestamp";
String KEY_READ = MSG_KEY_READ; 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_ID = "authorId";
String KEY_AUTHOR_NAME = "authorName"; String KEY_AUTHOR_NAME = "authorName";
String KEY_AUTHOR_PUBLIC_KEY = "authorPublicKey"; 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_ID;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_NAME; 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_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_READ;
import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP; import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP;
import static org.briarproject.privategroup.Constants.KEY_TYPE; import static org.briarproject.privategroup.Constants.KEY_TYPE;
@@ -80,6 +82,8 @@ class GroupMessageValidator extends BdfMessageValidator {
break; break;
case POST: case POST:
c = validatePost(m, g, body, member_name, member_public_key); c = validatePost(m, g, body, member_name, member_public_key);
addMessageMetadata(c, member_name, member_public_key,
m.getTimestamp());
break; break;
default: default:
throw new InvalidMessageException("Unknown Message Type"); throw new InvalidMessageException("Unknown Message Type");
@@ -141,6 +145,7 @@ class GroupMessageValidator extends BdfMessageValidator {
// Return the metadata and dependencies // Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(KEY_NEW_MEMBER_MSG_ID, new_member_id);
return new BdfMessageContext(meta, dependencies); return new BdfMessageContext(meta, dependencies);
} }
@@ -185,7 +190,8 @@ class GroupMessageValidator extends BdfMessageValidator {
// Return the metadata and dependencies // Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary(); 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); 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.GroupMessage;
import org.briarproject.api.privategroup.GroupMessageHeader; import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.privategroup.JoinMessageHeader; import org.briarproject.api.privategroup.JoinMessageHeader;
import org.briarproject.api.privategroup.MessageType;
import org.briarproject.api.privategroup.PrivateGroup; import org.briarproject.api.privategroup.PrivateGroup;
import org.briarproject.api.privategroup.PrivateGroupFactory; import org.briarproject.api.privategroup.PrivateGroupFactory;
import org.briarproject.api.privategroup.PrivateGroupManager; import org.briarproject.api.privategroup.PrivateGroupManager;
@@ -28,6 +29,7 @@ import org.briarproject.clients.BdfIncomingMessageHook;
import org.briarproject.util.StringUtils; import org.briarproject.util.StringUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; 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_ID;
import static org.briarproject.privategroup.Constants.KEY_AUTHOR_NAME; 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_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_PREVIOUS_MSG_ID;
import static org.briarproject.privategroup.Constants.KEY_READ; import static org.briarproject.privategroup.Constants.KEY_READ;
import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP; import static org.briarproject.privategroup.Constants.KEY_TIMESTAMP;
@@ -100,6 +103,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
throws DbException, FormatException { throws DbException, FormatException {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TYPE, NEW_MEMBER.getInt()); meta.put(KEY_TYPE, NEW_MEMBER.getInt());
addMessageMetadata(meta, m, true);
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true); clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
} }
@@ -166,9 +170,11 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
try { try {
BdfDictionary meta = new BdfDictionary(); BdfDictionary meta = new BdfDictionary();
meta.put(KEY_TYPE, POST.getInt()); 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); addMessageMetadata(meta, m, true);
clientHelper.addLocalMessage(txn, m.getMessage(), meta, true); clientHelper.addLocalMessage(txn, m.getMessage(), meta, true);
setPreviousMsgId(txn, m.getMessage().getGroupId(),
m.getMessage().getId());
trackOutgoingMessage(txn, m.getMessage()); trackOutgoingMessage(txn, m.getMessage());
txn.setComplete(); txn.setComplete();
} catch (FormatException e) { } catch (FormatException e) {
@@ -181,6 +187,15 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
m.getMessage().getTimestamp(), m.getMember(), OURSELVES, true); 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 @Override
public PrivateGroup getPrivateGroup(GroupId g) throws DbException { public PrivateGroup getPrivateGroup(GroupId g) throws DbException {
PrivateGroup privateGroup; PrivateGroup privateGroup;
@@ -288,8 +303,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
throws DbException, FormatException { throws DbException, FormatException {
MessageId parentId = null; MessageId parentId = null;
if (meta.containsKey(KEY_PARENT_ID)) { if (meta.containsKey(KEY_PARENT_MSG_ID)) {
parentId = new MessageId(meta.getRaw(KEY_PARENT_ID)); parentId = new MessageId(meta.getRaw(KEY_PARENT_MSG_ID));
} }
long timestamp = meta.getLong(KEY_TIMESTAMP); 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, protected boolean incomingMessage(Transaction txn, Message m, BdfList body,
BdfDictionary meta) throws DbException, FormatException { BdfDictionary meta) throws DbException, FormatException {
trackIncomingMessage(txn, m); long timestamp = meta.getLong(KEY_TIMESTAMP);
MessageType type =
// TODO POST timestamp must be greater than the timestamps of the parent post, if any, and the member's previous message MessageType.valueOf(meta.getLong(KEY_TYPE).intValue());
switch (type) {
// TODO JOIN timestamp must be equal to the timestamp of the new member message. case NEW_MEMBER:
// TODO JOIN new_member_id must be the identifier of a NEW_MEMBER message with the same member_name and member_public_key // don't track incoming message, because it won't show in the UI
return true;
return true; case JOIN:
} // new_member_id must be the identifier of a NEW_MEMBER message
byte[] newMemberIdBytes =
private void addMessageMetadata(BdfDictionary meta, GroupMessage m, meta.getOptionalRaw(KEY_NEW_MEMBER_MSG_ID);
boolean read) { MessageId newMemberId = new MessageId(newMemberIdBytes);
meta.put(KEY_TIMESTAMP, m.getMessage().getTimestamp()); BdfDictionary newMemberMeta = clientHelper
meta.put(KEY_READ, read); .getMessageMetadataAsDictionary(txn, newMemberId);
meta.put(KEY_AUTHOR_ID, m.getMember().getId()); MessageType newMemberType = MessageType
meta.put(KEY_AUTHOR_NAME, m.getMember().getName()); .valueOf(newMemberMeta.getLong(KEY_TYPE).intValue());
meta.put(KEY_AUTHOR_PUBLIC_KEY, m.getMember().getPublicKey()); 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");
}
} }
} }