mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-12 18:59:06 +01:00
Merge branch 'embargo-inactive-contacts' into 'master'
Don't communicate with inactive contacts When we're introduced to a new contact, we need to store the transport keys and start key rotation before activating the contact. During this period we shouldn't use the transport keys for outgoing streams until either the introduction protocol is complete or we receive an incoming stream from the contact, indicating that they've also started key rotation. See merge request !106
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package org.briarproject.transport;
|
||||
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.CryptoComponent;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
@@ -9,6 +10,7 @@ import org.briarproject.api.db.DatabaseExecutor;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.db.Transaction;
|
||||
import org.briarproject.api.event.ContactRemovedEvent;
|
||||
import org.briarproject.api.event.ContactStatusChangedEvent;
|
||||
import org.briarproject.api.event.Event;
|
||||
import org.briarproject.api.event.EventListener;
|
||||
import org.briarproject.api.event.TransportAddedEvent;
|
||||
@@ -19,6 +21,7 @@ import org.briarproject.api.system.Timer;
|
||||
import org.briarproject.api.transport.KeyManager;
|
||||
import org.briarproject.api.transport.StreamContext;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
@@ -39,6 +42,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
private final ExecutorService dbExecutor;
|
||||
private final Timer timer;
|
||||
private final Clock clock;
|
||||
private final Map<ContactId, Boolean> activeContacts;
|
||||
private final ConcurrentHashMap<TransportId, TransportKeyManager> managers;
|
||||
|
||||
@Inject
|
||||
@@ -50,20 +54,26 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
this.dbExecutor = dbExecutor;
|
||||
this.timer = timer;
|
||||
this.clock = clock;
|
||||
// Use a ConcurrentHashMap as a thread-safe set
|
||||
activeContacts = new ConcurrentHashMap<ContactId, Boolean>();
|
||||
managers = new ConcurrentHashMap<TransportId, TransportKeyManager>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean start() {
|
||||
try {
|
||||
Collection<Contact> contacts;
|
||||
Map<TransportId, Integer> latencies;
|
||||
Transaction txn = db.startTransaction();
|
||||
try {
|
||||
contacts = db.getContacts(txn);
|
||||
latencies = db.getTransportLatencies(txn);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
for (Contact c : contacts)
|
||||
if (c.isActive()) activeContacts.put(c.getId(), true);
|
||||
for (Entry<TransportId, Integer> e : latencies.entrySet())
|
||||
addTransport(e.getKey(), e.getValue());
|
||||
} catch (DbException e) {
|
||||
@@ -85,13 +95,33 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
}
|
||||
|
||||
public StreamContext getStreamContext(ContactId c, TransportId t) {
|
||||
// Don't allow outgoing streams to inactive contacts
|
||||
if (!activeContacts.containsKey(c)) return null;
|
||||
TransportKeyManager m = managers.get(t);
|
||||
return m == null ? null : m.getStreamContext(c);
|
||||
}
|
||||
|
||||
public StreamContext getStreamContext(TransportId t, byte[] tag) {
|
||||
TransportKeyManager m = managers.get(t);
|
||||
return m == null ? null : m.recogniseTag(tag);
|
||||
if (m == null) return null;
|
||||
StreamContext ctx = m.getStreamContext(tag);
|
||||
if (ctx == null) return null;
|
||||
// Activate the contact if not already active
|
||||
if (!activeContacts.containsKey(ctx.getContactId())) {
|
||||
try {
|
||||
Transaction txn = db.startTransaction();
|
||||
try {
|
||||
db.setContactActive(txn, ctx.getContactId(), true);
|
||||
txn.setComplete();
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
} catch (DbException e) {
|
||||
if (LOG.isLoggable(WARNING)) LOG.log(WARNING, e.toString(), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
public void eventOccurred(Event e) {
|
||||
@@ -102,6 +132,10 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
removeTransport(((TransportRemovedEvent) e).getTransportId());
|
||||
} else if (e instanceof ContactRemovedEvent) {
|
||||
removeContact(((ContactRemovedEvent) e).getContactId());
|
||||
} else if (e instanceof ContactStatusChangedEvent) {
|
||||
ContactStatusChangedEvent c = (ContactStatusChangedEvent) e;
|
||||
if (c.isActive()) activeContacts.put(c.getContactId(), true);
|
||||
else activeContacts.remove(c.getContactId());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +155,7 @@ class KeyManagerImpl implements KeyManager, Service, EventListener {
|
||||
}
|
||||
|
||||
private void removeContact(final ContactId c) {
|
||||
activeContacts.remove(c);
|
||||
dbExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
for (TransportKeyManager m : managers.values())
|
||||
|
||||
@@ -207,7 +207,7 @@ class TransportKeyManager extends TimerTask {
|
||||
}
|
||||
}
|
||||
|
||||
StreamContext recogniseTag(byte[] tag) {
|
||||
StreamContext getStreamContext(byte[] tag) {
|
||||
lock.lock();
|
||||
try {
|
||||
// Look up the incoming keys for the tag
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.briarproject.BriarTestCase;
|
||||
import org.briarproject.TestDatabaseConfig;
|
||||
import org.briarproject.TestUtils;
|
||||
import org.briarproject.api.TransportId;
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.crypto.SecretKey;
|
||||
import org.briarproject.api.db.DbException;
|
||||
@@ -1108,6 +1109,38 @@ public class H2DatabaseTest extends BriarTestCase {
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetContactActive() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
Connection txn = db.startTransaction();
|
||||
|
||||
// Add a contact
|
||||
db.addLocalAuthor(txn, localAuthor);
|
||||
assertEquals(contactId, db.addContact(txn, author, localAuthorId,
|
||||
true));
|
||||
|
||||
// The contact should be active
|
||||
Contact contact = db.getContact(txn, contactId);
|
||||
assertTrue(contact.isActive());
|
||||
|
||||
// Set the contact inactive
|
||||
db.setContactActive(txn, contactId, false);
|
||||
|
||||
// The contact should be inactive
|
||||
contact = db.getContact(txn, contactId);
|
||||
assertFalse(contact.isActive());
|
||||
|
||||
// Set the contact active
|
||||
db.setContactActive(txn, contactId, true);
|
||||
|
||||
// The contact should be active
|
||||
contact = db.getContact(txn, contactId);
|
||||
assertTrue(contact.isActive());
|
||||
|
||||
db.commitTransaction(txn);
|
||||
db.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExceptionHandling() throws Exception {
|
||||
Database<Connection> db = open(false);
|
||||
|
||||
Reference in New Issue
Block a user