diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java index a9e21a6b0..cf9d4eff3 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java @@ -209,6 +209,18 @@ public class ForumManagerTest { deliveryWaiter.await(TIMEOUT, 1); assertEquals(1, forumManager1.getPostHeaders(g).size()); + // add another forum post + time = clock.currentTimeMillis(); + ForumPost post2 = createForumPost(g, null, "b", time); + forumManager1.addLocalPost(post2); + assertEquals(1, forumManager0.getPostHeaders(g).size()); + assertEquals(2, forumManager1.getPostHeaders(g).size()); + + // send post to 0 + sync1To0(); + deliveryWaiter.await(TIMEOUT, 1); + assertEquals(2, forumManager1.getPostHeaders(g).size()); + stopLifecycles(); } diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java index 522ca424e..444f2f4c8 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTest.java @@ -9,6 +9,10 @@ import org.briarproject.api.clients.SessionId; import org.briarproject.api.contact.Contact; import org.briarproject.api.contact.ContactId; import org.briarproject.api.contact.ContactManager; +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.KeyPair; +import org.briarproject.api.crypto.KeyParser; +import org.briarproject.api.crypto.PrivateKey; import org.briarproject.api.crypto.SecretKey; import org.briarproject.api.data.BdfList; import org.briarproject.api.db.DatabaseComponent; @@ -23,6 +27,9 @@ import org.briarproject.api.event.MessageStateChangedEvent; import org.briarproject.api.forum.Forum; import org.briarproject.api.forum.ForumInvitationMessage; import org.briarproject.api.forum.ForumManager; +import org.briarproject.api.forum.ForumPost; +import org.briarproject.api.forum.ForumPostFactory; +import org.briarproject.api.forum.ForumPostHeader; import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.AuthorFactory; import org.briarproject.api.identity.IdentityManager; @@ -62,7 +69,6 @@ import javax.inject.Inject; import static org.briarproject.TestPluginsModule.MAX_LATENCY; import static org.briarproject.api.forum.ForumConstants.FORUM_SALT_LENGTH; -import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.api.sharing.SharingConstants.SHARE_MSG_TYPE_INVITATION; import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.api.sync.ValidationManager.State.INVALID; @@ -87,6 +93,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase { Clock clock; @Inject AuthorFactory authorFactory; + @Inject + ForumPostFactory forumPostFactory; + @Inject + CryptoComponent cryptoComponent; // objects accessed from background threads need to be volatile private volatile ForumSharingManager forumSharingManager0; @@ -173,7 +183,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailable().size()); + assertEquals(0, forumSharingManager0.getInvited().size()); assertEquals(1, forumManager1.getForums().size()); // invitee has one invitation message from sharer @@ -223,10 +233,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was not added - assertEquals(0, forumSharingManager0.getAvailable().size()); + assertEquals(0, forumSharingManager0.getInvited().size()); assertEquals(0, forumManager1.getForums().size()); // forum is no longer available to invitee who declined - assertEquals(0, forumSharingManager1.getAvailable().size()); + assertEquals(0, forumSharingManager1.getInvited().size()); // invitee has one invitation message from sharer List list = @@ -273,7 +283,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailable().size()); + assertEquals(0, forumSharingManager0.getInvited().size()); assertEquals(1, forumManager1.getForums().size()); assertTrue(forumManager1.getForums().contains(forum0)); @@ -293,7 +303,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { syncToSharer(); // forum is gone - assertEquals(0, forumSharingManager0.getAvailable().size()); + assertEquals(0, forumSharingManager0.getInvited().size()); assertEquals(0, forumManager1.getForums().size()); // sharer no longer shares forum with invitee @@ -333,7 +343,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener0.responseReceived); // forum was added successfully - assertEquals(0, forumSharingManager0.getAvailable().size()); + assertEquals(0, forumSharingManager0.getInvited().size()); assertEquals(1, forumManager1.getForums().size()); assertTrue(forumManager1.getForums().contains(forum0)); @@ -384,8 +394,9 @@ public class ForumSharingIntegrationTest extends BriarTestCase { // sharer un-subscribes from forum forumManager0.removeForum(forum0); - // from here on expect the response to fail with a DbException - thrown.expect(DbException.class); + // from here on expect the response to fail with an AssertionError, + // because there is in fact no invited forum available anymore + thrown.expect(AssertionError.class); // sync first request message and leave message syncToInvitee(); @@ -393,7 +404,7 @@ public class ForumSharingIntegrationTest extends BriarTestCase { assertTrue(listener1.requestReceived); // invitee has no forums available - assertEquals(0, forumSharingManager1.getAvailable().size()); + assertEquals(0, forumSharingManager1.getInvited().size()); } finally { stopLifecycles(); } @@ -699,10 +710,11 @@ public class ForumSharingIntegrationTest extends BriarTestCase { deliverMessage(sync2, contactId2, sync1, contactId1, "Sharer2 to Invitee"); - // make sure we have only one forum available - Collection forums = - forumSharingManager1.getAvailable(); + // make sure we now have two invitations to the same forum available + Collection forums = forumSharingManager1.getInvited(); assertEquals(1, forums.size()); + assertEquals(2, + forumSharingManager1.getSharedBy(forum0.getId()).size()); // make sure both sharers actually share the forum Collection contacts = @@ -731,6 +743,119 @@ public class ForumSharingIntegrationTest extends BriarTestCase { } } + @Test + public void testSyncAfterReSharing() throws Exception { + startLifecycles(); + try { + // initialize and let invitee accept all requests + defaultInit(true); + + // send invitation + forumSharingManager0 + .sendInvitation(forum0.getId(), contactId1, "Hi!"); + + // sync first request message + syncToInvitee(); + eventWaiter.await(TIMEOUT, 1); + + // sync response back + syncToSharer(); + eventWaiter.await(TIMEOUT, 1); + + // sharer posts into the forum + long time = clock.currentTimeMillis(); + byte[] body = TestUtils.getRandomBytes(42); + KeyParser keyParser = cryptoComponent.getSignatureKeyParser(); + PrivateKey key = keyParser.parsePrivateKey(author0.getPrivateKey()); + ForumPost p = forumPostFactory + .createPseudonymousPost(forum0.getId(), time, null, author0, + "text/plain", body, key); + forumManager0.addLocalPost(p); + + // sync forum post + syncToInvitee(); + + // make sure forum post arrived + Collection headers = + forumManager1.getPostHeaders(forum0.getId()); + assertEquals(1, headers.size()); + ForumPostHeader header = headers.iterator().next(); + assertEquals(p.getMessage().getId(), header.getId()); + assertEquals(author0, header.getAuthor()); + + // now invitee creates a post + time = clock.currentTimeMillis(); + body = TestUtils.getRandomBytes(42); + key = keyParser.parsePrivateKey(author1.getPrivateKey()); + p = forumPostFactory + .createPseudonymousPost(forum0.getId(), time, null, author1, + "text/plain", body, key); + forumManager1.addLocalPost(p); + + // sync forum post + syncToSharer(); + + // make sure forum post arrived + headers = forumManager1.getPostHeaders(forum0.getId()); + assertEquals(2, headers.size()); + boolean found = false; + for (ForumPostHeader h : headers) { + if (p.getMessage().getId().equals(h.getId())) { + found = true; + assertEquals(author1, h.getAuthor()); + } + } + assertTrue(found); + + // contacts remove each other + contactManager0.removeContact(contactId1); + contactManager1.removeContact(contactId0); + contactManager1.removeContact(contactId2); + contactManager2.removeContact(contactId21); + + // contacts add each other back + addDefaultContacts(); + + // send invitation again + forumSharingManager0 + .sendInvitation(forum0.getId(), contactId1, "Hi!"); + + // sync first request message + syncToInvitee(); + eventWaiter.await(TIMEOUT, 1); + + // sync response back + syncToSharer(); + eventWaiter.await(TIMEOUT, 1); + + // now invitee creates a post + time = clock.currentTimeMillis(); + body = TestUtils.getRandomBytes(42); + key = keyParser.parsePrivateKey(author1.getPrivateKey()); + p = forumPostFactory + .createPseudonymousPost(forum0.getId(), time, null, author1, + "text/plain", body, key); + forumManager1.addLocalPost(p); + + // sync forum post + syncToSharer(); + + // make sure forum post arrived + headers = forumManager1.getPostHeaders(forum0.getId()); + assertEquals(3, headers.size()); + found = false; + for (ForumPostHeader h : headers) { + if (p.getMessage().getId().equals(h.getId())) { + found = true; + assertEquals(author1, h.getAuthor()); + } + } + assertTrue(found); + } finally { + stopLifecycles(); + } + } + @After public void tearDown() throws InterruptedException { @@ -753,6 +878,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase { LOG.info("TEST: Sharer received message in group " + event.getMessage().getGroupId().hashCode()); msgWaiter.resume(); + } else if (s == DELIVERED && !event.isLocal() && + c.equals(forumManager0.getClientId())) { + LOG.info("TEST: Sharer received forum post"); + msgWaiter.resume(); } } else if (e instanceof ForumInvitationResponseReceivedEvent) { ForumInvitationResponseReceivedEvent event = @@ -807,6 +936,10 @@ public class ForumSharingIntegrationTest extends BriarTestCase { LOG.info("TEST: Invitee received message in group " + event.getMessage().getGroupId().hashCode()); msgWaiter.resume(); + } else if (s == DELIVERED && !event.isLocal() && + c.equals(forumManager0.getClientId())) { + LOG.info("TEST: Invitee received forum post"); + msgWaiter.resume(); } } else if (e instanceof ForumInvitationReceivedEvent) { ForumInvitationReceivedEvent event = @@ -815,6 +948,8 @@ public class ForumSharingIntegrationTest extends BriarTestCase { if (!answer) return; Forum f = event.getForum(); try { + eventWaiter.assertEquals(1, + forumSharingManager1.getInvited().size()); Contact c = contactManager1.getContact(event.getContactId()); forumSharingManager1.respondToInvitation(f, c, accept); @@ -866,17 +1001,22 @@ public class ForumSharingIntegrationTest extends BriarTestCase { } private void addDefaultIdentities() throws DbException { + KeyPair keyPair = cryptoComponent.generateSignatureKeyPair(); author0 = authorFactory.createLocalAuthor(SHARER, - TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - TestUtils.getRandomBytes(123)); + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); identityManager0.addLocalAuthor(author0); + + keyPair = cryptoComponent.generateSignatureKeyPair(); author1 = authorFactory.createLocalAuthor(INVITEE, - TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - TestUtils.getRandomBytes(123)); + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); identityManager1.addLocalAuthor(author1); + + keyPair = cryptoComponent.generateSignatureKeyPair(); author2 = authorFactory.createLocalAuthor(SHARER2, - TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - TestUtils.getRandomBytes(123)); + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); identityManager2.addLocalAuthor(author2); } diff --git a/briar-android/AndroidManifest.xml b/briar-android/AndroidManifest.xml index ea3126ed0..03664f0ef 100644 --- a/briar-android/AndroidManifest.xml +++ b/briar-android/AndroidManifest.xml @@ -100,8 +100,8 @@ + android:background="?attr/selectableItemBackground" + android:paddingTop="@dimen/listitem_horizontal_margin"> @@ -34,38 +36,55 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/forumNameView" - android:layout_marginBottom="-8dp" + android:layout_marginEnd="@dimen/listitem_horizontal_margin" + android:layout_marginRight="@dimen/listitem_horizontal_margin" android:layout_toEndOf="@+id/avatarView" android:layout_toRightOf="@+id/avatarView" android:paddingTop="@dimen/margin_medium" - android:textColor="@android:color/secondary_text_light" + android:textColor="@color/briar_text_secondary" android:textSize="@dimen/text_size_small" tools:text="Shared by Megalox"/> + +