diff --git a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java index 00609e4eba225a85ce8419d28d33c00e76a8f69f..18a6d5eb438981b0dd3a3731e787a37c106fa5e1 100644 --- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java @@ -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)); diff --git a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTestComponent.java index 7461eb02bcf81e54fe21b008600b587b7759dc36..68191f4f87b7099a9723749fb5d12184a050ab6a 100644 --- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTestComponent.java @@ -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, diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java index 8d61bbff83dd964ed230113e0053f7b4f1027279..abbf10d423508e41b7459f74f389e48f9ea67b2d 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupControllerImpl.java @@ -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()); } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageAdapter.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageAdapter.java index 2a9c75a009f1d4e2c79851713dc1256a2ae74236..58eec29385fc37b8a7e63a38fd626c7970e15c03 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageAdapter.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageAdapter.java @@ -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); } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageItem.java b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageItem.java index b961fd3f6bd5d34d3c30b4b280015a74dd78f3d5..9deb0424e574fc582b56dc687246c3f74d3438fb 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageItem.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/GroupMessageItem.java @@ -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; + } + } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItem.java b/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItem.java index e21399127a16c29b07449b15f159da11f08ffa3c..44c732ffd48970cc59a4abd2a92e4bebac232219 100644 --- a/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItem.java +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItem.java @@ -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; + } + } diff --git a/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItemHolder.java b/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItemHolder.java new file mode 100644 index 0000000000000000000000000000000000000000..8a2942a4c46f44a442df7f1e7214d118752dca3e --- /dev/null +++ b/briar-android/src/org/briarproject/android/privategroup/conversation/JoinMessageItemHolder.java @@ -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)); + } + +} diff --git a/briar-android/src/org/briarproject/android/threaded/BaseThreadItemViewHolder.java b/briar-android/src/org/briarproject/android/threaded/BaseThreadItemViewHolder.java index 47ed3502fa1dbb7b1b546c5167864273784f524a..af8e800b33ed2d308198ffc58a914279a10abea2 100644 --- a/briar-android/src/org/briarproject/android/threaded/BaseThreadItemViewHolder.java +++ b/briar-android/src/org/briarproject/android/threaded/BaseThreadItemViewHolder.java @@ -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; diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadItem.java b/briar-android/src/org/briarproject/android/threaded/ThreadItem.java index c4281e9ac1a5ea1b4f96739403151ea868fa738d..e4c055e2b39a31c228ff72c77964d76dd48a5ce2 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadItem.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadItem.java @@ -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; } + } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java index 9e93f8f0714cf10635060ff28213e154e646c9be..21425ced3815804046343b2c9fb8bd404a9a3994 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadItemAdapter.java @@ -316,7 +316,7 @@ public class ThreadItemAdapter<I extends ThreadItem> revision++; } - protected interface ThreadItemListener<I> { + public interface ThreadItemListener<I> { void onItemVisible(I item); diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListController.java b/briar-android/src/org/briarproject/android/threaded/ThreadListController.java index 43ce1d5c283dbe154b17e66976fef62451a4ee02..f2e7570a820d89f66cf7e3452d74b3a1a4256514 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListController.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListController.java @@ -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(); } } diff --git a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java index cf6ffb8d6cfc33657d7b0905da404e9e78a19958..6ea72c892357f669bc1fcd8d322ddca3b4b787cc 100644 --- a/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java +++ b/briar-android/src/org/briarproject/android/threaded/ThreadListControllerImpl.java @@ -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; diff --git a/briar-api/src/org/briarproject/api/clients/ClientHelper.java b/briar-api/src/org/briarproject/api/clients/ClientHelper.java index 4622431d407532206c8ba19499bd09e0062930a8..b24c9d2b715456a4137bef4246209bdc5853a741 100644 --- a/briar-api/src/org/briarproject/api/clients/ClientHelper.java +++ b/briar-api/src/org/briarproject/api/clients/ClientHelper.java @@ -84,6 +84,6 @@ public interface ClientHelper { throws FormatException, GeneralSecurityException; void verifySignature(byte[] sig, byte[] publicKey, BdfList signed) - throws InvalidMessageException; + throws FormatException, GeneralSecurityException; } diff --git a/briar-api/src/org/briarproject/api/privategroup/MessageType.java b/briar-api/src/org/briarproject/api/privategroup/MessageType.java index afe6a07d1c3dd17b37fe7e4498b45b3fb3e06402..7cffb0df312973ac3b4955547037782aa7a294fe 100644 --- a/briar-api/src/org/briarproject/api/privategroup/MessageType.java +++ b/briar-api/src/org/briarproject/api/privategroup/MessageType.java @@ -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; } -} \ No newline at end of file +} diff --git a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java index b01cd88c7f6d03c41d2593aebe5229aa326850fe..49bee81f8788f1edacda917d4d0244544fe001e8 100644 --- a/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java +++ b/briar-api/src/org/briarproject/api/privategroup/PrivateGroupManager.java @@ -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. */ diff --git a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java index 75b4797d0a92ab3e78d3cd4a6574ad9988e85e01..cd2347bc65ea79d8b3110ff28b556fab4a169eb4 100644 --- a/briar-core/src/org/briarproject/blogs/BlogPostValidator.java +++ b/briar-core/src/org/briarproject/blogs/BlogPostValidator.java @@ -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(); diff --git a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java index 612f80e815280b7276bd5c07dc7ced684307e314..9c0354419a0250f0ae85c122e7da4519d99c1f48 100644 --- a/briar-core/src/org/briarproject/clients/ClientHelperImpl.java +++ b/briar-core/src/org/briarproject/clients/ClientHelperImpl.java @@ -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"); } } diff --git a/briar-core/src/org/briarproject/forum/ForumPostValidator.java b/briar-core/src/org/briarproject/forum/ForumPostValidator.java index f25181f1ce69032ada72bdfcba2691124d148d8f..ce4bddb4364212326571fdce95d9dee020749dfc 100644 --- a/briar-core/src/org/briarproject/forum/ForumPostValidator.java +++ b/briar-core/src/org/briarproject/forum/ForumPostValidator.java @@ -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(); diff --git a/briar-core/src/org/briarproject/privategroup/Constants.java b/briar-core/src/org/briarproject/privategroup/Constants.java index 3c83d232618f074ac612e095eba4772aebf9bd95..12219f78d789193398edea716259c41cba7f7847 100644 --- a/briar-core/src/org/briarproject/privategroup/Constants.java +++ b/briar-core/src/org/briarproject/privategroup/Constants.java @@ -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"; } diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java b/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java index 4569bc50d5d052f886e609b13f49c7d141ff61a1..228b6425448958ae1ebaee41e372160b8092a078 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageFactoryImpl.java @@ -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); diff --git a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java index 01385793966e2ad89f6321c4a84edb67909c237b..25bf14730cc4b988b91728de14f9ef10fa22f2f7 100644 --- a/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java +++ b/briar-core/src/org/briarproject/privategroup/GroupMessageValidator.java @@ -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); } } diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java index eb3a888f0406ddd475772b8efafd74946911d4b6..769e065b87a200cd8e80b2cbcc64bb4c42fe5437 100644 --- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java +++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java @@ -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;