diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java index 6b4ba6b4c..896acb221 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ContactGroupFactory.java @@ -12,19 +12,19 @@ public interface ContactGroupFactory { /** * Creates a group that is not shared with any contacts. */ - Group createLocalGroup(ClientId clientId, int clientVersion); + Group createLocalGroup(ClientId clientId, int majorVersion); /** * Creates a group for the given client to share with the given contact. */ - Group createContactGroup(ClientId clientId, int clientVersion, + Group createContactGroup(ClientId clientId, int majorVersion, Contact contact); /** * Creates a group for the given client to share between the given authors * identified by their AuthorIds. */ - Group createContactGroup(ClientId clientId, int clientVersion, + Group createContactGroup(ClientId clientId, int majorVersion, AuthorId authorId1, AuthorId authorId2); } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java index ea05938d4..371567441 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java @@ -241,7 +241,8 @@ public interface DatabaseComponent { *
* Read-only. */ - Collection
+ * The number of available processors can change during the lifetime of the
+ * JVM, so this is just a reasonable guess.
+ */
+ private static final int MAX_EXECUTOR_THREADS =
+ Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
+
+ private final ExecutorService cryptoExecutor;
+
+ public CryptoExecutorModule() {
+ // Use an unbounded queue
+ BlockingQueue
- * The number of available processors can change during the lifetime of the
- * JVM, so this is just a reasonable guess.
- */
- private static final int MAX_EXECUTOR_THREADS =
- Math.max(1, Runtime.getRuntime().availableProcessors() - 1);
-
- private final ExecutorService cryptoExecutor;
-
- public CryptoModule() {
- // Use an unbounded queue
- BlockingQueue
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
private final Clock clock;
AbstractProtocolEngine(DatabaseComponent db, ClientHelper clientHelper,
+ ClientVersioningManager clientVersioningManager,
PrivateGroupManager privateGroupManager,
PrivateGroupFactory privateGroupFactory,
GroupMessageFactory groupMessageFactory,
@@ -60,6 +65,7 @@ abstract class AbstractProtocolEngine
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
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, MAJOR_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 ec5315a6d..d043fbad2 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
@@ -10,6 +10,7 @@ import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Message;
import org.briarproject.bramble.api.system.Clock;
+import org.briarproject.bramble.api.versioning.ClientVersioningManager;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.ProtocolStateException;
import org.briarproject.briar.api.client.SessionId;
@@ -36,15 +37,16 @@ import static org.briarproject.briar.privategroup.invitation.CreatorState.START;
class CreatorProtocolEngine extends AbstractProtocolEngine
protected final ClientHelper clientHelper;
protected final MessageParser messageParser;
+ private final ClientVersioningManager clientVersioningManager;
private final MessageEncoder messageEncoder;
private final MessageTracker messageTracker;
private final Clock clock;
+ private final ClientId shareableClientId;
+ private final int shareableClientVersion;
ProtocolEngineImpl(DatabaseComponent db, ClientHelper clientHelper,
+ ClientVersioningManager clientVersioningManager,
MessageEncoder messageEncoder, MessageParser messageParser,
- MessageTracker messageTracker, Clock clock) {
+ MessageTracker messageTracker, Clock clock,
+ ClientId shareableClientId, int shareableClientVersion) {
this.db = db;
this.clientHelper = clientHelper;
+ this.clientVersioningManager = clientVersioningManager;
this.messageEncoder = messageEncoder;
this.messageParser = messageParser;
this.messageTracker = messageTracker;
this.clock = clock;
+ this.shareableClientId = shareableClientId;
+ this.shareableClientVersion = shareableClientVersion;
}
@Override
@@ -598,9 +607,13 @@ abstract class ProtocolEngineImpl
}
private void setShareableVisibility(Transaction txn, Session session,
- Visibility v) throws DbException, FormatException {
+ 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.getShareableId(), v);
+ Visibility client = clientVersioningManager.getClientVisibility(txn,
+ contactId, shareableClientId, shareableClientVersion);
+ Visibility min = Visibility.min(preferred, client);
+ db.setGroupVisibility(txn, contactId, session.getShareableId(), min);
}
private ContactId getContactId(Transaction txn, GroupId contactGroupId)
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java
index 7cf2bf139..641731a4a 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionEncoderImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/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.sharing.SharingConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_IS_SESSION;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -27,6 +28,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.getShareableId());
d.put(SESSION_KEY_SHAREABLE_ID, s.getShareableId());
MessageId lastLocalMessageId = s.getLastLocalMessageId();
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
index a82aed3ec..eec97355f 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParser.java
@@ -11,6 +11,8 @@ interface SessionParser {
BdfDictionary getSessionQuery(SessionId s);
+ BdfDictionary getAllSessionsQuery();
+
Session parseSession(GroupId contactGroupId, BdfDictionary d)
throws FormatException;
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
index 62d9c44b1..ee0c06f61 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SessionParserImpl.java
@@ -13,6 +13,7 @@ import javax.annotation.concurrent.Immutable;
import javax.inject.Inject;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_INVITE_TIMESTAMP;
+import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_IS_SESSION;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_LOCAL_MESSAGE_ID;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LAST_REMOTE_MESSAGE_ID;
import static org.briarproject.briar.sharing.SharingConstants.SESSION_KEY_LOCAL_TIMESTAMP;
@@ -33,6 +34,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 Session parseSession(GroupId contactGroupId,
BdfDictionary d) throws FormatException {
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
index d98099e27..f2522d1a9 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingConstants.java
@@ -18,6 +18,7 @@ interface SharingConstants {
String MSG_KEY_INVITATION_ACCEPTED = "invitationAccepted";
// Session keys
+ String SESSION_KEY_IS_SESSION = "isSession";
String SESSION_KEY_STATE = "state";
String SESSION_KEY_SESSION_ID = "sessionId";
String SESSION_KEY_SHAREABLE_ID = "shareableId";
diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
index f26996438..fc57a6daa 100644
--- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java
@@ -17,10 +17,13 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.sync.Client;
import org.briarproject.bramble.api.sync.ClientId;
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;
import org.briarproject.bramble.api.sync.MessageStatus;
+import org.briarproject.bramble.api.versioning.ClientVersioningManager;
+import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook;
import org.briarproject.briar.api.client.MessageTracker;
import org.briarproject.briar.api.client.SessionId;
import org.briarproject.briar.api.sharing.InvitationMessage;
@@ -52,8 +55,10 @@ import static org.briarproject.briar.sharing.State.SHARING;
@NotNullByDefault
abstract class SharingManagerImpl
extends ConversationClientImpl
- implements SharingManager, Client, ContactHook {
+ implements SharingManager, Client, ContactHook,
+ ClientVersioningHook {
+ private final ClientVersioningManager clientVersioningManager;
private final MessageParser messageParser;
private final SessionEncoder sessionEncoder;
private final SessionParser sessionParser;
@@ -62,12 +67,14 @@ abstract class SharingManagerImpl
private final InvitationFactory invitationFactory;
SharingManagerImpl(DatabaseComponent db, ClientHelper clientHelper,
+ ClientVersioningManager clientVersioningManager,
MetadataParser metadataParser, MessageParser messageParser,
SessionEncoder sessionEncoder, SessionParser sessionParser,
MessageTracker messageTracker,
ContactGroupFactory contactGroupFactory, ProtocolEngine engine,
InvitationFactory invitationFactory) {
super(db, clientHelper, metadataParser, messageTracker);
+ this.clientVersioningManager = clientVersioningManager;
this.messageParser = messageParser;
this.sessionEncoder = sessionEncoder;
this.sessionParser = sessionParser;
@@ -78,48 +85,51 @@ abstract class SharingManagerImpl
protected abstract ClientId getClientId();
- protected abstract int getClientVersion();
+ protected abstract int getMajorVersion();
+
+ protected abstract ClientId getShareableClientId();
+
+ protected abstract int getShareableMajorVersion();
@Override
public void createLocalState(Transaction txn) throws DbException {
// Create a local group to indicate that we've set this client up
Group localGroup = contactGroupFactory.createLocalGroup(getClientId(),
- getClientVersion());
+ getMajorVersion());
if (db.containsGroup(txn, localGroup.getId())) return;
db.addGroup(txn, localGroup);
- // Ensure we've set things up for any pre-existing contacts
+ // Set things up for any pre-existing contacts
for (Contact c : db.getContacts(txn)) addingContact(txn, c);
}
@Override
public void addingContact(Transaction txn, Contact c) throws DbException {
+ // Create a group to share with the contact
+ Group g = getContactGroup(c);
+ db.addGroup(txn, g);
+ Visibility client = clientVersioningManager.getClientVisibility(txn,
+ c.getId(), getClientId(), getMajorVersion());
+ 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());
try {
- // Create a group to share with the contact
- Group g = getContactGroup(c);
- // Return if we've already set things up for this contact
- if (db.containsGroup(txn, g.getId())) return;
- // Store the group and share it with the contact
- db.addGroup(txn, g);
- db.setGroupVisibility(txn, c.getId(), g.getId(), SHARED);
- // Attach the contact ID to the group
- BdfDictionary meta = new BdfDictionary();
- meta.put(GROUP_KEY_CONTACT_ID, c.getId().getInt());
clientHelper.mergeGroupMetadata(txn, g.getId(), meta);
} catch (FormatException e) {
- throw new DbException(e);
+ throw new AssertionError(e);
}
}
@Override
public void removingContact(Transaction txn, Contact c) throws DbException {
- // remove the contact group (all messages will be removed with it)
+ // Remove the contact group (all messages will be removed with it)
db.removeGroup(txn, getContactGroup(c));
}
@Override
public Group getContactGroup(Contact c) {
return contactGroupFactory.createContactGroup(getClientId(),
- getClientVersion(), c);
+ getMajorVersion(), c);
}
@Override
@@ -152,17 +162,21 @@ abstract class SharingManagerImpl
*/
void preShareShareable(Transaction txn, Contact c, S shareable)
throws DbException, FormatException {
- // return if a session already exists with that Contact
+ // Return if a session already exists with the contact
GroupId contactGroupId = getContactGroup(c).getId();
StoredSession existingSession = getSession(txn, contactGroupId,
getSessionId(shareable.getId()));
if (existingSession != null) return;
- // add and shares the shareable with the Contact
+ // Add the shareable
db.addGroup(txn, shareable.getGroup());
- db.setGroupVisibility(txn, c.getId(), shareable.getId(), SHARED);
- // initialize session in sharing state
+ // Apply the client's visibility
+ Visibility client = clientVersioningManager.getClientVisibility(txn,
+ c.getId(), getShareableClientId(), getShareableMajorVersion());
+ db.setGroupVisibility(txn, c.getId(), shareable.getId(), client);
+
+ // Initialize session in sharing state
Session session = new Session(SHARING, contactGroupId,
shareable.getId(), null, null, 0, 0);
MessageId storageId = createStorageId(txn, contactGroupId);
@@ -446,6 +460,10 @@ abstract class SharingManagerImpl
private boolean canBeShared(Transaction txn, GroupId g, Contact c)
throws DbException {
+ // The group can't be shared unless the contact supports the client
+ Visibility client = clientVersioningManager.getClientVisibility(txn,
+ c.getId(), getShareableClientId(), getShareableMajorVersion());
+ if (client != SHARED) return false;
GroupId contactGroupId = getContactGroup(c).getId();
SessionId sessionId = getSessionId(g);
try {
@@ -482,6 +500,51 @@ abstract class SharingManagerImpl
}
}
+ @Override
+ public void onClientVisibilityChanging(Transaction txn, Contact c,
+ Visibility v) throws DbException {
+ // Apply the client's visibility to the contact group
+ Group g = getContactGroup(c);
+ db.setGroupVisibility(txn, c.getId(), g.getId(), v);
+ }
+
+ ClientVersioningHook getShareableClientVersioningHook() {
+ return this::onShareableClientVisibilityChanging;
+ }
+
+ // Versioning hook for the shareable client
+ private void onShareableClientVisibilityChanging(Transaction txn, Contact c,
+ Visibility client) throws DbException {
+ try {
+ Collection