Address review comments

This commit is contained in:
Torsten Grote
2016-10-28 16:07:17 -02:00
parent c79ce61f6d
commit c0aa255bb6
22 changed files with 226 additions and 132 deletions

View File

@@ -72,6 +72,7 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
private LocalAuthor author0, author1;
private PrivateGroup privateGroup0;
private GroupId groupId0;
private GroupMessage newMemberMsg0;
@Inject
Clock clock;
@@ -221,6 +222,20 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
// create and add test message with previousMsgId of newMemberMsg
previousMsgId = newMemberMsg0.getMessage().getId();
msg = groupMessageFactory
.createGroupMessage(groupId0, clock.currentTimeMillis(), null,
author0, "test", previousMsgId);
groupManager0.addLocalMessage(msg);
// sync test message
sync0To1();
validationWaiter.await(TIMEOUT, 1);
// assert that message did not arrive
assertEquals(2, groupManager1.getHeaders(groupId0).size());
}
@Test
@@ -437,13 +452,13 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
private void addGroup() throws Exception {
// author0 joins privateGroup0
long joinTime = clock.currentTimeMillis();
GroupMessage newMemberMsg = groupMessageFactory
newMemberMsg0 = groupMessageFactory
.createNewMemberMessage(privateGroup0.getId(), joinTime,
author0, author0);
GroupMessage joinMsg = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author0,
newMemberMsg.getMessage().getId());
groupManager0.addPrivateGroup(privateGroup0, newMemberMsg, joinMsg);
newMemberMsg0.getMessage().getId());
groupManager0.addPrivateGroup(privateGroup0, newMemberMsg0, joinMsg);
assertEquals(joinMsg.getMessage().getId(),
groupManager0.getPreviousMsgId(groupId0));
@@ -457,13 +472,13 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest {
// author1 joins privateGroup0
joinTime = clock.currentTimeMillis();
newMemberMsg = groupMessageFactory
GroupMessage newMemberMsg1 = groupMessageFactory
.createNewMemberMessage(privateGroup0.getId(), joinTime,
author0, author1);
joinMsg = groupMessageFactory
.createJoinMessage(privateGroup0.getId(), joinTime, author1,
newMemberMsg.getMessage().getId());
groupManager1.addPrivateGroup(privateGroup0, newMemberMsg, joinMsg);
newMemberMsg1.getMessage().getId());
groupManager1.addPrivateGroup(privateGroup0, newMemberMsg1, joinMsg);
assertEquals(joinMsg.getMessage().getId(),
groupManager1.getPreviousMsgId(groupId0));

View File

@@ -15,6 +15,7 @@ import org.briarproject.db.DatabaseModule;
import org.briarproject.event.EventModule;
import org.briarproject.identity.IdentityModule;
import org.briarproject.lifecycle.LifecycleModule;
import org.briarproject.messaging.MessagingModule;
import org.briarproject.privategroup.PrivateGroupModule;
import org.briarproject.properties.PropertiesModule;
import org.briarproject.sharing.SharingModule;
@@ -37,6 +38,7 @@ import dagger.Component;
DataModule.class,
DatabaseModule.class,
EventModule.class,
MessagingModule.class,
PrivateGroupModule.class,
IdentityModule.class,
LifecycleModule.class,

View File

@@ -2,7 +2,6 @@ package org.briarproject.android.privategroup.conversation;
import android.support.annotation.Nullable;
import org.briarproject.R;
import org.briarproject.android.api.AndroidNotificationManager;
import org.briarproject.android.controller.handler.ResultExceptionHandler;
import org.briarproject.android.threaded.ThreadListControllerImpl;
@@ -95,8 +94,8 @@ public class GroupControllerImpl extends
protected String loadMessageBody(GroupMessageHeader header)
throws DbException {
if (header instanceof JoinMessageHeader) {
return listener.getApplicationContext()
.getString(R.string.groups_member_joined);
// will be looked up later
return "";
}
return privateGroupManager.getMessageBody(header.getId());
}

View File

