diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/Contact.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/Contact.java index 1d921e8017f62e03100fda3e16f53692eac31155..c7aea8607f21c440279f37eeb2bafada08ed1c2d 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/Contact.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/Contact.java @@ -6,6 +6,8 @@ import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import javax.annotation.concurrent.Immutable; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; + @Immutable @NotNullByDefault public class Contact { @@ -36,6 +38,10 @@ public class Contact { return localAuthorId; } + public int getType() { + return CONTACT; + } + public boolean isVerified() { return verified; } @@ -44,6 +50,10 @@ public class Contact { return active; } + public boolean isHidden() { + return false; + } + @Override public int hashCode() { return id.hashCode(); diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java index 28857276e85a8048a0cc38d2b12ef9519fa95c1e..ab9daacc9b17a6708c6e421eb65d3bc46af9cc0f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactExchangeTask.java @@ -1,10 +1,14 @@ package org.briarproject.bramble.api.contact; import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; +import org.briarproject.bramble.api.properties.TransportProperties; + +import java.util.Map; /** * A task for conducting a contact information exchange with a remote peer. @@ -44,5 +48,23 @@ public interface ContactExchangeTask { void startExchange(ContactExchangeListener listener, LocalAuthor localAuthor, SecretKey masterSecret, DuplexTransportConnection conn, TransportId transportId, - boolean alice); + boolean alice, int localType, int remoteType); + + class ContactInfo { + public final Author author; + public final Map<TransportId, TransportProperties> properties; + public final byte[] signature; + public final long timestamp; + public final int type; + + public ContactInfo(Author author, + Map<TransportId, TransportProperties> properties, + byte[] signature, long timestamp, int type) { + this.author = author; + this.properties = properties; + this.signature = signature; + this.timestamp = timestamp; + this.type = type; + } + } } diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..b66eb4f080a9777d997e685b319264dfdd251631 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactFactory.java @@ -0,0 +1,30 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; +import static org.briarproject.bramble.api.contact.ContactTypes.MAILBOX_OWNER; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; + +@NotNullByDefault +public class ContactFactory { + + public static Contact createContact(ContactId c, Author author, + AuthorId localAuthorId, boolean verified, boolean active, + int type) { + switch (type) { + case CONTACT: + return new Contact(c, author, localAuthorId, verified, active); + case PRIVATE_MAILBOX: + return new PrivateMailbox(c, author, localAuthorId, verified, + active); + case MAILBOX_OWNER: + return new MailboxOwner(c, author, localAuthorId, verified, + active); + default: + throw new IllegalArgumentException("Unknown contact type"); + } + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java index 1f9daf48afc077a71ca87fa1a0a00de4db46cd99..23319c2d5c1e5c628b15e806c172429c7848a0d2 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactManager.java @@ -49,6 +49,16 @@ public interface ContactManager { long timestamp, boolean alice, boolean verified, boolean active) throws DbException; + + /** + * Add Repeater Contact + */ + ContactId addPrivateMailbox(Transaction txn, Author remote, AuthorId local, + SecretKey master, long timestamp, boolean alice) throws DbException; + + ContactId addMailboxOwner(Transaction txn, Author remote, AuthorId local, + SecretKey master, long timestamp, boolean alice) throws DbException; + /** * Returns the contact with the given ID. */ @@ -77,6 +87,16 @@ public interface ContactManager { */ Collection<Contact> getActiveContacts() throws DbException; + /** + * Returns all contacts which are visible to the user. + */ + Collection<Contact> getVisibleContacts() throws DbException; + + /** + * Returns all contacts of the give type. + */ + Collection<Contact> getContactsByType(int type) throws DbException; + /** * Removes a contact and all associated state. */ @@ -105,6 +125,7 @@ public interface ContactManager { boolean contactExists(AuthorId remoteAuthorId, AuthorId localAuthorId) throws DbException; + interface ContactHook { void addingContact(Transaction txn, Contact c) throws DbException; diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactTypes.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactTypes.java new file mode 100644 index 0000000000000000000000000000000000000000..33056f87b8ea4fecbf865858fa738afdb61fc66a --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/ContactTypes.java @@ -0,0 +1,9 @@ +package org.briarproject.bramble.api.contact; + +public interface ContactTypes { + int CONTACT = 0; + int PRIVATE_MAILBOX = 1; + int CONTACT_MAILBOX = 2; + int MAILBOX_OWNER = 3; + int MAILBOX_CONTACT = 4; +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxExchangeTask.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxExchangeTask.java new file mode 100644 index 0000000000000000000000000000000000000000..7d7f60b9b7af07d2917271046623bd5ebaf7f4e4 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxExchangeTask.java @@ -0,0 +1,8 @@ +package org.briarproject.bramble.api.contact; + +public interface MailboxExchangeTask extends ContactExchangeTask { + /** + * The current version of the contact exchange protocol. + */ + byte PROTOCOL_VERSION = 2; +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxOwner.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxOwner.java new file mode 100644 index 0000000000000000000000000000000000000000..067e55ad7ecb8076f8c14a24beabe3ad5845fd74 --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/MailboxOwner.java @@ -0,0 +1,31 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.contact.ContactTypes.MAILBOX_OWNER; + +@Immutable +@NotNullByDefault +public class MailboxOwner extends Contact { + + public MailboxOwner(ContactId id, + Author author, + AuthorId localAuthorId, + boolean verified, boolean active) { + super(id, author, localAuthorId, verified, active); + } + + @Override + public int getType() { + return MAILBOX_OWNER; + } + + @Override + public boolean isHidden() { + return true; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PrivateMailbox.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PrivateMailbox.java new file mode 100644 index 0000000000000000000000000000000000000000..b5b6a9c9a7de3812687fbf28d2e0e7808cf0363b --- /dev/null +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/PrivateMailbox.java @@ -0,0 +1,31 @@ +package org.briarproject.bramble.api.contact; + +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.nullsafety.NotNullByDefault; + +import javax.annotation.concurrent.Immutable; + +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; + +@Immutable +@NotNullByDefault +public class PrivateMailbox extends Contact { + + public PrivateMailbox(ContactId id, + Author author, + AuthorId localAuthorId, + boolean verified, boolean active) { + super(id, author, localAuthorId, verified, active); + } + + @Override + public int getType() { + return PRIVATE_MAILBOX; + } + + @Override + public boolean isHidden() { + return true; + } +} diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/RecordTypes.java b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/RecordTypes.java index bd24dcf67d892b5a37696f7777b500e57e8a5fbb..0375a1c7b1f9ff2fa97df69b86f91dd35510890f 100644 --- a/bramble-api/src/main/java/org/briarproject/bramble/api/contact/RecordTypes.java +++ b/bramble-api/src/main/java/org/briarproject/bramble/api/contact/RecordTypes.java @@ -6,4 +6,5 @@ package org.briarproject.bramble.api.contact; public interface RecordTypes { byte CONTACT_INFO = 0; + byte MAILBOX_INFO = 1; } 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 914b88a2e2d1db1a8bafa328850ca07dd80ed189..db32449aa36e4c163fa2c70a625e9f875b96569f 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 @@ -79,7 +79,7 @@ public interface DatabaseComponent { * and returns an ID for the contact. */ ContactId addContact(Transaction txn, Author remote, AuthorId local, - boolean verified, boolean active) throws DbException; + boolean verified, boolean active, int type) throws DbException; /** * Stores a group. @@ -208,6 +208,14 @@ public interface DatabaseComponent { Collection<Contact> getContactsByAuthorId(Transaction txn, AuthorId remote) throws DbException; + /** + * Returns a possibly empty collection of contacts of the given type. + * <p/> + * Read-only. + */ + Collection<Contact> getContactsByType(Transaction txn, int type) + throws DbException; + /** * Returns all contacts associated with the given local pseudonym. * <p/> @@ -267,7 +275,7 @@ public interface DatabaseComponent { * Read-only. */ Collection<MessageId> getMessageIds(Transaction txn, GroupId g) - throws DbException; + throws DbException; /** * Returns the IDs of any messages that need to be validated. @@ -487,7 +495,7 @@ public interface DatabaseComponent { * Removes the given transport keys from the database. */ void removeTransportKeys(Transaction txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Marks the given contact as verified. @@ -534,7 +542,7 @@ public interface DatabaseComponent { * Marks the given transport keys as usable for outgoing streams. */ void setTransportKeysActive(Transaction txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Stores the given transport keys, deleting any keys they have replaced. 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 afc40d91b87198f658f2eb39cda20f1955aa88ca..05fe22ae3c61f7d40f105daec552fea8f5882631 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 @@ -49,6 +49,7 @@ import static org.briarproject.bramble.util.ValidationUtils.checkSize; @NotNullByDefault class ClientHelperImpl implements ClientHelper { + /** * Length in bytes of the random salt used for creating local messages for * storing metadata. diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java index 69a543058c0d9f1bf1fa94f86b8a85a19a5f8ec1..16bdc9ec52e86ef077c79da2c543a4405a2ce52e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactExchangeTaskImpl.java @@ -78,6 +78,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { private volatile TransportId transportId; private volatile SecretKey masterSecret; private volatile boolean alice; + private volatile int localType, remoteType; @Inject ContactExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper, @@ -104,13 +105,15 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { public void startExchange(ContactExchangeListener listener, LocalAuthor localAuthor, SecretKey masterSecret, DuplexTransportConnection conn, TransportId transportId, - boolean alice) { + boolean alice, int localType, int remoteType) { this.listener = listener; this.localAuthor = localAuthor; this.conn = conn; this.transportId = transportId; this.masterSecret = masterSecret; this.alice = alice; + this.localType = localType; + this.remoteType = remoteType; start(); } @@ -281,7 +284,7 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { checkLength(signature, 1, MAX_SIGNATURE_LENGTH); long timestamp = payload.getLong(3); if (timestamp < 0) throw new FormatException(); - return new ContactInfo(author, properties, signature, timestamp); + return new ContactInfo(author, properties, signature, timestamp, remoteType); } private ContactId addContact(Author remoteAuthor, long timestamp, @@ -311,21 +314,4 @@ class ContactExchangeTaskImpl extends Thread implements ContactExchangeTask { logException(LOG, WARNING, e); } } - - private static class ContactInfo { - - private final Author author; - private final Map<TransportId, TransportProperties> properties; - private final byte[] signature; - private final long timestamp; - - private ContactInfo(Author author, - Map<TransportId, TransportProperties> properties, - byte[] signature, long timestamp) { - this.author = author; - this.properties = properties; - this.signature = signature; - this.timestamp = timestamp; - } - } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java index 02c94fc750aa1cef2edf7673b34d4fa40e65f94d..3d89da84e40d13df9c15335199d380bdf58a4a23 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactManagerImpl.java @@ -21,6 +21,10 @@ import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.concurrent.ThreadSafe; import javax.inject.Inject; +import static org.briarproject.bramble.api.contact.ContactTypes.MAILBOX_OWNER; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; + @ThreadSafe @NotNullByDefault class ContactManagerImpl implements ContactManager { @@ -45,7 +49,8 @@ class ContactManagerImpl implements ContactManager { public ContactId addContact(Transaction txn, Author remote, AuthorId local, SecretKey master, long timestamp, boolean alice, boolean verified, boolean active) throws DbException { - ContactId c = db.addContact(txn, remote, local, verified, active); + ContactId c = db.addContact(txn, remote, local, verified, active, + CONTACT); keyManager.addContact(txn, c, master, timestamp, alice, active); Contact contact = db.getContact(txn, c); for (ContactHook hook : hooks) hook.addingContact(txn, contact); @@ -55,7 +60,8 @@ class ContactManagerImpl implements ContactManager { @Override public ContactId addContact(Transaction txn, Author remote, AuthorId local, boolean verified, boolean active) throws DbException { - ContactId c = db.addContact(txn, remote, local, verified, active); + ContactId c = db.addContact(txn, remote, local, verified, active, + CONTACT); Contact contact = db.getContact(txn, c); for (ContactHook hook : hooks) hook.addingContact(txn, contact); return c; @@ -77,6 +83,53 @@ class ContactManagerImpl implements ContactManager { return c; } + @Override + public ContactId addPrivateMailbox(Transaction txn, Author remote, + AuthorId local, + SecretKey master, long timestamp, boolean alice) + throws DbException { + + Collection<Contact> privateMailbox = + db.getContactsByType(txn, PRIVATE_MAILBOX); + + // We only allow a single private mailbox per user and if + // the user tries to add the same repeater twice, addContact + // throws an exception + for (Contact c : privateMailbox) + if (!c.getAuthor().getId().equals(remote.getId())) + db.removeContact(txn, c.getId()); + + + ContactId c = db.addContact(txn, remote, local, true, true, + PRIVATE_MAILBOX); + keyManager.addContact(txn, c, master, timestamp, alice, true); + Contact contact = db.getContact(txn, c); + for (ContactHook hook : hooks) hook.addingContact(txn, contact); + return c; + } + + @Override + public ContactId addMailboxOwner(Transaction txn, Author remote, + AuthorId local, SecretKey master, long timestamp, boolean alice) throws DbException { + // We only allow a single owner per mailbox + Collection<Contact> mbOwner = + db.getContactsByType(txn, MAILBOX_OWNER) ; + + // We only allow a single private mailbox per user and if + // the user tries to add the same repeater twice, addContact + // throws an exception + for (Contact c : mbOwner) + if (!c.getAuthor().getId().equals(remote.getId())) + db.removeContact(txn, c.getId()); + + ContactId c = db.addContact(txn, remote, local, true, true, + MAILBOX_OWNER); + keyManager.addContact(txn, c, master, timestamp, alice, true); + Contact contact = db.getContact(txn, c); + for (ContactHook hook : hooks) hook.addingContact(txn, contact); + return c; + } + @Override public Contact getContact(ContactId c) throws DbException { Contact contact; @@ -116,8 +169,7 @@ class ContactManagerImpl implements ContactManager { throw new NoSuchContactException(); } - @Override - public Collection<Contact> getActiveContacts() throws DbException { + private Collection<Contact> getContacts() throws DbException { Collection<Contact> contacts; Transaction txn = db.startTransaction(true); try { @@ -126,11 +178,39 @@ class ContactManagerImpl implements ContactManager { } finally { db.endTransaction(txn); } + return contacts; + } + + @Override + public Collection<Contact> getActiveContacts() throws DbException { + Collection<Contact> contacts = getContacts(); List<Contact> active = new ArrayList<>(contacts.size()); for (Contact c : contacts) if (c.isActive()) active.add(c); return active; } + @Override + public Collection<Contact> getVisibleContacts() throws DbException { + Collection<Contact> contacts = getContacts(); + List<Contact> visible = new ArrayList<>(contacts.size()); + for (Contact c : contacts) + if (c.isActive() && !c.isHidden()) visible.add(c); + return visible; + } + + @Override + public Collection<Contact> getContactsByType(int type) throws DbException { + Collection<Contact> contacts; + Transaction txn = db.startTransaction(true); + try { + contacts = db.getContactsByType(txn, type); + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + return contacts; + } + @Override public void removeContact(ContactId c) throws DbException { Transaction txn = db.startTransaction(false); diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactModule.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactModule.java index 2cb610972caac67f87f197aaafd15016fe7472d7..3599ade1c005ea96b1ea5a69b7f3ec6611173445 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactModule.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/ContactModule.java @@ -2,6 +2,7 @@ package org.briarproject.bramble.contact; import org.briarproject.bramble.api.contact.ContactExchangeTask; import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.MailboxExchangeTask; import javax.inject.Inject; import javax.inject.Singleton; @@ -28,4 +29,10 @@ public class ContactModule { ContactExchangeTaskImpl contactExchangeTask) { return contactExchangeTask; } + + @Provides + MailboxExchangeTask provideMailboxExchangeTask( + MailboxExchangeTaskImpl mailboxExchangeTask) { + return mailboxExchangeTask; + } } diff --git a/bramble-core/src/main/java/org/briarproject/bramble/contact/MailboxExchangeTaskImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/contact/MailboxExchangeTaskImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7d09cb6e654c04ca35e3dece56556e314fc9260d --- /dev/null +++ b/bramble-core/src/main/java/org/briarproject/bramble/contact/MailboxExchangeTaskImpl.java @@ -0,0 +1,332 @@ +package org.briarproject.bramble.contact; + +import org.briarproject.bramble.api.FormatException; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactExchangeListener; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.MailboxExchangeTask; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.SecretKey; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfList; +import org.briarproject.bramble.api.db.ContactExistsException; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.DbException; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.LocalAuthor; +import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; +import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; +import org.briarproject.bramble.api.plugin.ConnectionManager; +import org.briarproject.bramble.api.plugin.TransportId; +import org.briarproject.bramble.api.plugin.duplex.DuplexTransportConnection; +import org.briarproject.bramble.api.properties.TransportProperties; +import org.briarproject.bramble.api.properties.TransportPropertyManager; +import org.briarproject.bramble.api.record.Record; +import org.briarproject.bramble.api.record.RecordReader; +import org.briarproject.bramble.api.record.RecordReaderFactory; +import org.briarproject.bramble.api.record.RecordWriter; +import org.briarproject.bramble.api.record.RecordWriterFactory; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.bramble.api.transport.StreamReaderFactory; +import org.briarproject.bramble.api.transport.StreamWriter; +import org.briarproject.bramble.api.transport.StreamWriterFactory; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.GeneralSecurityException; +import java.util.Map; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactTypes.MAILBOX_OWNER; +import static org.briarproject.bramble.api.contact.RecordTypes.MAILBOX_INFO; +import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_SIGNATURE_LENGTH; +import static org.briarproject.bramble.util.LogUtils.logException; +import static org.briarproject.bramble.util.ValidationUtils.checkLength; +import static org.briarproject.bramble.util.ValidationUtils.checkSize; + +@MethodsNotNullByDefault +@ParametersNotNullByDefault +class MailboxExchangeTaskImpl extends Thread implements MailboxExchangeTask { + private static final Logger LOG = + Logger.getLogger(MailboxExchangeTaskImpl.class.getName()); + + private static final String SIGNING_LABEL_EXCHANGE = + "org.briarproject.briar.contact/EXCHANGE"; + + private final DatabaseComponent db; + private final ClientHelper clientHelper; + private final RecordReaderFactory recordReaderFactory; + private final RecordWriterFactory recordWriterFactory; + private final Clock clock; + private final ConnectionManager connectionManager; + private final ContactManager contactManager; + private final TransportPropertyManager transportPropertyManager; + private final CryptoComponent crypto; + private final StreamReaderFactory streamReaderFactory; + private final StreamWriterFactory streamWriterFactory; + + private volatile ContactExchangeListener listener; + private volatile LocalAuthor localAuthor; + private volatile DuplexTransportConnection conn; + private volatile TransportId transportId; + private volatile SecretKey masterSecret; + private volatile boolean alice; + private volatile int localType, remoteType; + + @Inject + MailboxExchangeTaskImpl(DatabaseComponent db, ClientHelper clientHelper, + RecordReaderFactory recordReaderFactory, + RecordWriterFactory recordWriterFactory, Clock clock, + ConnectionManager connectionManager, ContactManager contactManager, + TransportPropertyManager transportPropertyManager, + CryptoComponent crypto, StreamReaderFactory streamReaderFactory, + StreamWriterFactory streamWriterFactory) { + this.db = db; + this.clientHelper = clientHelper; + this.recordReaderFactory = recordReaderFactory; + this.recordWriterFactory = recordWriterFactory; + this.clock = clock; + this.connectionManager = connectionManager; + this.contactManager = contactManager; + this.transportPropertyManager = transportPropertyManager; + this.crypto = crypto; + this.streamReaderFactory = streamReaderFactory; + this.streamWriterFactory = streamWriterFactory; + } + + @Override + public void startExchange(ContactExchangeListener listener, + LocalAuthor localAuthor, SecretKey masterSecret, + DuplexTransportConnection conn, TransportId transportId, + boolean alice, int localType, int remoteType) { + this.listener = listener; + this.localAuthor = localAuthor; + this.conn = conn; + this.transportId = transportId; + this.masterSecret = masterSecret; + this.alice = alice; + this.localType = localType; + this.remoteType = remoteType; + start(); + + } + + @Override + public void run() { + // Get the transport connection's input and output streams + InputStream in; + OutputStream out; + try { + in = conn.getReader().getInputStream(); + out = conn.getWriter().getOutputStream(); + } catch (IOException e) { + logException(LOG, WARNING, e); + listener.contactExchangeFailed(); + tryToClose(conn); + return; + } + + // Get the local transport properties + Map<TransportId, TransportProperties> localProperties; + try { + localProperties = transportPropertyManager.getLocalProperties(); + } catch (DbException e) { + logException(LOG, WARNING, e); + listener.contactExchangeFailed(); + tryToClose(conn); + return; + } + + // Derive the header keys for the transport streams + SecretKey aliceHeaderKey = crypto.deriveKey(ALICE_KEY_LABEL, + masterSecret, new byte[] {PROTOCOL_VERSION}); + SecretKey bobHeaderKey = crypto.deriveKey(BOB_KEY_LABEL, masterSecret, + new byte[] {PROTOCOL_VERSION}); + + // Create the readers + InputStream streamReader = + streamReaderFactory.createContactExchangeStreamReader(in, + alice ? bobHeaderKey : aliceHeaderKey); + RecordReader recordReader = + recordReaderFactory.createRecordReader(streamReader); + + // Create the writers + StreamWriter streamWriter = + streamWriterFactory.createContactExchangeStreamWriter(out, + alice ? aliceHeaderKey : bobHeaderKey); + RecordWriter recordWriter = + recordWriterFactory + .createRecordWriter(streamWriter.getOutputStream()); + + // Derive the nonces to be signed + byte[] aliceNonce = crypto.mac(ALICE_NONCE_LABEL, masterSecret, + new byte[] {PROTOCOL_VERSION}); + byte[] bobNonce = crypto.mac(BOB_NONCE_LABEL, masterSecret, + new byte[] {PROTOCOL_VERSION}); + byte[] localNonce = alice ? aliceNonce : bobNonce; + byte[] remoteNonce = alice ? bobNonce : aliceNonce; + + // Sign the nonce + byte[] localSignature = sign(localAuthor, localNonce); + + // Exchange contact info + long localTimestamp = clock.currentTimeMillis(); + ContactInfo remoteInfo; + try { + if (alice) { + sendContactInfo(recordWriter, localAuthor, localProperties, + localSignature, localTimestamp); + recordWriter.flush(); + remoteInfo = receiveContactInfo(recordReader); + } else { + remoteInfo = receiveContactInfo(recordReader); + sendContactInfo(recordWriter, localAuthor, localProperties, + localSignature, localTimestamp); + recordWriter.flush(); + } + // Send EOF on the outgoing stream + streamWriter.sendEndOfStream(); + // Skip any remaining records from the incoming stream + try { + while (true) recordReader.readRecord(); + } catch (EOFException expected) { + LOG.info("End of stream"); + } + } catch (IOException e) { + logException(LOG, WARNING, e); + listener.contactExchangeFailed(); + tryToClose(conn); + return; + } + + // Verify the contact's signature + if (!verify(remoteInfo.author, remoteNonce, remoteInfo.signature)) { + LOG.warning("Invalid signature"); + listener.contactExchangeFailed(); + tryToClose(conn); + return; + } + + // The agreed timestamp is the minimum of the peers' timestamps + long timestamp = Math.min(localTimestamp, remoteInfo.timestamp); + + try { + ContactId contactId; + // Add the Contact/Repeater + contactId = addContact(remoteInfo.author, timestamp, + remoteInfo.properties); + + // Reuse the connection as a transport connection + connectionManager.manageOutgoingConnection(contactId, transportId, + conn); + // Pseudonym exchange succeeded + LOG.info("Pseudonym exchange succeeded"); + listener.contactExchangeSucceeded(remoteInfo.author); + } catch (ContactExistsException e) { + logException(LOG, WARNING, e); + tryToClose(conn); + listener.duplicateContact(remoteInfo.author); + } catch (DbException e) { + logException(LOG, WARNING, e); + tryToClose(conn); + listener.contactExchangeFailed(); + } + } + + private byte[] sign(LocalAuthor author, byte[] nonce) { + try { + return crypto.sign(SIGNING_LABEL_EXCHANGE, nonce, + author.getPrivateKey()); + } catch (GeneralSecurityException e) { + throw new AssertionError(); + } + } + + private boolean verify(Author author, byte[] nonce, byte[] signature) { + try { + return crypto.verifySignature(signature, SIGNING_LABEL_EXCHANGE, + nonce, author.getPublicKey()); + } catch (GeneralSecurityException e) { + return false; + } + } + + private void sendContactInfo(RecordWriter recordWriter, Author author, + Map<TransportId, TransportProperties> properties, byte[] signature, + long timestamp) throws IOException { + BdfList authorList = clientHelper.toList(author); + BdfDictionary props = clientHelper.toDictionary(properties); + BdfList payload = BdfList.of(authorList, props, signature, timestamp, localType); + recordWriter.writeRecord(new Record(PROTOCOL_VERSION, MAILBOX_INFO, + clientHelper.toByteArray(payload))); + LOG.info("Sent repeater info"); + } + + private ContactInfo receiveContactInfo(RecordReader recordReader) + throws IOException { + Record record; + do { + record = recordReader.readRecord(); + if (record.getProtocolVersion() != PROTOCOL_VERSION) + throw new FormatException(); + } while (record.getRecordType() != MAILBOX_INFO); + LOG.info("Received contact info"); + BdfList payload = clientHelper.toList(record.getPayload()); + checkSize(payload, 5); + Author author = clientHelper.parseAndValidateAuthor(payload.getList(0)); + BdfDictionary props = payload.getDictionary(1); + Map<TransportId, TransportProperties> properties = + clientHelper.parseAndValidateTransportPropertiesMap(props); + byte[] signature = payload.getRaw(2); + checkLength(signature, 1, MAX_SIGNATURE_LENGTH); + long timestamp = payload.getLong(3); + if (timestamp < 0) throw new FormatException(); + int type = payload.getLong(4).intValue(); + if(type != remoteType) + throw new AssertionError(); + return new ContactInfo(author, properties, signature, timestamp, type); + } + + private ContactId addContact(Author remoteAuthor, long timestamp, + Map<TransportId, TransportProperties> remoteProperties) + throws DbException { + ContactId contactId; + Transaction txn = db.startTransaction(false); + try { + if (remoteType == MAILBOX_OWNER) { + contactId = contactManager.addMailboxOwner(txn, remoteAuthor, + localAuthor.getId(), masterSecret, timestamp, alice); + //TODO: Do we need transport properties here? (Repeater will not contact the Owner) + } else { + contactId = contactManager.addPrivateMailbox(txn, remoteAuthor, + localAuthor.getId(), masterSecret, timestamp, alice); + transportPropertyManager.addRemoteProperties(txn, contactId, + remoteProperties); + } + + db.commitTransaction(txn); + } finally { + db.endTransaction(txn); + } + return contactId; + } + + private void tryToClose(DuplexTransportConnection conn) { + try { + LOG.info("Closing connection"); + conn.getReader().dispose(true, true); + conn.getWriter().dispose(true); + } catch (IOException e) { + logException(LOG, WARNING, e); + } + } + + +} diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java index 66e5cfcf6d72ec90eed0dffa4bbf56c51d38b071..d895d29a4390ea0806b8093fffd8df0be4a8d07e 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java @@ -78,7 +78,7 @@ interface Database<T> { * and returns an ID for the contact. */ ContactId addContact(T txn, Author remote, AuthorId local, boolean verified, - boolean active) throws DbException; + boolean active, int ype) throws DbException; /** * Stores a group. @@ -227,6 +227,14 @@ interface Database<T> { Collection<Contact> getContactsByAuthorId(T txn, AuthorId remote) throws DbException; + /** + * Returns a possibly empty collection of contacts of the given type. + * <p/> + * Read-only. + */ + Collection<Contact> getContactsByType(T txn, int type) + throws DbException; + /** * Returns all contacts associated with the given local pseudonym. * <p/> @@ -641,7 +649,7 @@ interface Database<T> { * Marks the given transport keys as usable for outgoing streams. */ void setTransportKeysActive(T txn, TransportId t, KeySetId k) - throws DbException; + throws DbException; /** * Updates the transmission count and expiry time of the given message diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index f2e4de1c6fff7cbd3fbc6e92f52dead50c34b458..85d0304dabb51c0c6805c7d1929205dc6d5627fa 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -172,7 +172,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { @Override public ContactId addContact(Transaction transaction, Author remote, - AuthorId local, boolean verified, boolean active) + AuthorId local, boolean verified, boolean active, int type) throws DbException { if (transaction.isReadOnly()) throw new IllegalArgumentException(); T txn = unbox(transaction); @@ -182,7 +182,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { throw new ContactExistsException(); if (db.containsContact(txn, remote.getId(), local)) throw new ContactExistsException(); - ContactId c = db.addContact(txn, remote, local, verified, active); + ContactId c = db.addContact(txn, remote, local, verified, active, type); transaction.attach(new ContactAddedEvent(c, active)); if (active) transaction.attach(new ContactStatusChangedEvent(c, true)); return c; @@ -397,6 +397,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { return db.getContactsByAuthorId(txn, remote); } + @Override + public Collection<Contact> getContactsByType(Transaction transaction, int type) throws DbException{ + T txn = unbox(transaction); + return db.getContactsByType(txn, type); + } + @Override public Collection<ContactId> getContacts(Transaction transaction, AuthorId a) throws DbException { diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java index baa67a29ac6397c6c7e26b17a18feb455924c111..45bba640147292976cc416122031a72bc8c2408c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java @@ -1,6 +1,7 @@ package org.briarproject.bramble.db; import org.briarproject.bramble.api.contact.Contact; +import org.briarproject.bramble.api.contact.ContactFactory; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DataTooNewException; @@ -76,7 +77,7 @@ import static org.briarproject.bramble.util.LogUtils.logException; abstract class JdbcDatabase implements Database<Connection> { // Package access for testing - static final int CODE_SCHEMA_VERSION = 39; + static final int CODE_SCHEMA_VERSION = 40; // Rotation period offsets for incoming transport keys private static final int OFFSET_PREV = -1; @@ -110,6 +111,7 @@ abstract class JdbcDatabase implements Database<Connection> { + " localAuthorId _HASH NOT NULL," + " verified BOOLEAN NOT NULL," + " active BOOLEAN NOT NULL," + + " type INT NOT NULL," + " PRIMARY KEY (contactId)," + " FOREIGN KEY (localAuthorId)" + " REFERENCES localAuthors (authorId)" @@ -571,7 +573,7 @@ abstract class JdbcDatabase implements Database<Connection> { @Override public ContactId addContact(Connection txn, Author remote, AuthorId local, - boolean verified, boolean active) throws DbException { + boolean verified, boolean active, int type) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { @@ -579,8 +581,8 @@ abstract class JdbcDatabase implements Database<Connection> { String sql = "INSERT INTO contacts" + " (authorId, formatVersion, name, publicKey," + " localAuthorId," - + " verified, active)" - + " VALUES (?, ?, ?, ?, ?, ?, ?)"; + + " verified, active, type)" + + " VALUES (?, ?, ?, ?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, remote.getId().getBytes()); ps.setInt(2, remote.getFormatVersion()); @@ -589,6 +591,7 @@ abstract class JdbcDatabase implements Database<Connection> { ps.setBytes(5, local.getBytes()); ps.setBoolean(6, verified); ps.setBoolean(7, active); + ps.setInt(8, type); int affected = ps.executeUpdate(); if (affected != 1) throw new DbStateException(); ps.close(); @@ -1194,7 +1197,7 @@ abstract class JdbcDatabase implements Database<Connection> { ResultSet rs = null; try { String sql = "SELECT authorId, formatVersion, name, publicKey," - + " localAuthorId, verified, active" + + " localAuthorId, verified, active, type" + " FROM contacts" + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); @@ -1208,11 +1211,14 @@ abstract class JdbcDatabase implements Database<Connection> { AuthorId localAuthorId = new AuthorId(rs.getBytes(5)); boolean verified = rs.getBoolean(6); boolean active = rs.getBoolean(7); + int type = rs.getInt(8); rs.close(); ps.close(); Author author = new Author(authorId, formatVersion, name, publicKey); - return new Contact(c, author, localAuthorId, verified, active); + return ContactFactory + .createContact(c, author, localAuthorId, verified, active, + type); } catch (SQLException e) { tryToClose(rs); tryToClose(ps); @@ -1227,7 +1233,7 @@ abstract class JdbcDatabase implements Database<Connection> { ResultSet rs = null; try { String sql = "SELECT contactId, authorId, formatVersion, name," - + " publicKey, localAuthorId, verified, active" + + " publicKey, localAuthorId, verified, active, type" + " FROM contacts"; ps = txn.prepareStatement(sql); rs = ps.executeQuery(); @@ -1243,8 +1249,10 @@ abstract class JdbcDatabase implements Database<Connection> { AuthorId localAuthorId = new AuthorId(rs.getBytes(6)); boolean verified = rs.getBoolean(7); boolean active = rs.getBoolean(8); - contacts.add(new Contact(contactId, author, localAuthorId, - verified, active)); + int type = rs.getInt(9); + contacts.add(ContactFactory + .createContact(contactId, author, localAuthorId, + verified, active, type)); } rs.close(); ps.close(); @@ -1286,7 +1294,7 @@ abstract class JdbcDatabase implements Database<Connection> { ResultSet rs = null; try { String sql = "SELECT contactId, formatVersion, name, publicKey," - + " localAuthorId, verified, active" + + " localAuthorId, verified, active, type" + " FROM contacts" + " WHERE authorId = ?"; ps = txn.prepareStatement(sql); @@ -1301,10 +1309,51 @@ abstract class JdbcDatabase implements Database<Connection> { AuthorId localAuthorId = new AuthorId(rs.getBytes(5)); boolean verified = rs.getBoolean(6); boolean active = rs.getBoolean(7); + int type = rs.getInt(8); Author author = new Author(remote, formatVersion, name, publicKey); - contacts.add(new Contact(c, author, localAuthorId, verified, - active)); + contacts.add(ContactFactory + .createContact(c, author, localAuthorId, verified, + active, type)); + } + rs.close(); + ps.close(); + return contacts; + } catch (SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + + @Override + public Collection<Contact> getContactsByType(Connection txn, + int type) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT contactId, authorId, formatVersion, name," + + " publicKey, localAuthorId, verified, active" + + " FROM contacts" + + " WHERE type = ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, type); + rs = ps.executeQuery(); + List<Contact> contacts = new ArrayList<>(); + while (rs.next()) { + ContactId contactId = new ContactId(rs.getInt(1)); + AuthorId authorId = new AuthorId(rs.getBytes(2)); + int formatVersion = rs.getInt(3); + String name = rs.getString(4); + byte[] publicKey = rs.getBytes(5); + Author author = + new Author(authorId, formatVersion, name, publicKey); + AuthorId localAuthorId = new AuthorId(rs.getBytes(6)); + boolean verified = rs.getBoolean(7); + boolean active = rs.getBoolean(8); + contacts.add(ContactFactory + .createContact(contactId, author, localAuthorId, + verified, active, type)); } rs.close(); ps.close(); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java index a90d685b185bfb565f34a9d78a275a0953ae0330..2f1e17300ccd2b733c2e3038097ec8ec032737eb 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/contact/ContactManagerImplTest.java @@ -3,6 +3,7 @@ package org.briarproject.bramble.contact; import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactManager; +import org.briarproject.bramble.api.contact.PrivateMailbox; import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.NoSuchContactException; @@ -20,6 +21,7 @@ import java.util.Collection; import java.util.Collections; import java.util.Random; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.test.TestUtils.getAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getSecretKey; @@ -53,7 +55,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase { context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); - oneOf(db).addContact(txn, remote, local, verified, active); + oneOf(db).addContact(txn, remote, local, verified, active, CONTACT); will(returnValue(contactId)); oneOf(keyManager).addContact(txn, contactId, master, timestamp, alice, active); @@ -127,6 +129,24 @@ public class ContactManagerImplTest extends BrambleMockTestCase { contactManager.getContact(remote.getId(), new AuthorId(getRandomId())); } + @Test + public void testGetContactByType() throws Exception { + Transaction txn = new Transaction(null, true); + Collection<Contact> regularContacts = Collections.singletonList(contact); + Collection<Contact> contacts = new ArrayList<>(regularContacts); + contacts.add(new PrivateMailbox(new ContactId(3), remote, local, true, true)); + context.checking(new Expectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).getContactsByType(txn, CONTACT); + will(returnValue(regularContacts)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + + assertEquals(regularContacts, contactManager.getContactsByType(CONTACT)); + } + @Test public void testActiveContacts() throws Exception { Collection<Contact> activeContacts = Collections.singletonList(contact); @@ -145,6 +165,24 @@ public class ContactManagerImplTest extends BrambleMockTestCase { assertEquals(activeContacts, contactManager.getActiveContacts()); } + @Test + public void testVisibleContacts() throws Exception { + Collection<Contact> visibleContacts = Collections.singletonList(contact); + Collection<Contact> contacts = new ArrayList<>(visibleContacts); + contacts.add(new PrivateMailbox(new ContactId(3), remote, local, true, true)); + Transaction txn = new Transaction(null, true); + context.checking(new Expectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).getContacts(txn); + will(returnValue(contacts)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + + assertEquals(visibleContacts, contactManager.getVisibleContacts()); + } + @Test public void testRemoveContact() throws Exception { Transaction txn = new Transaction(null, false); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java index e16e03da0dc51086f73c9c6ed45ee81483f8a3b1..fe42e5b44efb53602668ceaf9926a9c63a2e172e 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java @@ -61,6 +61,7 @@ import java.util.concurrent.atomic.AtomicReference; import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; 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; @@ -162,7 +163,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { localAuthor.getId()); will(returnValue(false)); oneOf(database).addContact(txn, author, localAuthor.getId(), - true, true); + true, true, CONTACT); will(returnValue(contactId)); oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class))); oneOf(eventBus).broadcast(with(any( @@ -213,7 +214,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, db.addContact(transaction, author, - localAuthor.getId(), true, true)); + localAuthor.getId(), true, true, CONTACT)); assertEquals(singletonList(contact), db.getContacts(transaction)); db.addGroup(transaction, group); // First time - listeners called @@ -479,7 +480,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { Transaction transaction = db.startTransaction(false); try { - db.addContact(transaction, author, localAuthor.getId(), true, true); + db.addContact(transaction, author, localAuthor.getId(), true, true, + CONTACT); fail(); } catch (NoSuchLocalAuthorException expected) { // Expected @@ -755,7 +757,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { localAuthor.getId()); will(returnValue(false)); oneOf(database).addContact(txn, author, localAuthor.getId(), - true, true); + true, true, CONTACT); will(returnValue(contactId)); oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class))); oneOf(eventBus).broadcast(with(any( @@ -776,7 +778,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, db.addContact(transaction, author, - localAuthor.getId(), true, true)); + localAuthor.getId(), true, true, CONTACT)); db.commitTransaction(transaction); } finally { db.endTransaction(transaction); @@ -1556,7 +1558,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { Transaction transaction = db.startTransaction(false); try { - db.addContact(transaction, author, localAuthor.getId(), true, true); + db.addContact(transaction, author, localAuthor.getId(), true, true, + CONTACT); fail(); } catch (ContactExistsException expected) { // Expected @@ -1586,7 +1589,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase { Transaction transaction = db.startTransaction(false); try { - db.addContact(transaction, author, localAuthor.getId(), true, true); + db.addContact(transaction, author, localAuthor.getId(), true, true, + CONTACT); fail(); } catch (ContactExistsException expected) { // Expected diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java index e46a75b68460ba81166b20aabbfcddcbca1fe4b8..8e1348df4719e0382f1b1f51d9d7c3a620c6c69f 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java @@ -32,6 +32,7 @@ import java.util.Random; import java.util.logging.Logger; import static java.util.logging.Level.OFF; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.api.sync.SyncConstants.MAX_MESSAGE_IDS; import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.bramble.test.TestUtils.deleteTestDirectory; @@ -546,7 +547,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase { db.addLocalAuthor(txn, localAuthor); for (int i = 0; i < CONTACTS; i++) { ContactId c = db.addContact(txn, getAuthor(), localAuthor.getId(), - random.nextBoolean(), true); + random.nextBoolean(), true, CONTACT); contacts.add(db.getContact(txn, c)); contactGroups.put(c, new ArrayList<>()); for (int j = 0; j < GROUPS_PER_CONTACT; j++) { diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java index 2655e9ef7f571cdbcc80abb2a492e3b0e7c5bdcd..25416de5acdd85de56da67ecb731d2b20492c153 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java @@ -48,6 +48,8 @@ import static java.util.Collections.emptyMap; import static java.util.Collections.singletonList; import static java.util.Collections.singletonMap; import static java.util.concurrent.TimeUnit.SECONDS; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; import static org.briarproject.bramble.api.db.Metadata.REMOVE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; @@ -130,7 +132,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { assertFalse(db.containsContact(txn, contactId)); db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); assertTrue(db.containsContact(txn, contactId)); assertFalse(db.containsGroup(txn, groupId)); db.addGroup(txn, group); @@ -193,7 +195,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, true, null); @@ -224,7 +226,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared but unvalidated message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, UNKNOWN, true, null); @@ -269,7 +271,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, an invisible group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addMessage(txn, message, DELIVERED, true, null); @@ -320,7 +322,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and an unshared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, false, null); @@ -351,7 +353,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, true, null); @@ -377,7 +379,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact and a visible group db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, false); @@ -418,7 +420,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, true, null); @@ -575,7 +577,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact and a shared group db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); @@ -595,7 +597,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); // The group is not in the database assertFalse(db.containsVisibleMessage(txn, contactId, messageId)); @@ -613,7 +615,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, an invisible group and a message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addMessage(txn, message, DELIVERED, true, null); @@ -632,7 +634,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact and a group db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); // The group should not be visible to the contact @@ -684,7 +686,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add the contact, the transport and the transport keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, active)); + true, active, CONTACT)); db.addTransport(txn, transportId, 123); assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); assertEquals(keySetId1, db.addTransportKeys(txn, contactId, keys1)); @@ -776,7 +778,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add the contact, transport and transport keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addTransport(txn, transportId, 123); assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); @@ -819,7 +821,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add the contact, transport and transport keys db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, active)); + true, active, CONTACT)); db.addTransport(txn, transportId, 123); assertEquals(keySetId, db.addTransportKeys(txn, contactId, keys)); @@ -860,7 +862,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact associated with the local author assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); // Ensure contact is returned from database by Author ID Collection<Contact> contacts = @@ -890,7 +892,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact associated with the local author assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); contacts = db.getContacts(txn, localAuthor.getId()); assertEquals(singletonList(contactId), contacts); @@ -912,7 +914,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact - initially there should be no offered messages db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); assertEquals(0, db.countOfferedMessages(txn, contactId)); // Add some offered messages and count them @@ -933,6 +935,40 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { db.close(); } + @Test + public void testGetContactsByType() throws Exception { + Database<Connection> db = open(false); + Connection txn = db.startTransaction(); + + ContactId contactId1 = new ContactId(2); + Author author1 = getAuthor(); + + // Add a local author - no contacts should be associated + db.addLocalAuthor(txn, localAuthor); + + // Add two contact associated with the local author + assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), + true, true, CONTACT)); + assertEquals(contactId1, + db.addContact(txn, author1, localAuthor.getId(), + true, true, CONTACT_MAILBOX)); + + // Ensure contact is returned from database by type + Collection<Contact> contacts = + db.getContactsByType(txn, CONTACT); + assertEquals(1, contacts.size()); + assertEquals(contactId, contacts.iterator().next().getId()); + assertEquals(CONTACT, contacts.iterator().next().getType()); + + // Ensure no contacts are returned after contact was deleted + db.removeContact(txn, contactId); + contacts = db.getContactsByType(txn, CONTACT); + assertEquals(0, contacts.size()); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testGroupMetadata() throws Exception { Database<Connection> db = open(false); @@ -1504,7 +1540,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, true, null); @@ -1615,9 +1651,11 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add the same contact for each local author ContactId contactId = - db.addContact(txn, author, localAuthor.getId(), true, true); + db.addContact(txn, author, localAuthor.getId(), true, true, + CONTACT); ContactId contactId1 = - db.addContact(txn, author, localAuthor1.getId(), true, true); + db.addContact(txn, author, localAuthor1.getId(), true, true, + CONTACT); // The contacts should be distinct assertNotEquals(contactId, contactId1); @@ -1637,7 +1675,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a shared group and a shared message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addGroupVisibility(txn, contactId, groupId, true); db.addMessage(txn, message, DELIVERED, true, null); @@ -1682,7 +1720,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); // The contact should be active Contact contact = db.getContact(txn, contactId); @@ -1737,7 +1775,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); assertEquals(contactId, db.addContact(txn, author, localAuthor.getId(), - true, true)); + true, true, CONTACT)); db.addGroup(txn, group); db.addMessage(txn, message, UNKNOWN, false, null); diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java index 2dc00d67f63d6cd1e96507df45627f3de7a63d00..04fa53f9f3375a1daff46d58a728782d5868b588 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contact/ContactListFragment.java @@ -198,7 +198,7 @@ public class ContactListFragment extends BaseFragment implements EventListener { try { long start = now(); List<ContactListItem> contacts = new ArrayList<>(); - for (Contact c : contactManager.getActiveContacts()) { + for (Contact c : contactManager.getVisibleContacts()) { try { ContactId id = c.getId(); GroupCount count = diff --git a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/ContactSelectorControllerImpl.java b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/ContactSelectorControllerImpl.java index 9f6380d0faeb96b9c4313fd42a1645ca2d757705..2c33ee63d99498f92921a973265be7f32e45ea2a 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/contactselection/ContactSelectorControllerImpl.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/contactselection/ContactSelectorControllerImpl.java @@ -44,7 +44,7 @@ public abstract class ContactSelectorControllerImpl runOnDbThread(() -> { try { Collection<SelectableContactItem> contacts = new ArrayList<>(); - for (Contact c : contactManager.getActiveContacts()) { + for (Contact c : contactManager.getVisibleContacts()) { // was this contact already selected? boolean selected = selection.contains(c.getId()); // can this contact be selected? diff --git a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java index e053c50c1d65f744bd27773472dd5be8ededc7e8..5117cb09b811ebf7c360ae4dc55a6a45555c9fde 100644 --- a/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java +++ b/briar-android/src/main/java/org/briarproject/briar/android/keyagreement/ContactExchangeActivity.java @@ -24,6 +24,7 @@ import javax.inject.Inject; import static android.widget.Toast.LENGTH_LONG; import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.util.LogUtils.logException; @MethodsNotNullByDefault @@ -51,7 +52,7 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements getSupportActionBar().setTitle(string.add_contact_title); } - private void startContactExchange(KeyAgreementResult result) { + protected void startContactExchange(KeyAgreementResult result) { runOnDbThread(() -> { LocalAuthor localAuthor; // Load the local pseudonym @@ -67,7 +68,7 @@ public class ContactExchangeActivity extends KeyAgreementActivity implements contactExchangeTask.startExchange(ContactExchangeActivity.this, localAuthor, result.getMasterKey(), result.getConnection(), result.getTransportId(), - result.wasAlice()); + result.wasAlice(), CONTACT, CONTACT); }); } diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java index 6a05b9a1542b00d463ddad795f864b97079a2d7e..bc87cea69e290b1e351d55190a2843896baa34c9 100644 --- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java @@ -49,6 +49,8 @@ import java.util.concurrent.CopyOnWriteArrayList; import javax.annotation.Nullable; import javax.inject.Inject; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; import static org.briarproject.briar.api.blog.BlogConstants.KEY_AUTHOR; import static org.briarproject.briar.api.blog.BlogConstants.KEY_COMMENT; import static org.briarproject.briar.api.blog.BlogConstants.KEY_ORIGINAL_MSG_ID; @@ -99,6 +101,12 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, @Override public void removingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } Blog b = blogFactory.createBlog(c.getAuthor()); // TODO we might want to reconsider removing b, if otherwise shared if (db.containsGroup(txn, b.getId())) removeBlog(txn, b); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java index 651bd8a97336a8d5d352ab24b831eae2c5bfff2f..2928ed24866d6d60ff282f4afe6ace968206aa4f 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroduceeProtocolEngine.java @@ -40,6 +40,7 @@ import javax.annotation.concurrent.Immutable; import javax.inject.Inject; import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; import static org.briarproject.briar.introduction.IntroduceeState.AWAIT_AUTH; diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java index 64fc1b40d48ef99feca8a52c6869a1d2fcd105e2..90a2e6ee11ce93fc1bff95e002de73c35bffca43 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java @@ -47,6 +47,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; import static org.briarproject.briar.api.introduction.Role.INTRODUCEE; import static org.briarproject.briar.api.introduction.Role.INTRODUCER; import static org.briarproject.briar.introduction.IntroducerState.START; @@ -119,6 +121,12 @@ class IntroductionManagerImpl extends ConversationClientImpl @Override public void addingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Create a group to share with the contact Group g = getContactGroup(c); db.addGroup(txn, g); @@ -138,6 +146,12 @@ class IntroductionManagerImpl extends ConversationClientImpl @Override public void removingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } removeSessionWithIntroducer(txn, c); abortOrRemoveSessionWithIntroducee(txn, c); 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 a4aef1eca325f79485c255c311510cd9d58219d4..cec30893369cd4d7b378065279c6ae639e07b9f3 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 @@ -48,6 +48,8 @@ import javax.annotation.Nullable; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.briar.privategroup.invitation.CreatorState.START; import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; @@ -113,6 +115,12 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Override public void addingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Create a group to share with the contact Group g = getContactGroup(c); db.addGroup(txn, g); @@ -137,6 +145,12 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Override public void removingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Remove the contact group (all messages will be removed with it) db.removeGroup(txn, getContactGroup(c)); } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java index 5c77c7be942df58dd618bfc5fd70d055699d4bc9..5af30f69eec1e7340085675a1b650a3be632450a 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java @@ -23,6 +23,9 @@ import org.briarproject.briar.api.client.MessageTracker; import javax.annotation.concurrent.Immutable; import javax.inject.Inject; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; + @Immutable @NotNullByDefault class BlogSharingManagerImpl extends SharingManagerImpl<Blog> @@ -70,6 +73,12 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog> @Override public void addingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Create a group to share with the contact super.addingContact(txn, c); 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 fc57a6daace13c60480ea5e1c4e2518b4920ad1f..2e7de3035069b677eb92dc146d18c3236caf159e 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 @@ -43,6 +43,8 @@ import java.util.Map.Entry; import javax.annotation.Nullable; +import static org.briarproject.bramble.api.contact.ContactTypes.PRIVATE_MAILBOX; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT_MAILBOX; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.briar.sharing.MessageType.ABORT; import static org.briarproject.briar.sharing.MessageType.ACCEPT; @@ -104,6 +106,12 @@ abstract class SharingManagerImpl<S extends Shareable> @Override public void addingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Create a group to share with the contact Group g = getContactGroup(c); db.addGroup(txn, g); @@ -122,6 +130,12 @@ abstract class SharingManagerImpl<S extends Shareable> @Override public void removingContact(Transaction txn, Contact c) throws DbException { + switch (c.getType()) { + case PRIVATE_MAILBOX: + return; + case CONTACT_MAILBOX: + return; + } // Remove the contact group (all messages will be removed with it) db.removeGroup(txn, getContactGroup(c)); } diff --git a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java index 811f3a351008aaca919437fc2519d3d47087ba57..ca500bb60b1d9d39f527cf4a671955d36f9939ef 100644 --- a/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/test/TestDataCreatorImpl.java @@ -53,6 +53,7 @@ import javax.inject.Inject; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.api.plugin.BluetoothConstants.UUID_BYTES; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.util.StringUtils.getRandomString; diff --git a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java index b3161af64dce727a64b1fafa8dba50879ce68094..9cecc0cc6115d85a2736a8198884586fec083bc9 100644 --- a/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/introduction/IntroductionIntegrationTest.java @@ -41,6 +41,7 @@ import java.util.Collection; import java.util.Map; import java.util.concurrent.TimeoutException; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; diff --git a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java index 1007afe5e08866139119b5d3b3d129d5c1d8d434..f65ecfed48a608108b55d8670b3fcb215ccd0e9e 100644 --- a/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/messaging/SimplexMessagingIntegrationTest.java @@ -41,6 +41,7 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.api.transport.TransportConstants.TAG_LENGTH; import static org.briarproject.bramble.test.TestPluginConfigModule.MAX_LATENCY; import static org.briarproject.bramble.test.TestPluginConfigModule.TRANSPORT_ID; diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java index 481a574869a56d0f455a7f6673b7bf1f56fb5f32..557e853dcb62557a395ad659ada6be05bfc6b352 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarIntegrationTest.java @@ -62,6 +62,7 @@ import javax.annotation.Nullable; import javax.inject.Inject; import static junit.framework.Assert.assertNotNull; +import static org.briarproject.bramble.api.contact.ContactTypes.CONTACT; import static org.briarproject.bramble.api.sync.ValidationManager.State.DELIVERED; import static org.briarproject.bramble.api.sync.ValidationManager.State.INVALID; import static org.briarproject.bramble.api.sync.ValidationManager.State.PENDING;