From f4c5855dd8dba6be943e516fcaae6fe41615e3ae Mon Sep 17 00:00:00 2001 From: akwizgran <michael@briarproject.org> Date: Mon, 16 Apr 2018 14:55:02 +0100 Subject: [PATCH] Use client versioning for private groups. --- .../invitation/AbstractProtocolEngine.java | 16 +++- .../invitation/CreatorProtocolEngine.java | 8 +- .../privategroup/invitation/CreatorState.java | 20 +++- .../invitation/GroupInvitationConstants.java | 1 + .../GroupInvitationManagerImpl.java | 91 ++++++++++++++++++- .../invitation/GroupInvitationModule.java | 15 ++- .../invitation/InviteeProtocolEngine.java | 14 ++- .../privategroup/invitation/InviteeState.java | 23 ++++- .../invitation/PeerProtocolEngine.java | 8 +- .../privategroup/invitation/PeerState.java | 23 ++++- .../invitation/ProtocolEngineFactoryImpl.java | 13 ++- .../invitation/SessionEncoderImpl.java | 2 + .../invitation/SessionParser.java | 2 + .../invitation/SessionParserImpl.java | 6 ++ .../briar/privategroup/invitation/State.java | 4 + .../AbstractProtocolEngineTest.java | 10 +- .../invitation/CreatorProtocolEngineTest.java | 7 +- .../GroupInvitationManagerImplTest.java | 16 +++- .../invitation/InviteeProtocolEngineTest.java | 9 +- .../invitation/PeerProtocolEngineTest.java | 7 +- 20 files changed, 251 insertions(+), 44 deletions(-) diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java index c68f7b6625..c37c267251 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngine.java @@ -10,6 +10,7 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; @@ -28,6 +29,8 @@ import java.util.Map; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; +import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID; +import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_VERSION; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; @@ -45,6 +48,7 @@ abstract class AbstractProtocolEngine<S extends Session> protected final PrivateGroupFactory privateGroupFactory; protected final MessageTracker messageTracker; + private final ClientVersioningManager clientVersioningManager; private final GroupMessageFactory groupMessageFactory; private final IdentityManager identityManager; private final MessageParser messageParser; @@ -52,6 +56,7 @@ abstract class AbstractProtocolEngine<S extends Session> private final Clock clock; AbstractProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, @@ -60,6 +65,7 @@ abstract class AbstractProtocolEngine<S extends Session> Clock clock) { this.db = db; this.clientHelper = clientHelper; + this.clientVersioningManager = clientVersioningManager; this.privateGroupManager = privateGroupManager; this.privateGroupFactory = privateGroupFactory; this.groupMessageFactory = groupMessageFactory; @@ -90,10 +96,14 @@ abstract class AbstractProtocolEngine<S extends Session> return expected != null && dependency.equals(expected); } - void setPrivateGroupVisibility(Transaction txn, S session, Visibility v) - throws DbException, FormatException { + void setPrivateGroupVisibility(Transaction txn, S session, + Visibility preferred) throws DbException, FormatException { + // Apply min of preferred visibility and client's visibility ContactId contactId = getContactId(txn, session.getContactGroupId()); - db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), v); + Visibility client = clientVersioningManager.getClientVisibility(txn, + contactId, CLIENT_ID, CLIENT_VERSION); + Visibility min = Visibility.min(preferred, client); + db.setGroupVisibility(txn, contactId, session.getPrivateGroupId(), min); } Message sendInviteMessage(Transaction txn, S session, diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java index ec5315a6d0..62030a09b7 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngine.java @@ -8,6 +8,7 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; @@ -36,15 +37,16 @@ import static org.briarproject.briar.privategroup.invitation.CreatorState.START; class CreatorProtocolEngine extends AbstractProtocolEngine<CreatorSession> { CreatorProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, IdentityManager identityManager, MessageParser messageParser, MessageEncoder messageEncoder, MessageTracker messageTracker, Clock clock) { - super(db, clientHelper, privateGroupManager, privateGroupFactory, - groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + super(db, clientHelper, clientVersioningManager, privateGroupManager, + privateGroupFactory, groupMessageFactory, identityManager, + messageParser, messageEncoder, messageTracker, clock); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java index 4afe89c4d8..6fe69a08c9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/CreatorState.java @@ -2,19 +2,30 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group.Visibility; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; + @Immutable @NotNullByDefault enum CreatorState implements State { - START(0), INVITED(1), JOINED(2), LEFT(3), DISSOLVED(4), ERROR(5); + START(0, INVISIBLE), + INVITED(1, INVISIBLE), + JOINED(2, SHARED), + LEFT(3, INVISIBLE), + DISSOLVED(4, INVISIBLE), + ERROR(5, INVISIBLE); private final int value; + private final Visibility visibility; - CreatorState(int value) { + CreatorState(int value, Visibility visibility) { this.value = value; + this.visibility = visibility; } @Override @@ -22,6 +33,11 @@ enum CreatorState implements State { return value; } + @Override + public Visibility getVisibility() { + return visibility; + } + static CreatorState fromValue(int value) throws FormatException { for (CreatorState s : values()) if (s.value == value) return s; throw new FormatException(); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java index a9a6ef0929..90c0fcd299 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationConstants.java @@ -15,6 +15,7 @@ interface GroupInvitationConstants { String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted"; // Session keys + String SESSION_KEY_IS_SESSION = "isSession"; String SESSION_KEY_SESSION_ID = "sessionId"; String SESSION_KEY_PRIVATE_GROUP_ID = "privateGroupId"; String SESSION_KEY_LAST_LOCAL_MESSAGE_ID = "lastLocalMessageId"; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java index 5ae9a3f81b..6275fad703 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java @@ -16,7 +16,10 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Client; +import org.briarproject.bramble.api.sync.ClientVersioningManager; +import org.briarproject.bramble.api.sync.ClientVersioningManager.ClientVersioningHook; import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; @@ -36,15 +39,17 @@ import org.briarproject.briar.client.ConversationClientImpl; import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.logging.Logger; import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; -import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static java.util.logging.Level.INFO; import static org.briarproject.briar.privategroup.invitation.CreatorState.START; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; @@ -59,8 +64,12 @@ import static org.briarproject.briar.privategroup.invitation.Role.PEER; @NotNullByDefault class GroupInvitationManagerImpl extends ConversationClientImpl implements GroupInvitationManager, Client, ContactHook, - PrivateGroupHook { + PrivateGroupHook, ClientVersioningHook { + private static final Logger LOG = + Logger.getLogger(GroupInvitationManagerImpl.class.getName()); + + private final ClientVersioningManager clientVersioningManager; private final ContactGroupFactory contactGroupFactory; private final PrivateGroupFactory privateGroupFactory; private final PrivateGroupManager privateGroupManager; @@ -73,8 +82,9 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Inject GroupInvitationManagerImpl(DatabaseComponent db, - ClientHelper clientHelper, MetadataParser metadataParser, - MessageTracker messageTracker, + ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, + MetadataParser metadataParser, MessageTracker messageTracker, ContactGroupFactory contactGroupFactory, PrivateGroupFactory privateGroupFactory, PrivateGroupManager privateGroupManager, @@ -82,6 +92,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl SessionEncoder sessionEncoder, ProtocolEngineFactory engineFactory) { super(db, clientHelper, metadataParser, messageTracker); + this.clientVersioningManager = clientVersioningManager; this.contactGroupFactory = contactGroupFactory; this.privateGroupFactory = privateGroupFactory; this.privateGroupManager = privateGroupManager; @@ -110,7 +121,11 @@ class GroupInvitationManagerImpl extends ConversationClientImpl Group g = getContactGroup(c); // Store the group and share it with the contact db.addGroup(txn, g); - db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED); + Visibility client = clientVersioningManager.getClientVisibility(txn, + c.getId(), CLIENT_ID, CLIENT_VERSION); + if (LOG.isLoggable(INFO)) + LOG.info("Applying visibility " + client + " to new contact group"); + db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group BdfDictionary meta = new BdfDictionary(); meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt()); @@ -565,6 +580,72 @@ class GroupInvitationManagerImpl extends ConversationClientImpl } } + @Override + public void onClientVisibilityChanging(Transaction txn, Contact c, + Visibility v) throws DbException { + // Apply the client's visibility to the contact group + if (LOG.isLoggable(INFO)) + LOG.info("Applying visibility " + v + " to contact group"); + Group g = getContactGroup(c); + db.setGroupVisibility(txn, c.getId(), g.getId(), v); + } + + ClientVersioningHook getPrivateGroupClientVersioningHook() { + return this::onPrivateGroupClientVisibilityChanging; + } + + private void onPrivateGroupClientVisibilityChanging(Transaction txn, + Contact c, Visibility client) throws DbException { + try { + Collection<Group> shareables = + db.getGroups(txn, PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.CLIENT_VERSION); + Map<GroupId, Visibility> m = getPreferredVisibilities(txn, c); + for (Group g : shareables) { + Visibility preferred = m.get(g.getId()); + if (preferred == null) continue; // No session for this group + // Apply min of preferred visibility and client's visibility + Visibility min = Visibility.min(preferred, client); + if (LOG.isLoggable(INFO)) { + LOG.info("Applying visibility " + min + + " to private group, preferred " + preferred + + ", client " + client); + } + db.setGroupVisibility(txn, c.getId(), g.getId(), min); + } + } catch (FormatException e) { + throw new DbException(e); + } + } + + private Map<GroupId, Visibility> getPreferredVisibilities(Transaction txn, + Contact c) throws DbException, FormatException { + GroupId contactGroupId = getContactGroup(c).getId(); + BdfDictionary query = sessionParser.getAllSessionsQuery(); + Map<MessageId, BdfDictionary> results = clientHelper + .getMessageMetadataAsDictionary(txn, contactGroupId, query); + Map<GroupId, Visibility> m = new HashMap<>(); + for (BdfDictionary d : results.values()) { + Role role = sessionParser.getRole(d); + if (role == CREATOR) { + CreatorSession s = + sessionParser.parseCreatorSession(contactGroupId, d); + m.put(s.getPrivateGroupId(), s.getState().getVisibility()); + } else if (role == INVITEE) { + InviteeSession s = + sessionParser.parseInviteeSession(contactGroupId, d); + m.put(s.getPrivateGroupId(), s.getState().getVisibility()); + } else if (role == PEER) { + PeerSession s = + sessionParser.parsePeerSession(contactGroupId, d); + m.put(s.getPrivateGroupId(), s.getState().getVisibility()); + } else { + throw new AssertionError(); + } + } + return m; + } + private static class StoredSession { private final MessageId storageId; diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java index 178cafdd09..f022875743 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationModule.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.data.MetadataEncoder; import org.briarproject.bramble.api.lifecycle.LifecycleManager; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.ValidationManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.messaging.ConversationManager; @@ -38,13 +39,25 @@ public class GroupInvitationModule { LifecycleManager lifecycleManager, ValidationManager validationManager, ContactManager contactManager, PrivateGroupManager privateGroupManager, - ConversationManager conversationManager) { + ConversationManager conversationManager, + ClientVersioningManager clientVersioningManager) { lifecycleManager.registerClient(groupInvitationManager); validationManager.registerIncomingMessageHook(CLIENT_ID, CLIENT_VERSION, groupInvitationManager); contactManager.registerContactHook(groupInvitationManager); privateGroupManager.registerPrivateGroupHook(groupInvitationManager); conversationManager.registerConversationClient(groupInvitationManager); + clientVersioningManager.registerClient(CLIENT_ID, CLIENT_VERSION); + clientVersioningManager.registerClientVersioningHook(CLIENT_ID, + CLIENT_VERSION, groupInvitationManager); + // The group invitation manager handles client visibility changes for + // the private group manager + clientVersioningManager.registerClient(PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.CLIENT_VERSION); + clientVersioningManager.registerClientVersioningHook( + PrivateGroupManager.CLIENT_ID, + PrivateGroupManager.CLIENT_VERSION, + groupInvitationManager.getPrivateGroupClientVersioningHook()); return groupInvitationManager; } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java index f181d1f776..064c1d5936 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngine.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.system.Clock; @@ -41,15 +42,16 @@ import static org.briarproject.briar.privategroup.invitation.InviteeState.START; class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { InviteeProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, IdentityManager identityManager, MessageParser messageParser, MessageEncoder messageEncoder, MessageTracker messageTracker, Clock clock) { - super(db, clientHelper, privateGroupManager, privateGroupFactory, - groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + super(db, clientHelper, clientVersioningManager, privateGroupManager, + privateGroupFactory, groupMessageFactory, identityManager, + messageParser, messageEncoder, messageTracker, clock); } @Override @@ -212,6 +214,12 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> { throws DbException { // Send a LEAVE message Message sent = sendLeaveMessage(txn, s, false); + try { + // Make the private group invisible to the contact + setPrivateGroupVisibility(txn, s, INVISIBLE); + } catch (FormatException e) { + throw new DbException(e); // Invalid group metadata + } // Move to the LEFT state return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(), sent.getId(), s.getLastRemoteMessageId(), sent.getTimestamp(), diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java index 7fa69e6af9..f347ca0618 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/InviteeState.java @@ -2,20 +2,32 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group.Visibility; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; + @Immutable @NotNullByDefault enum InviteeState implements State { - START(0), INVITED(1), ACCEPTED(2), JOINED(3), LEFT(4), DISSOLVED(5), - ERROR(6); + START(0, INVISIBLE), + INVITED(1, INVISIBLE), + ACCEPTED(2, VISIBLE), + JOINED(3, SHARED), + LEFT(4, INVISIBLE), + DISSOLVED(5, INVISIBLE), + ERROR(6, INVISIBLE); private final int value; + private final Visibility visibility; - InviteeState(int value) { + InviteeState(int value, Visibility visibility) { this.value = value; + this.visibility = visibility; } @Override @@ -23,6 +35,11 @@ enum InviteeState implements State { return value; } + @Override + public Visibility getVisibility() { + return visibility; + } + static InviteeState fromValue(int value) throws FormatException { for (InviteeState s : values()) if (s.value == value) return s; throw new FormatException(); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java index c1908735fd..5a7f1c6c3a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngine.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; @@ -36,15 +37,16 @@ import static org.briarproject.briar.privategroup.invitation.PeerState.START; class PeerProtocolEngine extends AbstractProtocolEngine<PeerSession> { PeerProtocolEngine(DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, IdentityManager identityManager, MessageParser messageParser, MessageEncoder messageEncoder, MessageTracker messageTracker, Clock clock) { - super(db, clientHelper, privateGroupManager, privateGroupFactory, - groupMessageFactory, identityManager, messageParser, - messageEncoder, messageTracker, clock); + super(db, clientHelper, clientVersioningManager, privateGroupManager, + privateGroupFactory, groupMessageFactory, identityManager, + messageParser, messageEncoder, messageTracker, clock); } @Override diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java index 94f9d19afe..041528266e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/PeerState.java @@ -2,20 +2,32 @@ package org.briarproject.briar.privategroup.invitation; import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.Group.Visibility; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.bramble.api.sync.Group.Visibility.VISIBLE; + @Immutable @NotNullByDefault enum PeerState implements State { - START(0), AWAIT_MEMBER(1), NEITHER_JOINED(2), LOCAL_JOINED(3), - BOTH_JOINED(4), LOCAL_LEFT(5), ERROR(6); + START(0, INVISIBLE), + AWAIT_MEMBER(1, INVISIBLE), + NEITHER_JOINED(2, INVISIBLE), + LOCAL_JOINED(3, VISIBLE), + BOTH_JOINED(4, SHARED), + LOCAL_LEFT(5, INVISIBLE), + ERROR(6, INVISIBLE); private final int value; + private final Visibility visibility; - PeerState(int value) { + PeerState(int value, Visibility visibility) { this.value = value; + this.visibility = visibility; } @Override @@ -23,6 +35,11 @@ enum PeerState implements State { return value; } + @Override + public Visibility getVisibility() { + return visibility; + } + static PeerState fromValue(int value) throws FormatException { for (PeerState s : values()) if (s.value == value) return s; throw new FormatException(); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java index af3bbe8167..801d16d06e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/ProtocolEngineFactoryImpl.java @@ -4,6 +4,7 @@ import org.briarproject.bramble.api.client.ClientHelper; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.system.Clock; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.privategroup.GroupMessageFactory; @@ -19,6 +20,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { private final DatabaseComponent db; private final ClientHelper clientHelper; + private final ClientVersioningManager clientVersioningManager; private final PrivateGroupManager privateGroupManager; private final PrivateGroupFactory privateGroupFactory; private final GroupMessageFactory groupMessageFactory; @@ -30,6 +32,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { @Inject ProtocolEngineFactoryImpl(DatabaseComponent db, ClientHelper clientHelper, + ClientVersioningManager clientVersioningManager, PrivateGroupManager privateGroupManager, PrivateGroupFactory privateGroupFactory, GroupMessageFactory groupMessageFactory, @@ -38,6 +41,7 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { Clock clock) { this.db = db; this.clientHelper = clientHelper; + this.clientVersioningManager = clientVersioningManager; this.privateGroupManager = privateGroupManager; this.privateGroupFactory = privateGroupFactory; this.groupMessageFactory = groupMessageFactory; @@ -50,21 +54,24 @@ class ProtocolEngineFactoryImpl implements ProtocolEngineFactory { @Override public ProtocolEngine<CreatorSession> createCreatorEngine() { - return new CreatorProtocolEngine(db, clientHelper, privateGroupManager, + return new CreatorProtocolEngine(db, clientHelper, + clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, messageEncoder, messageTracker, clock); } @Override public ProtocolEngine<InviteeSession> createInviteeEngine() { - return new InviteeProtocolEngine(db, clientHelper, privateGroupManager, + return new InviteeProtocolEngine(db, clientHelper, + clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, messageEncoder, messageTracker, clock); } @Override public ProtocolEngine<PeerSession> createPeerEngine() { - return new PeerProtocolEngine(db, clientHelper, privateGroupManager, + return new PeerProtocolEngine(db, clientHelper, + clientVersioningManager, privateGroupManager, privateGroupFactory, groupMessageFactory, identityManager, messageParser, messageEncoder, messageTracker, clock); } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java index 78e36bf3a5..86fe5e3a04 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionEncoderImpl.java @@ -9,6 +9,7 @@ import javax.inject.Inject; import static org.briarproject.bramble.api.data.BdfDictionary.NULL_VALUE; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_INVITE_TIMESTAMP; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_IS_SESSION; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LOCAL_TIMESTAMP; @@ -28,6 +29,7 @@ class SessionEncoderImpl implements SessionEncoder { @Override public BdfDictionary encodeSession(Session s) { BdfDictionary d = new BdfDictionary(); + d.put(SESSION_KEY_IS_SESSION, true); d.put(SESSION_KEY_SESSION_ID, s.getPrivateGroupId()); d.put(SESSION_KEY_PRIVATE_GROUP_ID, s.getPrivateGroupId()); MessageId lastLocalMessageId = s.getLastLocalMessageId(); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java index baf0de80e2..152ed067e3 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParser.java @@ -11,6 +11,8 @@ interface SessionParser { BdfDictionary getSessionQuery(SessionId s); + BdfDictionary getAllSessionsQuery(); + Role getRole(BdfDictionary d) throws FormatException; CreatorSession parseCreatorSession(GroupId contactGroupId, BdfDictionary d) diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java index e8813b6dcd..19a424d707 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/SessionParserImpl.java @@ -13,6 +13,7 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_INVITE_TIMESTAMP; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_IS_SESSION; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.SESSION_KEY_LOCAL_TIMESTAMP; @@ -37,6 +38,11 @@ class SessionParserImpl implements SessionParser { return BdfDictionary.of(new BdfEntry(SESSION_KEY_SESSION_ID, s)); } + @Override + public BdfDictionary getAllSessionsQuery() { + return BdfDictionary.of(new BdfEntry(SESSION_KEY_IS_SESSION, true)); + } + @Override public Role getRole(BdfDictionary d) throws FormatException { return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue()); diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java index 46df85efdc..2313f96c7e 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/State.java @@ -1,6 +1,10 @@ package org.briarproject.briar.privategroup.invitation; +import org.briarproject.bramble.api.sync.Group.Visibility; + interface State { int getValue(); + + Visibility getVisibility(); } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java index 3ae2fb61e4..8c8056512f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java @@ -10,7 +10,9 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.Group.Visibility; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageId; @@ -24,6 +26,7 @@ import org.briarproject.briar.api.privategroup.PrivateGroupManager; import org.jmock.Expectations; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; @@ -47,6 +50,8 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { context.mock(DatabaseComponent.class); protected final ClientHelper clientHelper = context.mock(ClientHelper.class); + protected final ClientVersioningManager clientVersioningManager = + context.mock(ClientVersioningManager.class); protected final PrivateGroupFactory privateGroupFactory = context.mock(PrivateGroupFactory.class); protected final PrivateGroupManager privateGroupManager = @@ -181,10 +186,13 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase { }}); } - protected void expectSetPrivateGroupVisibility(Group.Visibility v) + protected void expectSetPrivateGroupVisibility(Visibility v) throws Exception { expectGetContactId(); context.checking(new Expectations() {{ + oneOf(clientVersioningManager).getClientVisibility(txn, contactId, + CLIENT_ID, CLIENT_VERSION); + will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v); }}); } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java index 22e64a9f98..c1b2bd9b27 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java @@ -19,9 +19,10 @@ import static org.junit.Assert.assertEquals; public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { private final CreatorProtocolEngine engine = - new CreatorProtocolEngine(db, clientHelper, privateGroupManager, - privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + new CreatorProtocolEngine(db, clientHelper, clientVersioningManager, + privateGroupManager, privateGroupFactory, + groupMessageFactory, identityManager, messageParser, + messageEncoder, messageTracker, clock); private CreatorSession getDefaultSession(CreatorState state) { return new CreatorSession(contactGroupId, privateGroupId, diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java index 1a7ae0857d..e7db720c76 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -15,6 +15,7 @@ import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.sync.ClientVersioningManager; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; @@ -69,6 +70,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { private final DatabaseComponent db = context.mock(DatabaseComponent.class); private final ClientHelper clientHelper = context.mock(ClientHelper.class); + private final ClientVersioningManager clientVersioningManager = + context.mock(ClientVersioningManager.class); private final ContactGroupFactory contactGroupFactory = context.mock(ContactGroupFactory.class); private final PrivateGroupFactory privateGroupFactory = @@ -140,11 +143,11 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { }}); MetadataParser metadataParser = context.mock(MetadataParser.class); MessageTracker messageTracker = context.mock(MessageTracker.class); - groupInvitationManager = - new GroupInvitationManagerImpl(db, clientHelper, metadataParser, - messageTracker, contactGroupFactory, - privateGroupFactory, privateGroupManager, messageParser, - sessionParser, sessionEncoder, engineFactory); + groupInvitationManager = new GroupInvitationManagerImpl(db, + clientHelper, clientVersioningManager, metadataParser, + messageTracker, contactGroupFactory, privateGroupFactory, + privateGroupManager, messageParser, sessionParser, + sessionEncoder, engineFactory); } @Test @@ -184,6 +187,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { CLIENT_VERSION, c); will(returnValue(contactGroup)); oneOf(db).addGroup(txn, contactGroup); + oneOf(clientVersioningManager).getClientVisibility(txn, contactId, + CLIENT_ID, CLIENT_VERSION); + will(returnValue(SHARED)); oneOf(db).setGroupVisibility(txn, c.getId(), contactGroup.getId(), SHARED); oneOf(clientHelper) diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java index 0030945428..f398d3a7fd 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/InviteeProtocolEngineTest.java @@ -38,9 +38,10 @@ import static org.junit.Assert.assertTrue; public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { private final InviteeProtocolEngine engine = - new InviteeProtocolEngine(db, clientHelper, privateGroupManager, - privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + new InviteeProtocolEngine(db, clientHelper, clientVersioningManager, + privateGroupManager, privateGroupFactory, + groupMessageFactory, identityManager, messageParser, + messageEncoder, messageTracker, clock); private final LocalAuthor localAuthor = getLocalAuthor(); private InviteeSession getDefaultSession(InviteeState state) { @@ -238,6 +239,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { @Test public void testOnLeaveActionFromAccepted() throws Exception { expectSendLeaveMessage(false); + expectSetPrivateGroupVisibility(INVISIBLE); InviteeSession session = getDefaultSession(ACCEPTED); InviteeSession newSession = engine.onLeaveAction(txn, session); @@ -249,6 +251,7 @@ public class InviteeProtocolEngineTest extends AbstractProtocolEngineTest { @Test public void testOnLeaveActionFromJoined() throws Exception { expectSendLeaveMessage(false); + expectSetPrivateGroupVisibility(INVISIBLE); InviteeSession session = getDefaultSession(JOINED); InviteeSession newSession = engine.onLeaveAction(txn, session); diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java index d5d53168fa..05c0920c54 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/PeerProtocolEngineTest.java @@ -24,9 +24,10 @@ import static org.junit.Assert.assertTrue; public class PeerProtocolEngineTest extends AbstractProtocolEngineTest { private final PeerProtocolEngine engine = - new PeerProtocolEngine(db, clientHelper, privateGroupManager, - privateGroupFactory, groupMessageFactory, identityManager, - messageParser, messageEncoder, messageTracker, clock); + new PeerProtocolEngine(db, clientHelper, clientVersioningManager, + privateGroupManager, privateGroupFactory, + groupMessageFactory, identityManager, messageParser, + messageEncoder, messageTracker, clock); private PeerSession getDefaultSession(PeerState state) { return new PeerSession(contactGroupId, privateGroupId, -- GitLab