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 6b149c13fa0269b7915e08ed4638c6e1e14c2a40..0d79b1b027ff42e78632da3b244acc08f8fa73b9 100644 --- a/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java +++ b/briar-android-tests/src/test/java/org/briarproject/PrivateGroupManagerTest.java @@ -212,6 +212,7 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { defaultInit(); // create and add test message with no previousMsgId + @SuppressWarnings("ConstantConditions") GroupMessage msg = groupMessageFactory .createGroupMessage(groupId0, clock.currentTimeMillis(), null, author0, "test", null); @@ -484,6 +485,35 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { } } + @Test + public void testJoinMessages() throws Exception { + defaultInit(); + + Collection<GroupMessageHeader> headers0 = + groupManager0.getHeaders(groupId0); + for (GroupMessageHeader h : headers0) { + if (h instanceof JoinMessageHeader) { + JoinMessageHeader j = (JoinMessageHeader) h; + // all relationships of the creator are visible + assertEquals(VISIBLE, j.getVisibility()); + } + } + + Collection<GroupMessageHeader> headers1 = + groupManager1.getHeaders(groupId0); + for (GroupMessageHeader h : headers1) { + if (h instanceof JoinMessageHeader) { + JoinMessageHeader j = (JoinMessageHeader) h; + if (h.getAuthor().equals(author1)) + // we are visible to ourselves + assertEquals(VISIBLE, j.getVisibility()); + else + // our relationship to the creator is visible + assertEquals(VISIBLE, j.getVisibility()); + } + } + } + @Test public void testRevealingRelationships() throws Exception { defaultInit(); @@ -568,6 +598,51 @@ public class PrivateGroupManagerTest extends BriarIntegrationTest { assertEquals(REVEALED_BY_CONTACT, m.getVisibility()); } } + + // assert that join messages reflect revealed relationship + Collection<GroupMessageHeader> headers1 = + groupManager1.getHeaders(groupId0); + for (GroupMessageHeader h : headers1) { + if (h instanceof JoinMessageHeader) { + JoinMessageHeader j = (JoinMessageHeader) h; + if (h.getAuthor().equals(author2)) + // 1 revealed the relationship to 2 + assertEquals(REVEALED_BY_YOU, j.getVisibility()); + else + // 1's other relationship (to 1 and creator) are visible + assertEquals(VISIBLE, j.getVisibility()); + } + } + Collection<GroupMessageHeader> headers2 = + groupManager2.getHeaders(groupId0); + for (GroupMessageHeader h : headers2) { + if (h instanceof JoinMessageHeader) { + JoinMessageHeader j = (JoinMessageHeader) h; + if (h.getAuthor().equals(author1)) + // 2's relationship was revealed by 1 + assertEquals(REVEALED_BY_CONTACT, j.getVisibility()); + else + // 2's other relationship (to 2 and creator) are visible + assertEquals(VISIBLE, j.getVisibility()); + } + } + } + + @Test + public void testDissolveGroup() throws Exception { + defaultInit(); + + // group is not dissolved initially + assertFalse(groupManager0.isDissolved(groupId0)); + + // creator dissolves group + Transaction txn0 = db0.startTransaction(false); + groupManager0.markGroupDissolved(txn0, groupId0); + db0.commitTransaction(txn0); + db0.endTransaction(txn0); + + // group is dissolved now + assertTrue(groupManager0.isDissolved(groupId0)); } @After diff --git a/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java b/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java index ef8c3b337d72124fd5d42b075f5e8edea894a53f..8b14717a6e622d9f3a52f745673bb90e46088d39 100644 --- a/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java +++ b/briar-api/src/org/briarproject/api/privategroup/JoinMessageHeader.java @@ -1,10 +1,6 @@ package org.briarproject.api.privategroup; -import org.briarproject.api.identity.Author; import org.briarproject.api.nullsafety.NotNullByDefault; -import org.briarproject.api.sync.GroupId; -import org.briarproject.api.sync.MessageId; -import org.jetbrains.annotations.Nullable; import javax.annotation.concurrent.Immutable; @@ -12,10 +8,16 @@ import javax.annotation.concurrent.Immutable; @NotNullByDefault public class JoinMessageHeader extends GroupMessageHeader { - public JoinMessageHeader(GroupId groupId, MessageId id, - @Nullable MessageId parentId, long timestamp, Author author, - Author.Status authorStatus, boolean read) { - super(groupId, id, parentId, timestamp, author, authorStatus, read); + private final Visibility visibility; + + public JoinMessageHeader(GroupMessageHeader h, Visibility visibility) { + super(h.getGroupId(), h.getId(), h.getParentId(), h.getTimestamp(), + h.getAuthor(), h.getAuthorStatus(), h.isRead()); + this.visibility = visibility; + } + + public Visibility getVisibility() { + return visibility; } } diff --git a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java index a407f1fcf3b1afee01f30a260230ba30647ea08a..42ba0d9b01e355d05f42e5a3c3864f27906c30cb 100644 --- a/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java +++ b/briar-core/src/org/briarproject/privategroup/PrivateGroupManagerImpl.java @@ -110,7 +110,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements GroupMessage joinMsg, boolean creator) throws DbException { try { db.addGroup(txn, group.getGroup()); - AuthorId creatorId = joinMsg.getMember().getId(); + AuthorId creatorId = group.getCreator().getId(); BdfDictionary meta = BdfDictionary.of( new BdfEntry(GROUP_KEY_MEMBERS, new BdfList()), new BdfEntry(GROUP_KEY_CREATOR_ID, creatorId), @@ -134,6 +134,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements addMember(txn, m.getMessage().getGroupId(), m.getMember(), VISIBLE); setPreviousMsgId(txn, m.getMessage().getGroupId(), m.getMessage().getId()); + attachJoinMessageAddedEvent(txn, m.getMessage(), meta, true, VISIBLE); } @Override @@ -335,11 +336,22 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements for (AuthorId id : authors) { statuses.put(id, identityManager.getAuthorStatus(txn, id)); } - // Parse the metadata + // get current visibilities for join messages + Map<Author, Visibility> visibilities = getMembers(txn, g); + // parse the metadata for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) { BdfDictionary meta = entry.getValue(); - headers.add(getGroupMessageHeader(txn, g, entry.getKey(), meta, - statuses)); + if (meta.getLong(KEY_TYPE) == JOIN.getInt()) { + Author member = getAuthor(meta); + Visibility v = visibilities.get(member); + headers.add( + getJoinMessageHeader(txn, g, entry.getKey(), meta, + statuses, v)); + } else { + headers.add( + getGroupMessageHeader(txn, g, entry.getKey(), meta, + statuses)); + } } db.commitTransaction(txn); return headers; @@ -369,19 +381,17 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements } boolean read = meta.getBoolean(KEY_READ); - if (meta.getLong(KEY_TYPE) == JOIN.getInt()) { - return new JoinMessageHeader(g, id, parentId, timestamp, author, - status, read); - } return new GroupMessageHeader(g, id, parentId, timestamp, author, status, read); } - private GroupMessageHeader getGroupMessageHeader(Transaction txn, GroupId g, - MessageId id, BdfDictionary meta) - throws DbException, FormatException { - return getGroupMessageHeader(txn, g, id, meta, - Collections.<AuthorId, Status>emptyMap()); + private JoinMessageHeader getJoinMessageHeader(Transaction txn, GroupId g, + MessageId id, BdfDictionary meta, Map<AuthorId, Status> statuses, + Visibility v) throws DbException, FormatException { + + GroupMessageHeader header = + getGroupMessageHeader(txn, g, id, meta, statuses); + return new JoinMessageHeader(header, v); } @Override @@ -494,7 +504,7 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements addMember(txn, m.getGroupId(), member, v); // track message and broadcast event trackIncomingMessage(txn, m); - attachGroupMessageAddedEvent(txn, m, meta, false); + attachJoinMessageAddedEvent(txn, m, meta, false, v); } private void handleGroupMessage(Transaction txn, Message m, @@ -538,7 +548,18 @@ public class PrivateGroupManagerImpl extends BdfIncomingMessageHook implements BdfDictionary meta, boolean local) throws DbException, FormatException { GroupMessageHeader h = - getGroupMessageHeader(txn, m.getGroupId(), m.getId(), meta); + getGroupMessageHeader(txn, m.getGroupId(), m.getId(), meta, + Collections.<AuthorId, Status>emptyMap()); + Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local); + txn.attach(e); + } + + private void attachJoinMessageAddedEvent(Transaction txn, Message m, + BdfDictionary meta, boolean local, Visibility v) + throws DbException, FormatException { + JoinMessageHeader h = + getJoinMessageHeader(txn, m.getGroupId(), m.getId(), meta, + Collections.<AuthorId, Status>emptyMap(), v); Event e = new GroupMessageAddedEvent(m.getGroupId(), h, local); txn.attach(e); }