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.
This commit is contained in:
Daniel Lublin
2022-05-13 11:45:42 +02:00
parent 5d5d8d206c
commit a42d9eec1c
17 changed files with 473 additions and 171 deletions

View File

@@ -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<MailboxVersion> clientSupportsList =
getMailboxVersionList(clientSupports);
List<MailboxVersion> 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<MailboxVersion> getMailboxVersionList(BdfList bdfList)
throws FormatException {
List<MailboxVersion> 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

View File

@@ -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<MailboxVersion> CLIENT_SUPPORTS = singletonList(
new MailboxVersion(1, 0));
/**
* Sets up the mailbox with the setup token.
*

View File

@@ -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());
}
}

View File

@@ -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<MailboxVersion> 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<MailboxVersion> 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<MailboxVersion> 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) {

View File

@@ -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);

View File

@@ -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());
}
}