@@ -1,5 +1,6 @@
package org.briarproject.android.privategroup.conversation;
import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import android.support.v7.widget.LinearLayoutManager;
import android.view.LayoutInflater;
@@ -19,12 +20,11 @@ public class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
super(listener, layoutManager);
}
@LayoutRes
@Override
public int getItemViewType(int position) {
GroupMessageItem item = getVisibleItem(position);
if (item instanceof JoinMessageItem) {
return R.layout.list_item_thread_notice;
}
if (item != null) return item.getLayout();
return R.layout.list_item_thread;
}
@@ -34,7 +34,7 @@ public class GroupMessageAdapter extends ThreadItemAdapter<GroupMessageItem> {
View v = LayoutInflater.from(parent.getContext())
.inflate(type, parent, false);
if (type == R.layout.list_item_thread_notice) {
return new BaseThreadItemViewHolder<>(v);
return new JoinMessageItemHolder(v);
}
return new ThreadItemViewHolder<>(v);
}

View File

@@ -1,11 +1,19 @@
package org.briarproject.android.privategroup.conversation;
import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import org.briarproject.R;
import org.briarproject.android.threaded.ThreadItem;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.Author.Status;
import org.briarproject.api.privategroup.GroupMessageHeader;
import org.briarproject.api.sync.MessageId;
import javax.annotation.concurrent.NotThreadSafe;
@UiThread
@NotThreadSafe
class GroupMessageItem extends ThreadItem {
private GroupMessageItem(MessageId messageId, MessageId parentId,
@@ -19,4 +27,9 @@ class GroupMessageItem extends ThreadItem {
h.getAuthorStatus(), h.isRead());
}
@LayoutRes
public int getLayout() {
return R.layout.list_item_thread;
}
}

View File

@@ -1,7 +1,15 @@
package org.briarproject.android.privategroup.conversation;
import android.support.annotation.LayoutRes;
import android.support.annotation.UiThread;
import org.briarproject.R;
import org.briarproject.api.privategroup.GroupMessageHeader;
import javax.annotation.concurrent.NotThreadSafe;
@UiThread
@NotThreadSafe
class JoinMessageItem extends GroupMessageItem {
JoinMessageItem(GroupMessageHeader h,
@@ -19,4 +27,9 @@ class JoinMessageItem extends GroupMessageItem {
return false;
}
@LayoutRes
public int getLayout() {
return R.layout.list_item_thread_notice;
}
}

View File

@@ -0,0 +1,30 @@
package org.briarproject.android.privategroup.conversation;
import android.support.annotation.UiThread;
import android.view.View;
import org.briarproject.R;
import org.briarproject.android.threaded.BaseThreadItemViewHolder;
import org.briarproject.android.threaded.ThreadItemAdapter;
import org.briarproject.android.threaded.ThreadItemAdapter.ThreadItemListener;
import org.briarproject.api.nullsafety.NotNullByDefault;
@UiThread
@NotNullByDefault
public class JoinMessageItemHolder
extends BaseThreadItemViewHolder<GroupMessageItem> {
public JoinMessageItemHolder(View v) {
super(v);
}
@Override
public void bind(final ThreadItemAdapter<GroupMessageItem> adapter,
final ThreadItemListener<GroupMessageItem> listener,
final GroupMessageItem item, int pos) {
super.bind(adapter, listener, item, pos);
textView.setText(getContext().getString(R.string.groups_member_joined));
}
}

View File

@@ -21,13 +21,13 @@ import org.briarproject.util.StringUtils;
@UiThread
@NotNullByDefault
public class BaseThreadItemViewHolder<I extends ThreadItem>
public abstract class BaseThreadItemViewHolder<I extends ThreadItem>
extends RecyclerView.ViewHolder {
private final static int ANIMATION_DURATION = 5000;
protected final TextView textView;
private final ViewGroup layout;
private final TextView textView;
private final AuthorView author;
private final View topDivider;

View File

@@ -1,7 +1,5 @@
package org.briarproject.android.threaded;
import android.support.annotation.UiThread;
import org.briarproject.api.clients.MessageTree.MessageNode;
import org.briarproject.api.identity.Author;
import org.briarproject.api.identity.Author.Status;
@@ -11,7 +9,6 @@ import javax.annotation.concurrent.NotThreadSafe;
import static org.briarproject.android.threaded.ThreadItemAdapter.UNDEFINED;
@UiThread
@NotThreadSafe
public abstract class ThreadItem implements MessageNode {
@@ -97,4 +94,5 @@ public abstract class ThreadItem implements MessageNode {
public void setDescendantCount(int descendantCount) {
this.descendantCount = descendantCount;
}
}

View File

@@ -316,7 +316,7 @@ public class ThreadItemAdapter<I extends ThreadItem>
revision++;
}
protected interface ThreadItemListener<I> {
public interface ThreadItemListener<I> {
void onItemVisible(I item);

View File

@@ -1,6 +1,5 @@
package org.briarproject.android.threaded;
import android.content.Context;
import android.support.annotation.Nullable;
import android.support.annotation.UiThread;
@@ -40,8 +39,6 @@ public interface ThreadListController<G extends NamedGroup, I extends ThreadItem
@UiThread
void onGroupRemoved();
Context getApplicationContext();
}
}

View File

@@ -42,7 +42,6 @@ public abstract class ThreadListControllerImpl<G extends NamedGroup, I extends T
Logger.getLogger(ThreadListControllerImpl.class.getName());
protected final IdentityManager identityManager;
@CryptoExecutor
protected final Executor cryptoExecutor;
protected final AndroidNotificationManager notificationManager;
protected final Clock clock;

View File

@@ -84,6 +84,6 @@ public interface ClientHelper {
throws FormatException, GeneralSecurityException;
void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws InvalidMessageException;
throws FormatException, GeneralSecurityException;
}

View File

@@ -12,19 +12,11 @@ public enum MessageType {
}
public static MessageType valueOf(int value) {
switch (value) {
case 0:
return NEW_MEMBER;
case 1:
return JOIN;
case 2:
return POST;
default:
throw new IllegalArgumentException();
}
for (MessageType m : values()) if (m.value == value) return m;
throw new IllegalArgumentException();
}
public int getInt() {
return value;
}
}
}

