mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Do additional validation on incoming private group messages
This commit is contained in:
@@ -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";
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user