From a42d9eec1cf5a821f0aacb9a5031e58eb32e0f46 Mon Sep 17 00:00:00 2001 From: Daniel Lublin Date: Fri, 13 May 2022 11:45:42 +0200 Subject: [PATCH] Include mailbox API version in local and remote mailbox properties This changes the format of the mailbox properties update message, so the major version of the client is bumped. --- .../bramble/api/client/ClientHelper.java | 12 +- .../api/mailbox/MailboxPropertiesUpdate.java | 35 +--- .../MailboxPropertiesUpdateMailbox.java | 51 +++++ .../api/mailbox/MailboxPropertyManager.java | 2 +- .../api/mailbox/MailboxSettingsManager.java | 5 +- .../RemoteMailboxPropertiesUpdateEvent.java | 5 +- .../briarproject/bramble/test/TestUtils.java | 20 +- .../bramble/client/ClientHelperImpl.java | 46 ++++- .../bramble/mailbox/MailboxApi.java | 11 + .../mailbox/MailboxPairingTaskImpl.java | 2 +- .../mailbox/MailboxPropertyManagerImpl.java | 80 +++++--- .../mailbox/MailboxPropertyValidator.java | 14 +- .../mailbox/MailboxSettingsManagerImpl.java | 2 +- .../bramble/client/ClientHelperImplTest.java | 122 ++++++++++-- .../mailbox/MailboxPairingTaskImplTest.java | 10 +- .../MailboxPropertyManagerImplTest.java | 188 ++++++++++++------ .../mailbox/MailboxPropertyValidatorTest.java | 39 +++- 17 files changed, 473 insertions(+), 171 deletions(-) create mode 100644 bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdateMailbox.java diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java index 262d82c9b..84893c56c 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/client/ClientHelper.java @@ -21,8 +21,6 @@ import java.security.GeneralSecurityException; import java.util.Collection; import java.util.Map; -import javax.annotation.Nullable; - @NotNullByDefault public interface ClientHelper { @@ -127,15 +125,13 @@ public interface ClientHelper { BdfDictionary properties) throws FormatException; /** - * Parse and validate the property dictionary of a Mailbox property update - * message. + * Parse and validate the elements of a Mailbox property update message. * - * @return the properties for using the Mailbox, or null if there is no - * Mailbox available - * @throws FormatException if the properties are not valid + * @return the parsed update message + * @throws FormatException if the message elements are invalid */ - @Nullable MailboxPropertiesUpdate parseAndValidateMailboxPropertiesUpdate( + BdfList clientSupports, BdfList serverSupports, BdfDictionary properties) throws FormatException; /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdate.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdate.java index fb37448dd..8319d1ec5 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdate.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdate.java @@ -2,40 +2,27 @@ package org.briarproject.bramble.api.mailbox; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import java.util.List; + import javax.annotation.concurrent.Immutable; @Immutable @NotNullByDefault public class MailboxPropertiesUpdate { - private final String onion; - private final MailboxAuthToken authToken; - private final MailboxFolderId inboxId; - private final MailboxFolderId outboxId; + boolean hasMailbox; + private final List clientSupports; - public MailboxPropertiesUpdate(String onion, - MailboxAuthToken authToken, MailboxFolderId inboxId, - MailboxFolderId outboxId) { - this.onion = onion; - this.authToken = authToken; - this.inboxId = inboxId; - this.outboxId = outboxId; + public MailboxPropertiesUpdate(List clientSupports) { + this.hasMailbox = false; + this.clientSupports = clientSupports; } - public String getOnion() { - return onion; + public List getClientSupports() { + return clientSupports; } - public MailboxAuthToken getAuthToken() { - return authToken; + public boolean hasMailbox() { + return hasMailbox; } - - public MailboxFolderId getInboxId() { - return inboxId; - } - - public MailboxFolderId getOutboxId() { - return outboxId; - } - } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdateMailbox.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdateMailbox.java new file mode 100644 index 000000000..2992c49ab --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertiesUpdateMailbox.java @@ -0,0 +1,51 @@ +package org.briarproject.bramble.api.mailbox; + +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import java.util.List; + +import javax.annotation.concurrent.Immutable; + +@Immutable +@NotNullByDefault +public class MailboxPropertiesUpdateMailbox extends MailboxPropertiesUpdate { + private final List serverSupports; + private final String onion; + private final MailboxAuthToken authToken; + private final MailboxFolderId inboxId; + private final MailboxFolderId outboxId; + + public MailboxPropertiesUpdateMailbox(List clientSupports, + List serverSupports, String onion, + MailboxAuthToken authToken, MailboxFolderId inboxId, + MailboxFolderId outboxId + ) { + super(clientSupports); + this.hasMailbox = true; + this.serverSupports = serverSupports; + this.onion = onion; + this.authToken = authToken; + this.inboxId = inboxId; + this.outboxId = outboxId; + } + + public String getOnion() { + return onion; + } + + public MailboxAuthToken getAuthToken() { + return authToken; + } + + public MailboxFolderId getInboxId() { + return inboxId; + } + + public MailboxFolderId getOutboxId() { + return outboxId; + } + + public List getServerSupports() { + return serverSupports; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertyManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertyManager.java index b0ecf8fdd..6180ba152 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertyManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxPropertyManager.java @@ -20,7 +20,7 @@ public interface MailboxPropertyManager { /** * The current major version of the mailbox property client. */ - int MAJOR_VERSION = 0; + int MAJOR_VERSION = 1; /** * The current minor version of the mailbox property client. diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java index e2a4c7110..3bd50d6c6 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/MailboxSettingsManager.java @@ -7,6 +7,8 @@ import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; +import java.util.List; + import javax.annotation.Nullable; @NotNullByDefault @@ -49,7 +51,8 @@ public interface MailboxSettingsManager { * @param txn A read-write transaction * @param ownOnion Our new mailbox's onion (56 base32 chars) */ - void mailboxPaired(Transaction txn, String ownOnion) + void mailboxPaired(Transaction txn, String ownOnion, + List serverSupports) throws DbException; /** diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/RemoteMailboxPropertiesUpdateEvent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/RemoteMailboxPropertiesUpdateEvent.java index 3d63acd37..649c5c41e 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/RemoteMailboxPropertiesUpdateEvent.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/mailbox/RemoteMailboxPropertiesUpdateEvent.java @@ -4,7 +4,6 @@ import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; -import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; /** @@ -16,11 +15,10 @@ import javax.annotation.concurrent.Immutable; public class RemoteMailboxPropertiesUpdateEvent extends Event { private final ContactId contactId; - @Nullable private final MailboxPropertiesUpdate mailboxPropertiesUpdate; public RemoteMailboxPropertiesUpdateEvent(ContactId contactId, - @Nullable MailboxPropertiesUpdate mailboxPropertiesUpdate) { + MailboxPropertiesUpdate mailboxPropertiesUpdate) { this.contactId = contactId; this.mailboxPropertiesUpdate = mailboxPropertiesUpdate; } @@ -29,7 +27,6 @@ public class RemoteMailboxPropertiesUpdateEvent extends Event { return contactId; } - @Nullable public MailboxPropertiesUpdate getMailboxPropertiesUpdate() { return mailboxPropertiesUpdate; } diff --git a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java index 0f4a4748d..fa01c7beb 100644 --- a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java +++ b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java @@ -22,6 +22,7 @@ import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.sync.ClientId; @@ -286,10 +287,21 @@ public class TestUtils { if (a == null || b == null) { return a == b; } - return a.getOnion().equals(b.getOnion()) && - a.getAuthToken().equals(b.getAuthToken()) && - a.getInboxId().equals(b.getInboxId()) && - a.getOutboxId().equals(b.getOutboxId()); + if (!a.hasMailbox() && !b.hasMailbox()) { + return a.getClientSupports().equals(b.getClientSupports()); + } else if (a.hasMailbox() && b.hasMailbox()) { + MailboxPropertiesUpdateMailbox am = + (MailboxPropertiesUpdateMailbox) a; + MailboxPropertiesUpdateMailbox bm = + (MailboxPropertiesUpdateMailbox) b; + return am.getClientSupports().equals(bm.getClientSupports()) && + am.getServerSupports().equals(bm.getServerSupports()) && + am.getOnion().equals(bm.getOnion()) && + am.getAuthToken().equals(bm.getAuthToken()) && + am.getInboxId().equals(bm.getInboxId()) && + am.getOutboxId().equals(bm.getOutboxId()); + } + return false; } public static boolean mailboxPropertiesEqual( diff --git a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java index bab9a18e6..39d9079d1 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/client/ClientHelperImpl.java @@ -26,6 +26,8 @@ import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.properties.TransportProperties; @@ -39,12 +41,13 @@ import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.security.GeneralSecurityException; +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 javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; @@ -412,11 +415,28 @@ class ClientHelperImpl implements ClientHelper { } @Override - @Nullable public MailboxPropertiesUpdate parseAndValidateMailboxPropertiesUpdate( + BdfList clientSupports, BdfList serverSupports, BdfDictionary properties) throws FormatException { + List clientSupportsList = + getMailboxVersionList(clientSupports); + List serverSupportsList = + getMailboxVersionList(serverSupports); + + // We must always learn what Mailbox API version(s) the client supports + if (clientSupports.isEmpty()) { + throw new FormatException(); + } if (properties.isEmpty()) { - return null; + // No mailbox -- cannot claim to support any API versions! + if (!serverSupports.isEmpty()) { + throw new FormatException(); + } + return new MailboxPropertiesUpdate(clientSupportsList); + } + // Mailbox must be accompanied by the Mailbox API version(s) it supports + if (serverSupports.isEmpty()) { + throw new FormatException(); } // Accepting more props than we need, for forward compatibility if (properties.size() < PROP_COUNT) { @@ -435,9 +455,23 @@ class ClientHelperImpl implements ClientHelper { checkLength(inboxId, UniqueId.LENGTH); byte[] outboxId = properties.getRaw(PROP_KEY_OUTBOXID); checkLength(outboxId, UniqueId.LENGTH); - return new MailboxPropertiesUpdate(onion, - new MailboxAuthToken(authToken), new MailboxFolderId(inboxId), - new MailboxFolderId(outboxId)); + return new MailboxPropertiesUpdateMailbox(clientSupportsList, + serverSupportsList, onion, new MailboxAuthToken(authToken), + new MailboxFolderId(inboxId), new MailboxFolderId(outboxId)); + } + + private List getMailboxVersionList(BdfList bdfList) + throws FormatException { + List list = new ArrayList<>(); + for (int i = 0; i < bdfList.size(); i++) { + BdfList element = bdfList.getList(i); + if (element.size() != 2) { + throw new FormatException(); + } + list.add(new MailboxVersion(element.getLong(0).intValue(), + element.getLong(1).intValue())); + } + return list; } @Override diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java index 9596ce2f3..22d00a18f 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxApi.java @@ -7,6 +7,8 @@ import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFileId; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.api.mailbox.MailboxPropertyManager; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import java.io.File; @@ -17,9 +19,18 @@ import java.util.List; import javax.annotation.Nonnull; import javax.annotation.concurrent.Immutable; +import static java.util.Collections.singletonList; + @NotNullByDefault interface MailboxApi { + /** + * Mailbox API versions that we support as a client. This is reported to our + * contacts by {@link MailboxPropertyManager}. + */ + List CLIENT_SUPPORTS = singletonList( + new MailboxVersion(1, 0)); + /** * Sets up the mailbox with the setup token. * diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java index 7dabeaa2c..8236e07e2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImpl.java @@ -127,7 +127,7 @@ class MailboxPairingTaskImpl implements MailboxPairingTask { for (Contact c : db.getContacts(txn)) { MailboxPropertiesUpdate remoteProps = mailboxPropertyManager .getRemoteProperties(txn, c.getId()); - if (remoteProps == null) { + if (remoteProps == null || !remoteProps.hasMailbox()) { db.resetUnackedMessagesToSend(txn, c.getId()); } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImpl.java index c1db5697d..f2ca77084 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImpl.java @@ -19,9 +19,11 @@ import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; import org.briarproject.bramble.api.mailbox.MailboxPropertyManager; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager.MailboxHook; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.mailbox.RemoteMailboxPropertiesUpdateEvent; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.sync.Group; @@ -35,6 +37,7 @@ import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.versioning.ClientVersioningManager; import org.briarproject.bramble.api.versioning.ClientVersioningManager.ClientVersioningHook; +import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -42,6 +45,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE; +import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS; @NotNullByDefault class MailboxPropertyManagerImpl implements MailboxPropertyManager, @@ -100,11 +104,15 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, db.setGroupVisibility(txn, c.getId(), g.getId(), client); // Attach the contact ID to the group clientHelper.setContactId(txn, g.getId(), c.getId()); - // If we are paired, create and send props to the newly added contact MailboxProperties ownProps = mailboxSettingsManager.getOwnMailboxProperties(txn); if (ownProps != null) { - createAndSendProperties(txn, c, ownProps.getOnion()); + // We are paired, create and send props to the newly added contact + createAndSendProperties(txn, c, ownProps.getServerSupports(), + ownProps.getOnion()); + } else { + // Not paired, but we still want to get our clientSupports sent + sendEmptyProperties(txn, c); } } @@ -114,10 +122,11 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, } @Override - public void mailboxPaired(Transaction txn, String ownOnion) + public void mailboxPaired(Transaction txn, String ownOnion, + List serverSupports) throws DbException { for (Contact c : db.getContacts(txn)) { - createAndSendProperties(txn, c, ownOnion); + createAndSendProperties(txn, c, serverSupports, ownOnion); } } @@ -186,12 +195,15 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, /** * Creates and sends an update message to the given contact. The message - * holds our own mailbox's onion, and generated unique properties. All of - * which the contact needs to communicate with our Mailbox. + * holds our own mailbox's onion, generated unique properties, and lists of + * supported Mailbox API version(s). All of which the contact needs to + * communicate with our Mailbox. */ - private void createAndSendProperties(Transaction txn, - Contact c, String ownOnion) throws DbException { - MailboxPropertiesUpdate p = new MailboxPropertiesUpdate(ownOnion, + private void createAndSendProperties(Transaction txn, Contact c, + List serverSupports, String ownOnion) + throws DbException { + MailboxPropertiesUpdate p = new MailboxPropertiesUpdateMailbox( + CLIENT_SUPPORTS, serverSupports, ownOnion, new MailboxAuthToken(crypto.generateUniqueId().getBytes()), new MailboxFolderId(crypto.generateUniqueId().getBytes()), new MailboxFolderId(crypto.generateUniqueId().getBytes())); @@ -200,14 +212,17 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, } /** - * Sends an empty update message to the given contact. The empty update - * indicates for the receiving contact that we no longer have a Mailbox that - * they can use. + * Sends an update message with empty properties to the given contact. The + * empty update indicates for the receiving contact that we don't have any + * Mailbox that they can use. It still includes the list of Mailbox API + * version(s) that we support as a client. */ private void sendEmptyProperties(Transaction txn, Contact c) throws DbException { Group g = getContactGroup(c); - storeMessageReplaceLatest(txn, g.getId(), null); + MailboxPropertiesUpdate p = + new MailboxPropertiesUpdate(CLIENT_SUPPORTS); + storeMessageReplaceLatest(txn, g.getId(), p); } @Nullable @@ -229,7 +244,7 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, } private void storeMessageReplaceLatest(Transaction txn, GroupId g, - @Nullable MailboxPropertiesUpdate p) throws DbException { + MailboxPropertiesUpdate p) throws DbException { try { LatestUpdate latest = findLatest(txn, g, true); long version = latest == null ? 1 : latest.version + 1; @@ -266,23 +281,38 @@ class MailboxPropertyManagerImpl implements MailboxPropertyManager, return null; } - private BdfList encodeProperties(long version, - @Nullable MailboxPropertiesUpdate p) { + private BdfList encodeProperties(long version, MailboxPropertiesUpdate p) { BdfDictionary dict = new BdfDictionary(); - if (p != null) { - dict.put(PROP_KEY_ONION, p.getOnion()); - dict.put(PROP_KEY_AUTHTOKEN, p.getAuthToken().getBytes()); - dict.put(PROP_KEY_INBOXID, p.getInboxId().getBytes()); - dict.put(PROP_KEY_OUTBOXID, p.getOutboxId().getBytes()); + BdfList serverSupports = new BdfList(); + if (p.hasMailbox()) { + MailboxPropertiesUpdateMailbox pm = + (MailboxPropertiesUpdateMailbox) p; + serverSupports = encodeSupportsList(pm.getServerSupports()); + dict.put(PROP_KEY_ONION, pm.getOnion()); + dict.put(PROP_KEY_AUTHTOKEN, pm.getAuthToken().getBytes()); + dict.put(PROP_KEY_INBOXID, pm.getInboxId().getBytes()); + dict.put(PROP_KEY_OUTBOXID, pm.getOutboxId().getBytes()); } - return BdfList.of(version, dict); + return BdfList.of(version, encodeSupportsList(p.getClientSupports()), + serverSupports, dict); + } + + private BdfList encodeSupportsList(List supportsList) { + BdfList supports = new BdfList(); + for (MailboxVersion version : supportsList) { + supports.add(BdfList.of(version.getMajor(), version.getMinor())); + } + return supports; } - @Nullable private MailboxPropertiesUpdate parseProperties(BdfList body) throws FormatException { - BdfDictionary dict = body.getDictionary(1); - return clientHelper.parseAndValidateMailboxPropertiesUpdate(dict); + BdfList clientSupports = body.getList(1); + BdfList serverSupports = body.getList(2); + BdfDictionary dict = body.getDictionary(3); + return clientHelper.parseAndValidateMailboxPropertiesUpdate( + clientSupports, serverSupports, dict + ); } private Group getContactGroup(Contact c) { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyValidator.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyValidator.java index 32b581fc0..8d279c8bd 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyValidator.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxPropertyValidator.java @@ -31,14 +31,20 @@ class MailboxPropertyValidator extends BdfMessageValidator { @Override protected BdfMessageContext validateMessage(Message m, Group g, BdfList body) throws InvalidMessageException, FormatException { - // Version, properties - checkSize(body, 2); + // Version, Properties, clientSupports, serverSupports + checkSize(body, 4); // Version long version = body.getLong(0); if (version < 0) throw new FormatException(); + // clientSupports + BdfList clientSupports = body.getList(1); + // serverSupports + BdfList serverSupports = body.getList(2); // Properties - BdfDictionary dictionary = body.getDictionary(1); - clientHelper.parseAndValidateMailboxPropertiesUpdate(dictionary); + BdfDictionary dictionary = body.getDictionary(3); + clientHelper.parseAndValidateMailboxPropertiesUpdate(clientSupports, + serverSupports, dictionary + ); // Return the metadata BdfDictionary meta = new BdfDictionary(); meta.put(MSG_KEY_VERSION, version); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java index ae705784e..eee2a49c2 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/mailbox/MailboxSettingsManagerImpl.java @@ -91,7 +91,7 @@ class MailboxSettingsManagerImpl implements MailboxSettingsManager { s.putIntArray(SETTINGS_KEY_SERVER_SUPPORTS, ints); settingsManager.mergeSettings(txn, s, SETTINGS_NAMESPACE); for (MailboxHook hook : hooks) { - hook.mailboxPaired(txn, p.getOnion()); + hook.mailboxPaired(txn, p.getOnion(), p.getServerSupports()); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java index 6214d67c5..b5dd6d06c 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/client/ClientHelperImplTest.java @@ -24,6 +24,8 @@ import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.sync.GroupId; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.sync.MessageFactory; @@ -41,6 +43,7 @@ import java.util.HashMap; import java.util.Map; import java.util.Random; +import static java.util.Collections.singletonList; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; @@ -58,7 +61,7 @@ import static org.briarproject.bramble.test.TestUtils.mailboxPropertiesUpdateEqu import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; @@ -95,10 +98,20 @@ public class ClientHelperImplTest extends BrambleMockTestCase { messageFactory, bdfReaderFactory, bdfWriterFactory, metadataParser, metadataEncoder, cryptoComponent, authorFactory); - private final MailboxPropertiesUpdate validMailboxPropsUpdate; + private final MailboxPropertiesUpdateMailbox validMailboxPropsUpdate; + private final BdfList emptyClientSupports; + private final BdfList someClientSupports; + private final BdfList emptyServerSupports; + private final BdfList someServerSupports; public ClientHelperImplTest() { - validMailboxPropsUpdate = new MailboxPropertiesUpdate( + emptyClientSupports = new BdfList(); + someClientSupports = BdfList.of(BdfList.of(1, 0)); + emptyServerSupports = new BdfList(); + someServerSupports = BdfList.of(BdfList.of(1, 0)); + validMailboxPropsUpdate = new MailboxPropertiesUpdateMailbox( + singletonList(new MailboxVersion(1, 0)), + singletonList(new MailboxVersion(1, 0)), "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd", new MailboxAuthToken(getRandomId()), new MailboxFolderId(getRandomId()), @@ -546,23 +559,84 @@ public class ClientHelperImplTest extends BrambleMockTestCase { }}); } + @Test(expected = FormatException.class) + public void testRejectsMailboxPropsWithEmptyClientSupports() + throws Exception { + BdfDictionary emptyPropsDict = new BdfDictionary(); + clientHelper.parseAndValidateMailboxPropertiesUpdate( + emptyClientSupports, emptyServerSupports, emptyPropsDict + ); + } + @Test public void testParseEmptyMailboxPropsUpdate() throws Exception { BdfDictionary emptyPropsDict = new BdfDictionary(); MailboxPropertiesUpdate parsedProps = clientHelper - .parseAndValidateMailboxPropertiesUpdate(emptyPropsDict); - assertNull(parsedProps); + .parseAndValidateMailboxPropertiesUpdate(someClientSupports, + emptyServerSupports, emptyPropsDict + ); + assertFalse(parsedProps.hasMailbox()); + } + + @Test(expected = FormatException.class) + public void testRejectsEmptyMailboxPropsWithSomeServerSupports() + throws Exception { + BdfDictionary emptyPropsDict = new BdfDictionary(); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, emptyPropsDict + ); + } + + @Test(expected = FormatException.class) + public void testRejectsMailboxPropsShortSupports() throws Exception { + clientHelper.parseAndValidateMailboxPropertiesUpdate( + BdfList.of(BdfList.of(1)), emptyServerSupports, + new BdfDictionary() + ); + } + + @Test(expected = FormatException.class) + public void testRejectsMailboxPropsLongSupports() throws Exception { + clientHelper.parseAndValidateMailboxPropertiesUpdate( + BdfList.of(BdfList.of(1, 0, 0)), emptyServerSupports, + new BdfDictionary() + ); + } + + @Test(expected = FormatException.class) + public void testRejectsMailboxPropsNonIntSupports() throws Exception { + clientHelper.parseAndValidateMailboxPropertiesUpdate( + BdfList.of(BdfList.of(1, "0")), emptyServerSupports, + new BdfDictionary() + ); + } + + @Test(expected = FormatException.class) + public void testRejectsMailboxPropsNonListSupports() throws Exception { + clientHelper.parseAndValidateMailboxPropertiesUpdate( + BdfList.of("non-list"), emptyServerSupports, new BdfDictionary() + ); } @Test public void testParseValidMailboxPropsUpdate() throws Exception { MailboxPropertiesUpdate parsedProps = clientHelper .parseAndValidateMailboxPropertiesUpdate( - getValidMailboxPropsUpdateDict()); + someClientSupports, someServerSupports, + getValidMailboxPropsUpdateDict() + ); assertTrue(mailboxPropertiesUpdateEqual(validMailboxPropsUpdate, parsedProps)); } + @Test(expected = FormatException.class) + public void rejectsMailboxPropsWithEmptyServerSupports() throws Exception { + clientHelper.parseAndValidateMailboxPropertiesUpdate( + someClientSupports, emptyServerSupports, + getValidMailboxPropsUpdateDict() + ); + } + @Test(expected = FormatException.class) public void testRejectsMailboxPropsUpdateOnionNotDecodable() throws Exception { @@ -570,7 +644,9 @@ public class ClientHelperImplTest extends BrambleMockTestCase { String badOnion = "!" + propsDict.getString(PROP_KEY_ONION) .substring(1); propsDict.put(PROP_KEY_ONION, badOnion); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + emptyServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -579,7 +655,9 @@ public class ClientHelperImplTest extends BrambleMockTestCase { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); String tooLongOnion = propsDict.getString(PROP_KEY_ONION) + "!"; propsDict.put(PROP_KEY_ONION, tooLongOnion); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + emptyServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -587,7 +665,9 @@ public class ClientHelperImplTest extends BrambleMockTestCase { throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.put(PROP_KEY_INBOXID, getRandomBytes(UniqueId.LENGTH + 1)); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -595,7 +675,9 @@ public class ClientHelperImplTest extends BrambleMockTestCase { throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.put(PROP_KEY_OUTBOXID, getRandomBytes(UniqueId.LENGTH + 1)); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -603,14 +685,18 @@ public class ClientHelperImplTest extends BrambleMockTestCase { throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.put(PROP_KEY_AUTHTOKEN, getRandomBytes(UniqueId.LENGTH + 1)); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) public void testRejectsMailboxPropsUpdateMissingOnion() throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.remove(PROP_KEY_ONION); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -618,14 +704,18 @@ public class ClientHelperImplTest extends BrambleMockTestCase { throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.remove(PROP_KEY_AUTHTOKEN); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) public void testRejectsMailboxPropsUpdateMissingInboxId() throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.remove(PROP_KEY_INBOXID); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } @Test(expected = FormatException.class) @@ -633,7 +723,9 @@ public class ClientHelperImplTest extends BrambleMockTestCase { throws Exception { BdfDictionary propsDict = getValidMailboxPropsUpdateDict(); propsDict.remove(PROP_KEY_OUTBOXID); - clientHelper.parseAndValidateMailboxPropertiesUpdate(propsDict); + clientHelper.parseAndValidateMailboxPropertiesUpdate(someClientSupports, + someServerSupports, propsDict + ); } } diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java index 70d6477a7..bd60e24be 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPairingTaskImplTest.java @@ -9,6 +9,7 @@ import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxPairingState; import org.briarproject.bramble.api.mailbox.MailboxPairingTask; import org.briarproject.bramble.api.mailbox.MailboxProperties; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; import org.briarproject.bramble.api.mailbox.MailboxPropertyManager; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; import org.briarproject.bramble.api.mailbox.OwnMailboxConnectionStatusEvent; @@ -24,10 +25,11 @@ import java.io.IOException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import java.util.ArrayList; -import java.util.Collections; import java.util.concurrent.Executor; import java.util.concurrent.atomic.AtomicInteger; +import static java.util.Collections.singletonList; +import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS; import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -105,16 +107,18 @@ public class MailboxPairingTaskImplTest extends BrambleMockTestCase { }}); Contact contact1 = getContact(); Transaction txn = new Transaction(null, false); + MailboxPropertiesUpdate emptyProps = new MailboxPropertiesUpdate( + CLIENT_SUPPORTS); context.checking(new DbExpectations() {{ oneOf(db).transaction(with(false), withDbRunnable(txn)); oneOf(mailboxSettingsManager).setOwnMailboxProperties( with(txn), with(matches(ownerProperties))); oneOf(mailboxSettingsManager).recordSuccessfulConnection(txn, time); oneOf(db).getContacts(txn); - will(returnValue(Collections.singletonList(contact1))); + will(returnValue(singletonList(contact1))); oneOf(mailboxPropertyManager).getRemoteProperties(txn, contact1.getId()); - will(returnValue(null)); + will(returnValue(emptyProps)); oneOf(db).resetUnackedMessagesToSend(txn, contact1.getId()); }}); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImplTest.java index fd2c6ab22..679555d53 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyManagerImplTest.java @@ -15,7 +15,9 @@ import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxProperties; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; import org.briarproject.bramble.api.mailbox.MailboxSettingsManager; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.mailbox.RemoteMailboxPropertiesUpdateEvent; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.GroupId; @@ -27,7 +29,6 @@ import org.briarproject.bramble.test.BrambleMockTestCase; import org.jmock.Expectations; import org.junit.Test; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -43,6 +44,7 @@ import static org.briarproject.bramble.api.mailbox.MailboxPropertyManager.PROP_K import static org.briarproject.bramble.api.mailbox.MailboxPropertyManager.PROP_KEY_OUTBOXID; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.validation.IncomingMessageHook.DeliveryAction.ACCEPT_DO_NOT_SHARE; +import static org.briarproject.bramble.mailbox.MailboxApi.CLIENT_SUPPORTS; import static org.briarproject.bramble.test.TestUtils.getContact; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getMessage; @@ -72,21 +74,44 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { private final Group localGroup = getGroup(CLIENT_ID, MAJOR_VERSION); private final BdfDictionary propsDict; private final BdfDictionary emptyPropsDict = new BdfDictionary(); - private final MailboxPropertiesUpdate props; + private final BdfList realClientSupports; + private final BdfList someClientSupports; + private final List someClientSupportsList; + private final BdfList emptyServerSupports; + private final BdfList someServerSupports; + private final List someServerSupportsList; + private final MailboxPropertiesUpdateMailbox updateMailbox; + private final MailboxPropertiesUpdate updateNoMailbox; private final MailboxProperties ownProps; public MailboxPropertyManagerImplTest() { + someClientSupports = BdfList.of(BdfList.of(1, 0)); + someClientSupportsList = singletonList(new MailboxVersion(1, 0)); + emptyServerSupports = new BdfList(); + someServerSupports = BdfList.of(BdfList.of(1, 0)); + someServerSupportsList = singletonList(new MailboxVersion(1, 0)); + realClientSupports = new BdfList(); + for (MailboxVersion v : CLIENT_SUPPORTS) { + realClientSupports.add(BdfList.of(v.getMajor(), v.getMinor())); + } ownProps = new MailboxProperties("http://bar.onion", - new MailboxAuthToken(getRandomId()), true, new ArrayList<>()); - props = new MailboxPropertiesUpdate(ownProps.getOnion(), + new MailboxAuthToken(getRandomId()), true, + someServerSupportsList); + updateMailbox = new MailboxPropertiesUpdateMailbox( + singletonList(new MailboxVersion(1, 0)), + singletonList(new MailboxVersion(1, 0)), + ownProps.getOnion(), new MailboxAuthToken(getRandomId()), new MailboxFolderId(getRandomId()), new MailboxFolderId(getRandomId())); propsDict = new BdfDictionary(); - propsDict.put(PROP_KEY_ONION, props.getOnion()); - propsDict.put(PROP_KEY_AUTHTOKEN, props.getAuthToken().getBytes()); - propsDict.put(PROP_KEY_INBOXID, props.getInboxId().getBytes()); - propsDict.put(PROP_KEY_OUTBOXID, props.getOutboxId().getBytes()); + propsDict.put(PROP_KEY_ONION, updateMailbox.getOnion()); + propsDict.put(PROP_KEY_AUTHTOKEN, + updateMailbox.getAuthToken().getBytes()); + propsDict.put(PROP_KEY_INBOXID, updateMailbox.getInboxId().getBytes()); + propsDict.put(PROP_KEY_OUTBOXID, + updateMailbox.getOutboxId().getBytes()); + updateNoMailbox = new MailboxPropertiesUpdate(someClientSupportsList); } private MailboxPropertyManagerImpl createInstance() { @@ -105,6 +130,7 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + Map messageMetadata = new LinkedHashMap<>(); context.checking(new Expectations() {{ oneOf(db).containsGroup(txn, localGroup.getId()); @@ -125,6 +151,14 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { contact.getId()); oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn); will(returnValue(null)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + MAJOR_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(messageMetadata)); + expectStoreMessage(txn, contactGroup.getId(), 1, realClientSupports, + emptyServerSupports, emptyPropsDict, true); }}); MailboxPropertyManagerImpl t = createInstance(); @@ -159,18 +193,19 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn); will(returnValue(ownProps)); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getAuthToken())); + will(returnValue(updateMailbox.getAuthToken())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getInboxId())); + will(returnValue(updateMailbox.getInboxId())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getOutboxId())); + will(returnValue(updateMailbox.getOutboxId())); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, MAJOR_VERSION, contact); will(returnValue(contactGroup)); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - expectStoreMessage(txn, contactGroup.getId(), propsDict, 1, true); + expectStoreMessage(txn, contactGroup.getId(), 1, realClientSupports, + someServerSupports, propsDict, true); }}); MailboxPropertyManagerImpl t = createInstance(); @@ -197,6 +232,7 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { Transaction txn = new Transaction(null, false); Contact contact = getContact(); Group contactGroup = getGroup(CLIENT_ID, MAJOR_VERSION); + Map messageMetadata = new LinkedHashMap<>(); context.checking(new Expectations() {{ // Create the group and share it with the contact @@ -213,6 +249,14 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { contact.getId()); oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn); will(returnValue(null)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + MAJOR_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId()); + will(returnValue(messageMetadata)); + expectStoreMessage(txn, contactGroup.getId(), 1, realClientSupports, + emptyServerSupports, emptyPropsDict, true); }}); MailboxPropertyManagerImpl t = createInstance(); @@ -243,18 +287,19 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(mailboxSettingsManager).getOwnMailboxProperties(txn); will(returnValue(ownProps)); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getAuthToken())); + will(returnValue(updateMailbox.getAuthToken())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getInboxId())); + will(returnValue(updateMailbox.getInboxId())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getOutboxId())); + will(returnValue(updateMailbox.getOutboxId())); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, MAJOR_VERSION, contact); will(returnValue(contactGroup)); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - expectStoreMessage(txn, contactGroup.getId(), propsDict, 1, true); + expectStoreMessage(txn, contactGroup.getId(), 1, someClientSupports, + someServerSupports, propsDict, true); }}); MailboxPropertyManagerImpl t = createInstance(); @@ -285,7 +330,8 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); Message message = getMessage(contactGroupId); - BdfList body = BdfList.of(1, propsDict); + BdfList body = BdfList.of(1, someClientSupports, someServerSupports, + propsDict); Metadata meta = new Metadata(); BdfDictionary metaDictionary = BdfDictionary.of( new BdfEntry(MSG_KEY_VERSION, 1), @@ -310,8 +356,8 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageAsList(txn, message.getId()); will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - propsDict); - will(returnValue(props)); + someClientSupports, someServerSupports, propsDict); + will(returnValue(updateMailbox)); oneOf(db).resetUnackedMessagesToSend(txn, contact.getId()); }}); @@ -328,7 +374,8 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { Contact contact = getContact(); GroupId contactGroupId = new GroupId(getRandomId()); Message message = getMessage(contactGroupId); - BdfList body = BdfList.of(1, propsDict); + BdfList body = BdfList.of(1, someClientSupports, someServerSupports, + propsDict); Metadata meta = new Metadata(); BdfDictionary metaDictionary = BdfDictionary.of( new BdfEntry(MSG_KEY_VERSION, 2), @@ -361,8 +408,8 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageAsList(txn, message.getId()); will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - propsDict); - will(returnValue(props)); + someClientSupports, someServerSupports, propsDict); + will(returnValue(updateMailbox)); oneOf(db).resetUnackedMessagesToSend(txn, contact.getId()); }}); @@ -430,23 +477,24 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(db).getContacts(txn); will(returnValue(contacts)); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getAuthToken())); + will(returnValue(updateMailbox.getAuthToken())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getInboxId())); + will(returnValue(updateMailbox.getInboxId())); oneOf(crypto).generateUniqueId(); - will(returnValue(props.getOutboxId())); + will(returnValue(updateMailbox.getOutboxId())); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, MAJOR_VERSION, contact); will(returnValue(contactGroup)); oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - expectStoreMessage(txn, contactGroup.getId(), propsDict, 2, true); + expectStoreMessage(txn, contactGroup.getId(), 2, someClientSupports, + someServerSupports, propsDict, true); oneOf(db).removeMessage(txn, latestId); }}); MailboxPropertyManagerImpl t = createInstance(); - t.mailboxPaired(txn, ownProps.getOnion()); + t.mailboxPaired(txn, ownProps.getOnion(), someServerSupportsList); } @Test @@ -478,8 +526,8 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - expectStoreMessage(txn, contactGroup.getId(), emptyPropsDict, - 2, true); + expectStoreMessage(txn, contactGroup.getId(), 2, someClientSupports, + emptyServerSupports, emptyPropsDict, true); oneOf(db).removeMessage(txn, latestId); }}); @@ -498,9 +546,10 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_LOCAL, false) ); Map messageMetadata = new LinkedHashMap<>(); - MessageId fooUpdateId = new MessageId(getRandomId()); - messageMetadata.put(fooUpdateId, metaDictionary); - BdfList fooUpdate = BdfList.of(1, propsDict); + MessageId messageId = new MessageId(getRandomId()); + messageMetadata.put(messageId, metaDictionary); + BdfList body = BdfList.of(1, someClientSupports, someServerSupports, + propsDict); context.checking(new Expectations() {{ oneOf(db).getContact(txn, contact.getId()); @@ -511,17 +560,17 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); - will(returnValue(fooUpdate)); + oneOf(clientHelper).getMessageAsList(txn, messageId); + will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - propsDict); - will(returnValue(props)); + someClientSupports, someServerSupports, propsDict); + will(returnValue(updateMailbox)); }}); MailboxPropertyManagerImpl t = createInstance(); MailboxPropertiesUpdate remote = t.getRemoteProperties(txn, contact.getId()); - assertTrue(mailboxPropertiesUpdateEqual(remote, props)); + assertTrue(mailboxPropertiesUpdateEqual(remote, updateMailbox)); } @Test @@ -549,7 +598,7 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { } @Test - public void testGetRemotePropertiesReturnsNullBecauseEmptyUpdate() + public void testGetRemotePropertiesNoMailbox() throws Exception { Transaction txn = new Transaction(null, false); Contact contact = getContact(); @@ -559,9 +608,10 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_LOCAL, false) ); Map messageMetadata = new LinkedHashMap<>(); - MessageId fooUpdateId = new MessageId(getRandomId()); - messageMetadata.put(fooUpdateId, metaDictionary); - BdfList fooUpdate = BdfList.of(1, emptyPropsDict); + MessageId messageId = new MessageId(getRandomId()); + messageMetadata.put(messageId, metaDictionary); + BdfList body = BdfList.of(1, someClientSupports, emptyServerSupports, + emptyPropsDict); context.checking(new Expectations() {{ oneOf(db).getContact(txn, contact.getId()); @@ -572,15 +622,17 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); - will(returnValue(fooUpdate)); + oneOf(clientHelper).getMessageAsList(txn, messageId); + will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - emptyPropsDict); - will(returnValue(null)); + someClientSupports, emptyServerSupports, emptyPropsDict); + will(returnValue(updateNoMailbox)); }}); MailboxPropertyManagerImpl t = createInstance(); - assertNull(t.getRemoteProperties(txn, contact.getId())); + MailboxPropertiesUpdate remote = + t.getRemoteProperties(txn, contact.getId()); + assertTrue(mailboxPropertiesUpdateEqual(remote, updateNoMailbox)); } @Test @@ -594,9 +646,10 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_LOCAL, true) ); Map messageMetadata = new LinkedHashMap<>(); - MessageId fooUpdateId = new MessageId(getRandomId()); - messageMetadata.put(fooUpdateId, metaDictionary); - BdfList fooUpdate = BdfList.of(1, propsDict); + MessageId messageId = new MessageId(getRandomId()); + messageMetadata.put(messageId, metaDictionary); + BdfList body = BdfList.of(1, someClientSupports, someServerSupports, + propsDict); context.checking(new Expectations() {{ oneOf(db).getContact(txn, contact.getId()); @@ -607,17 +660,17 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); - will(returnValue(fooUpdate)); + oneOf(clientHelper).getMessageAsList(txn, messageId); + will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - propsDict); - will(returnValue(props)); + someClientSupports, someServerSupports, propsDict); + will(returnValue(updateMailbox)); }}); MailboxPropertyManagerImpl t = createInstance(); MailboxPropertiesUpdate local = t.getLocalProperties(txn, contact.getId()); - assertTrue(mailboxPropertiesUpdateEqual(local, props)); + assertTrue(mailboxPropertiesUpdateEqual(local, updateMailbox)); } @Test @@ -645,7 +698,7 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { } @Test - public void testGetLocalPropertiesReturnsNullBecauseEmptyUpdate() + public void testGetLocalPropertiesNoMailbox() throws Exception { Transaction txn = new Transaction(null, false); Contact contact = getContact(); @@ -655,9 +708,10 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { new BdfEntry(MSG_KEY_LOCAL, true) ); Map messageMetadata = new LinkedHashMap<>(); - MessageId fooUpdateId = new MessageId(getRandomId()); - messageMetadata.put(fooUpdateId, metaDictionary); - BdfList fooUpdate = BdfList.of(1, emptyPropsDict); + MessageId messageId = new MessageId(getRandomId()); + messageMetadata.put(messageId, metaDictionary); + BdfList body = BdfList.of(1, someClientSupports, emptyServerSupports, + emptyPropsDict); context.checking(new Expectations() {{ oneOf(db).getContact(txn, contact.getId()); @@ -668,21 +722,25 @@ public class MailboxPropertyManagerImplTest extends BrambleMockTestCase { oneOf(clientHelper).getMessageMetadataAsDictionary(txn, contactGroup.getId()); will(returnValue(messageMetadata)); - oneOf(clientHelper).getMessageAsList(txn, fooUpdateId); - will(returnValue(fooUpdate)); + oneOf(clientHelper).getMessageAsList(txn, messageId); + will(returnValue(body)); oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - emptyPropsDict); - will(returnValue(null)); + someClientSupports, emptyServerSupports, emptyPropsDict); + will(returnValue(updateNoMailbox)); }}); MailboxPropertyManagerImpl t = createInstance(); - assertNull(t.getLocalProperties(txn, contact.getId())); + MailboxPropertiesUpdate local = + t.getLocalProperties(txn, contact.getId()); + assertTrue(mailboxPropertiesUpdateEqual(local, updateNoMailbox)); } private void expectStoreMessage(Transaction txn, GroupId g, - BdfDictionary properties, long version, boolean local) + long version, BdfList clientSupports, BdfList serverSupports, + BdfDictionary properties, boolean local) throws Exception { - BdfList body = BdfList.of(version, properties); + BdfList body = BdfList.of(version, clientSupports, serverSupports, + properties); Message message = getMessage(g); long timestamp = message.getTimestamp(); BdfDictionary meta = BdfDictionary.of( diff --git a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyValidatorTest.java b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyValidatorTest.java index 0ee1747da..eea64ac5e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyValidatorTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/mailbox/MailboxPropertyValidatorTest.java @@ -9,7 +9,9 @@ import org.briarproject.bramble.api.data.MetadataEncoder; import org.briarproject.bramble.api.mailbox.MailboxAuthToken; import org.briarproject.bramble.api.mailbox.MailboxFolderId; import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdate; +import org.briarproject.bramble.api.mailbox.MailboxPropertiesUpdateMailbox; import org.briarproject.bramble.api.mailbox.MailboxPropertyManager; +import org.briarproject.bramble.api.mailbox.MailboxVersion; import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Message; import org.briarproject.bramble.api.system.Clock; @@ -18,7 +20,9 @@ import org.jmock.Expectations; import org.junit.Test; import java.io.IOException; +import java.util.List; +import static java.util.Collections.singletonList; import static org.briarproject.bramble.test.TestUtils.getGroup; import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomId; @@ -29,7 +33,12 @@ public class MailboxPropertyValidatorTest extends BrambleMockTestCase { private final ClientHelper clientHelper = context.mock(ClientHelper.class); private final BdfDictionary bdfDict; - private final MailboxPropertiesUpdate mailboxProps; + private final BdfList emptyServerSupports; + private final BdfList someClientSupports; + private final List someClientSupportsList; + private final BdfList someServerSupports; + private final MailboxPropertiesUpdateMailbox updateMailbox; + private final MailboxPropertiesUpdate updateNoMailbox; private final Group group; private final Message message; private final MailboxPropertyValidator mpv; @@ -38,11 +47,21 @@ public class MailboxPropertyValidatorTest extends BrambleMockTestCase { // Just dummies, clientHelper is mocked so our test is a bit shallow; // not testing // {@link ClientHelper#parseAndValidateMailboxPropertiesUpdate(BdfDictionary)} + emptyServerSupports = new BdfList(); + someClientSupports = BdfList.of(BdfList.of(1, 0)); + someClientSupportsList = singletonList(new MailboxVersion(1, 0)); + someServerSupports = BdfList.of(BdfList.of(1, 0)); bdfDict = BdfDictionary.of(new BdfEntry("foo", "bar")); - mailboxProps = new MailboxPropertiesUpdate("baz", + + updateMailbox = new MailboxPropertiesUpdateMailbox( + singletonList(new MailboxVersion(1, 0)), + singletonList(new MailboxVersion(1, 0)), + "baz", new MailboxAuthToken(getRandomId()), new MailboxFolderId(getRandomId()), new MailboxFolderId(getRandomId())); + updateNoMailbox = new MailboxPropertiesUpdate(someClientSupportsList); + group = getGroup(MailboxPropertyManager.CLIENT_ID, MailboxPropertyManager.MAJOR_VERSION); @@ -56,12 +75,13 @@ public class MailboxPropertyValidatorTest extends BrambleMockTestCase { @Test public void testValidateMessageBody() throws IOException { - BdfList body = BdfList.of(4, bdfDict); + BdfList body = + BdfList.of(4, someClientSupports, someServerSupports, bdfDict); context.checking(new Expectations() {{ oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - bdfDict); - will(returnValue(mailboxProps)); + someClientSupports, someServerSupports, bdfDict); + will(returnValue(updateMailbox)); }}); BdfDictionary result = @@ -82,14 +102,15 @@ public class MailboxPropertyValidatorTest extends BrambleMockTestCase { } @Test - public void testEmptyPropertiesReturnsNull() throws IOException { + public void testEmptyProperties() throws IOException { BdfDictionary emptyBdfDict = new BdfDictionary(); - BdfList body = BdfList.of(42, emptyBdfDict); + BdfList body = BdfList.of(42, someClientSupports, emptyServerSupports, + emptyBdfDict); context.checking(new Expectations() {{ oneOf(clientHelper).parseAndValidateMailboxPropertiesUpdate( - emptyBdfDict); - will(returnValue(null)); + someClientSupports, emptyServerSupports, emptyBdfDict); + will(returnValue(updateNoMailbox)); }}); BdfDictionary result =