View File

@@ -18,8 +18,9 @@ public interface PrivateGroupManager extends MessageTracker {
* Adds a new private group and joins it.
*
* @param group The private group to add
* @param newMemberMsg The creator's message announcing the first new member
* @param joinMsg The first new member's join message
* @param newMemberMsg The creator's message announcing herself as
* first new member
* @param joinMsg The creator's own join message
*/
void addPrivateGroup(PrivateGroup group, GroupMessage newMemberMsg,
GroupMessage joinMsg) throws DbException;
@@ -27,10 +28,11 @@ public interface PrivateGroupManager extends MessageTracker {
/** Removes a dissolved private group. */
void removePrivateGroup(GroupId g) throws DbException;
/** Gets the MessageId of the */
/** Gets the MessageId of your previous message sent to the group */
MessageId getPreviousMsgId(GroupId g) throws DbException;
/** Returns the timestamp of the message with the given ID */
// TODO change to getPreviousMessageHeader()
long getMessageTimestamp(MessageId id) throws DbException;
/** Stores (and sends) a local group message. */

View File

@@ -20,6 +20,7 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfMessageValidator;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Collections;
@@ -101,7 +102,11 @@ class BlogPostValidator extends BdfMessageValidator {
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), postBody);
Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter
Author a = b.getAuthor();
clientHelper.verifySignature(sig, a.getPublicKey(), signed);
try {
clientHelper.verifySignature(sig, a.getPublicKey(), signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();
@@ -142,7 +147,11 @@ class BlogPostValidator extends BdfMessageValidator {
currentId);
Blog b = blogFactory.parseBlog(g, ""); // description doesn't matter
Author a = b.getAuthor();
clientHelper.verifySignature(sig, a.getPublicKey(), signed);
try {
clientHelper.verifySignature(sig, a.getPublicKey(), signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();

View File

@@ -20,7 +20,6 @@ import org.briarproject.api.db.DbException;
import org.briarproject.api.db.Metadata;
import org.briarproject.api.db.Transaction;
import org.briarproject.api.sync.GroupId;
import org.briarproject.api.sync.InvalidMessageException;
import org.briarproject.api.sync.Message;
import org.briarproject.api.sync.MessageFactory;
import org.briarproject.api.sync.MessageId;
@@ -325,22 +324,16 @@ class ClientHelperImpl implements ClientHelper {
@Override
public void verifySignature(byte[] sig, byte[] publicKey, BdfList signed)
throws InvalidMessageException {
try {
// Parse the public key
KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(publicKey);
// Verify the signature
Signature signature = cryptoComponent.getSignature();
signature.initVerify(key);
signature.update(toByteArray(signed));
if (!signature.verify(sig)) {
throw new InvalidMessageException("Invalid signature");
}
} catch (GeneralSecurityException e) {
throw new InvalidMessageException("Invalid public key");
} catch (FormatException e) {
throw new InvalidMessageException(e);
throws FormatException, GeneralSecurityException {
// Parse the public key
KeyParser keyParser = cryptoComponent.getSignatureKeyParser();
PublicKey key = keyParser.parsePublicKey(publicKey);
// Verify the signature
Signature signature = cryptoComponent.getSignature();
signature.initVerify(key);
signature.update(toByteArray(signed));
if (!signature.verify(sig)) {
throw new GeneralSecurityException("Invalid signature");
}
}

View File

@@ -16,6 +16,7 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfMessageValidator;
import java.security.GeneralSecurityException;
import java.util.Collection;
import java.util.Collections;
@@ -73,10 +74,15 @@ class ForumPostValidator extends BdfMessageValidator {
}
// Verify the signature, if any
if (author != null) {
// Serialise the data to be signed
// Serialise the data to be verified
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), parent,
authorList, contentType, forumPostBody);
clientHelper.verifySignature(sig, author.getPublicKey(), signed);
try {
clientHelper
.verifySignature(sig, author.getPublicKey(), signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
}
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();

View File

@@ -11,8 +11,8 @@ interface Constants {
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";
String KEY_MEMBER_ID = "memberId";
String KEY_MEMBER_NAME = "memberName";
String KEY_MEMBER_PUBLIC_KEY = "memberPublicKey";
}

View File

@@ -36,14 +36,15 @@ class GroupMessageFactoryImpl implements GroupMessageFactory {
LocalAuthor creator, Author member) {
try {
// Generate the signature
BdfList toSign = BdfList.of(groupId, timestamp, member.getName(),
member.getPublicKey());
int type = NEW_MEMBER.getInt();
BdfList toSign = BdfList.of(groupId, timestamp, type,
member.getName(), member.getPublicKey());
byte[] signature =
clientHelper.sign(toSign, creator.getPrivateKey());
// Compose the message
BdfList body =
BdfList.of(NEW_MEMBER.getInt(), member.getName(),
BdfList.of(type, member.getName(),
member.getPublicKey(), signature);
Message m = clientHelper.createMessage(groupId, timestamp, body);
@@ -60,14 +61,15 @@ class GroupMessageFactoryImpl implements GroupMessageFactory {
LocalAuthor member, MessageId newMemberId) {
try {
// Generate the signature
BdfList toSign = BdfList.of(groupId, timestamp, member.getName(),
member.getPublicKey(), newMemberId);
int type = JOIN.getInt();
BdfList toSign = BdfList.of(groupId, timestamp, type,
member.getName(), member.getPublicKey(), newMemberId);
byte[] signature =
clientHelper.sign(toSign, member.getPrivateKey());
// Compose the message
BdfList body =
BdfList.of(JOIN.getInt(), member.getName(),
BdfList.of(type, member.getName(),
member.getPublicKey(), newMemberId, signature);
Message m = clientHelper.createMessage(groupId, timestamp, body);
@@ -85,14 +87,16 @@ class GroupMessageFactoryImpl implements GroupMessageFactory {
MessageId previousMsgId) {
try {
// Generate the signature
BdfList toSign = BdfList.of(groupId, timestamp, author.getName(),
author.getPublicKey(), parentId, previousMsgId, content);
int type = POST.getInt();
BdfList toSign = BdfList.of(groupId, timestamp, type,
author.getName(), author.getPublicKey(), parentId,
previousMsgId, content);
byte[] signature =
clientHelper.sign(toSign, author.getPrivateKey());
// Compose the message
BdfList body =
BdfList.of(POST.getInt(), author.getName(),
BdfList.of(type, author.getName(),
author.getPublicKey(), parentId, previousMsgId,
content, signature);
Message m = clientHelper.createMessage(groupId, timestamp, body);

View File

@@ -18,6 +18,7 @@ import org.briarproject.api.sync.MessageId;
import org.briarproject.api.system.Clock;
import org.briarproject.clients.BdfMessageValidator;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -25,10 +26,13 @@ import java.util.Collections;
import static org.briarproject.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
import static org.briarproject.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH;
import static org.briarproject.api.privategroup.MessageType.JOIN;
import static org.briarproject.api.privategroup.MessageType.NEW_MEMBER;
import static org.briarproject.api.privategroup.MessageType.POST;
import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_POST_BODY_LENGTH;
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_MEMBER_ID;
import static org.briarproject.privategroup.Constants.KEY_MEMBER_NAME;
import static org.briarproject.privategroup.Constants.KEY_MEMBER_PUBLIC_KEY;
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;
@@ -60,29 +64,29 @@ class GroupMessageValidator extends BdfMessageValidator {
body.removeElementAt(0);
// member_name (string)
String member_name = body.getString(0);
checkLength(member_name, 1, MAX_AUTHOR_NAME_LENGTH);
String memberName = body.getString(0);
checkLength(memberName, 1, MAX_AUTHOR_NAME_LENGTH);
// member_public_key (raw)
byte[] member_public_key = body.getRaw(1);
checkLength(member_public_key, 1, MAX_PUBLIC_KEY_LENGTH);
byte[] memberPublicKey = body.getRaw(1);
checkLength(memberPublicKey, 1, MAX_PUBLIC_KEY_LENGTH);
BdfMessageContext c;
switch (MessageType.valueOf(type)) {
case NEW_MEMBER:
c = validateNewMember(m, g, body, member_name,
member_public_key);
addMessageMetadata(c, member_name, member_public_key,
c = validateNewMember(m, g, body, memberName,
memberPublicKey);
addMessageMetadata(c, memberName, memberPublicKey,
m.getTimestamp());
break;
case JOIN:
c = validateJoin(m, g, body, member_name, member_public_key);
addMessageMetadata(c, member_name, member_public_key,
c = validateJoin(m, g, body, memberName, memberPublicKey);
addMessageMetadata(c, memberName, memberPublicKey,
m.getTimestamp());
break;
case POST:
c = validatePost(m, g, body, member_name, member_public_key);
addMessageMetadata(c, member_name, member_public_key,
c = validatePost(m, g, body, memberName, memberPublicKey);
addMessageMetadata(c, memberName, memberPublicKey,
m.getTimestamp());
break;
default:
@@ -93,7 +97,7 @@ class GroupMessageValidator extends BdfMessageValidator {
}
private BdfMessageContext validateNewMember(Message m, Group g,
BdfList body, String member_name, byte[] member_public_key)
BdfList body, String memberName, byte[] memberPublicKey)
throws InvalidMessageException, FormatException {
// The content is a BDF list with three elements
@@ -105,11 +109,16 @@ class GroupMessageValidator extends BdfMessageValidator {
checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
// Verify Signature
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), member_name,
member_public_key);
BdfList signed =
BdfList.of(g.getId(), m.getTimestamp(), NEW_MEMBER.getInt(),
memberName, memberPublicKey);
PrivateGroup group = groupFactory.parsePrivateGroup(g);
byte[] creatorPublicKey = group.getAuthor().getPublicKey();
clientHelper.verifySignature(signature, creatorPublicKey, signed);
try {
clientHelper.verifySignature(signature, creatorPublicKey, signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
// Return the metadata and no dependencies
BdfDictionary meta = new BdfDictionary();
@@ -117,7 +126,7 @@ class GroupMessageValidator extends BdfMessageValidator {
}
private BdfMessageContext validateJoin(Message m, Group g, BdfList body,
String member_name, byte[] member_public_key)
String memberName, byte[] memberPublicKey)
throws InvalidMessageException, FormatException {
// The content is a BDF list with four elements
@@ -126,8 +135,8 @@ class GroupMessageValidator extends BdfMessageValidator {
// new_member_id (raw)
// the identifier of a new member message
// with the same member_name and member_public_key
byte[] new_member_id = body.getRaw(2);
checkLength(new_member_id, MessageId.LENGTH);
byte[] newMemberId = body.getRaw(2);
checkLength(newMemberId, MessageId.LENGTH);
// signature (raw)
// a signature with the member's private key over a list with 5 elements
@@ -135,22 +144,26 @@ class GroupMessageValidator extends BdfMessageValidator {
checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
// Verify Signature
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), member_name,
member_public_key, new_member_id);
clientHelper.verifySignature(signature, member_public_key, signed);
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), JOIN.getInt(),
memberName, memberPublicKey, newMemberId);
try {
clientHelper.verifySignature(signature, memberPublicKey, signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
// The new member message is a dependency
Collection<MessageId> dependencies =
Collections.singleton(new MessageId(new_member_id));
Collections.singleton(new MessageId(newMemberId));
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();
meta.put(KEY_NEW_MEMBER_MSG_ID, new_member_id);
meta.put(KEY_NEW_MEMBER_MSG_ID, newMemberId);
return new BdfMessageContext(meta, dependencies);
}
private BdfMessageContext validatePost(Message m, Group g, BdfList body,
String member_name, byte[] member_public_key)
String memberName, byte[] memberPublicKey)
throws InvalidMessageException, FormatException {
// The content is a BDF list with six elements
@@ -158,15 +171,13 @@ class GroupMessageValidator extends BdfMessageValidator {
// parent_id (raw or null)
// the identifier of the post to which this is a reply, if any
byte[] parent_id = body.getOptionalRaw(2);
if (parent_id != null) {
checkLength(parent_id, MessageId.LENGTH);
}
byte[] parentId = body.getOptionalRaw(2);
checkLength(parentId, MessageId.LENGTH);
// previous_message_id (raw)
// the identifier of the member's previous post or join message
byte[] previous_message_id = body.getRaw(3);
checkLength(previous_message_id, MessageId.LENGTH);
byte[] previousMessageId = body.getRaw(3);
checkLength(previousMessageId, MessageId.LENGTH);
// content (string)
String content = body.getString(4);
@@ -178,20 +189,25 @@ class GroupMessageValidator extends BdfMessageValidator {
checkLength(signature, 1, MAX_SIGNATURE_LENGTH);
// Verify Signature
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), member_name,
member_public_key, parent_id, previous_message_id, content);
clientHelper.verifySignature(signature, member_public_key, signed);
BdfList signed = BdfList.of(g.getId(), m.getTimestamp(), POST.getInt(),
memberName, memberPublicKey, parentId, previousMessageId,
content);
try {
clientHelper.verifySignature(signature, memberPublicKey, signed);
} catch (GeneralSecurityException e) {
throw new InvalidMessageException(e);
}
// The parent post, if any,
// and the member's previous message are dependencies
Collection<MessageId> dependencies = new ArrayList<MessageId>();
if (parent_id != null) dependencies.add(new MessageId(parent_id));
dependencies.add(new MessageId(previous_message_id));
if (parentId != null) dependencies.add(new MessageId(parentId));
dependencies.add(new MessageId(previousMessageId));
// Return the metadata and dependencies
BdfDictionary meta = new BdfDictionary();
if (parent_id != null) meta.put(KEY_PARENT_MSG_ID, parent_id);
meta.put(KEY_PREVIOUS_MSG_ID, previous_message_id);
if (parentId != null) meta.put(KEY_PARENT_MSG_ID, parentId);
meta.put(KEY_PREVIOUS_MSG_ID, previousMessageId);
return new BdfMessageContext(meta, dependencies);
}
@@ -200,9 +216,9 @@ class GroupMessageValidator extends BdfMessageValidator {
c.getDictionary().put(KEY_TIMESTAMP, time);
c.getDictionary().put(KEY_READ, false);
Author a = authorFactory.createAuthor(authorName, pubKey);
c.getDictionary().put(KEY_AUTHOR_ID, a.getId());
c.getDictionary().put(KEY_AUTHOR_NAME, authorName);
c.getDictionary().put(KEY_AUTHOR_PUBLIC_KEY, pubKey);
c.getDictionary().put(KEY_MEMBER_ID, a.getId());
c.getDictionary().put(KEY_MEMBER_NAME, authorName);
c.getDictionary().put(KEY_MEMBER_PUBLIC_KEY, pubKey);
}
}

View File

@@ -44,9 +44,9 @@ import static org.briarproject.api.identity.Author.Status.OURSELVES;
import static org.briarproject.api.privategroup.MessageType.JOIN;
import static org.briarproject.api.privategroup.MessageType.NEW_MEMBER;
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_MEMBER_ID;
import static org.briarproject.privategroup.Constants.KEY_MEMBER_NAME;
import static org.briarproject.privategroup.Constants.KEY_MEMBER_PUBLIC_KEY;
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;
@@ -141,8 +141,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
private MessageId getPreviousMsgId(Transaction txn, GroupId g)
throws DbException, FormatException {
BdfDictionary d = clientHelper.getGroupMetadataAsDictionary(txn, g);
byte[] previousMsgIdBytes = d.getOptionalRaw(KEY_PREVIOUS_MSG_ID);
if (previousMsgIdBytes == null) throw new DbException();
byte[] previousMsgIdBytes = d.getRaw(KEY_PREVIOUS_MSG_ID);
return new MessageId(previousMsgIdBytes);
}
@@ -191,9 +190,9 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
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());
meta.put(KEY_MEMBER_ID, m.getMember().getId());
meta.put(KEY_MEMBER_NAME, m.getMember().getName());
meta.put(KEY_MEMBER_PUBLIC_KEY, m.getMember().getPublicKey());
}
@Override
@@ -269,11 +268,10 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
clientHelper.getMessageMetadataAsDictionary(txn, g);
// get all authors we need to get the status for
Set<AuthorId> authors = new HashSet<AuthorId>();
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
BdfDictionary meta = entry.getValue();
for (BdfDictionary meta : metadata.values()) {
if (meta.getLong(KEY_TYPE) == NEW_MEMBER.getInt())
continue;
byte[] idBytes = meta.getRaw(KEY_AUTHOR_ID);
byte[] idBytes = meta.getRaw(KEY_MEMBER_ID);
authors.add(new AuthorId(idBytes));
}
// get statuses for all authors
@@ -308,9 +306,9 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
}
long timestamp = meta.getLong(KEY_TIMESTAMP);
AuthorId authorId = new AuthorId(meta.getRaw(KEY_AUTHOR_ID));
String name = meta.getString(KEY_AUTHOR_NAME);
byte[] publicKey = meta.getRaw(KEY_AUTHOR_PUBLIC_KEY);
AuthorId authorId = new AuthorId(meta.getRaw(KEY_MEMBER_ID));
String name = meta.getString(KEY_MEMBER_NAME);
byte[] publicKey = meta.getRaw(KEY_MEMBER_PUBLIC_KEY);
Author author = new Author(authorId, name, publicKey);
Status status;
@@ -361,8 +359,8 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
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))) {
if (!Arrays.equals(meta.getRaw(KEY_MEMBER_ID),
newMemberMeta.getRaw(KEY_MEMBER_ID))) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
@@ -401,8 +399,16 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements
return false;
}
// previous message must be from same member
if (!Arrays.equals(meta.getRaw(KEY_AUTHOR_ID),
previousMeta.getRaw(KEY_AUTHOR_ID))) {
if (!Arrays.equals(meta.getRaw(KEY_MEMBER_ID),
previousMeta.getRaw(KEY_MEMBER_ID))) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;
}
// previous message must be a POST or JOIN
MessageType previousType = MessageType
.valueOf(previousMeta.getLong(KEY_TYPE).intValue());
if (previousType != JOIN && previousType != POST) {
// FIXME throw new InvalidMessageException() (#643)
db.deleteMessage(txn, m.getId());
return false;