Also test that messages arrive and activate keys

This commit is contained in:
Torsten Grote
2021-06-24 15:57:19 -03:00
parent 3f6f970d36
commit dc3ba3d8f0
4 changed files with 125 additions and 20 deletions

View File

@@ -45,7 +45,6 @@ abstract class Connection {
@Nullable @Nullable
StreamContext recogniseTag(TransportConnectionReader reader, StreamContext recogniseTag(TransportConnectionReader reader,
TransportId transportId) { TransportId transportId) {
StreamContext ctx;
try { try {
byte[] tag = readTag(reader.getInputStream()); byte[] tag = readTag(reader.getInputStream());
return keyManager.getStreamContext(transportId, tag); return keyManager.getStreamContext(transportId, tag);

View File

@@ -13,6 +13,7 @@ import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault; import org.briarproject.bramble.api.nullsafety.MethodsNotNullByDefault;
import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault; import org.briarproject.bramble.api.nullsafety.ParametersNotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent; import org.briarproject.bramble.api.sync.event.MessageStateChangedEvent;
import org.briarproject.bramble.api.sync.event.MessagesAckedEvent; import org.briarproject.bramble.api.sync.event.MessagesAckedEvent;
@@ -152,6 +153,13 @@ public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestCom
} }
protected void syncMessage(BrambleIntegrationTestComponent fromComponent,
BrambleIntegrationTestComponent toComponent, ContactId toId,
TransportId transportId, int num, boolean valid) throws Exception {
syncMessage(fromComponent, toComponent, toId, transportId, num, 0,
valid ? 0 : num, valid ? num : 0);
}
protected void syncMessage(BrambleIntegrationTestComponent fromComponent, protected void syncMessage(BrambleIntegrationTestComponent fromComponent,
BrambleIntegrationTestComponent toComponent, ContactId toId, BrambleIntegrationTestComponent toComponent, ContactId toId,
int num, boolean valid) throws Exception { int num, boolean valid) throws Exception {
@@ -163,7 +171,14 @@ public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestCom
BrambleIntegrationTestComponent toComponent, ContactId toId, BrambleIntegrationTestComponent toComponent, ContactId toId,
int numNew, int numDupes, int numPendingOrInvalid, int numDelivered) int numNew, int numDupes, int numPendingOrInvalid, int numDelivered)
throws Exception { throws Exception {
syncMessage(fromComponent, toComponent, toId, SIMPLEX_TRANSPORT_ID,
numNew, numDupes, numPendingOrInvalid, numDelivered);
}
protected void syncMessage(BrambleIntegrationTestComponent fromComponent,
BrambleIntegrationTestComponent toComponent, ContactId toId,
TransportId transportId, int numNew, int numDupes,
int numPendingOrInvalid, int numDelivered) throws Exception {
// Debug output // Debug output
String from = String from =
fromComponent.getIdentityManager().getLocalAuthor().getName(); fromComponent.getIdentityManager().getLocalAuthor().getName();
@@ -181,7 +196,7 @@ public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestCom
TestTransportConnectionWriter writer = TestTransportConnectionWriter writer =
new TestTransportConnectionWriter(out, false); new TestTransportConnectionWriter(out, false);
fromComponent.getConnectionManager().manageOutgoingConnection(toId, fromComponent.getConnectionManager().manageOutgoingConnection(toId,
SIMPLEX_TRANSPORT_ID, writer); transportId, writer);
writer.getDisposedLatch().await(TIMEOUT, MILLISECONDS); writer.getDisposedLatch().await(TIMEOUT, MILLISECONDS);
// Check that the expected number of messages were sent // Check that the expected number of messages were sent
@@ -195,7 +210,7 @@ public abstract class BrambleIntegrationTest<C extends BrambleIntegrationTestCom
TestTransportConnectionReader reader = TestTransportConnectionReader reader =
new TestTransportConnectionReader(in); new TestTransportConnectionReader(in);
toComponent.getConnectionManager().manageIncomingConnection( toComponent.getConnectionManager().manageIncomingConnection(
SIMPLEX_TRANSPORT_ID, reader); transportId, reader);
if (numPendingOrInvalid > 0) { if (numPendingOrInvalid > 0) {
validationWaiter.await(TIMEOUT, numPendingOrInvalid); validationWaiter.await(TIMEOUT, numPendingOrInvalid);

View File

@@ -7,12 +7,14 @@ import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.data.BdfDictionary; import org.briarproject.bramble.api.data.BdfDictionary;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.Identity; import org.briarproject.bramble.api.identity.Identity;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.plugin.TransportId; import org.briarproject.bramble.api.plugin.TransportId;
import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.sync.Group; import org.briarproject.bramble.api.sync.Group;
import org.briarproject.bramble.api.sync.MessageId; import org.briarproject.bramble.api.sync.MessageId;
import org.briarproject.bramble.test.BrambleIntegrationTest; import org.briarproject.bramble.test.BrambleIntegrationTest;
@@ -47,6 +49,7 @@ public class TransportKeyAgreementIntegrationTest
new TransportId(getRandomString(8)); new TransportId(getRandomString(8));
private TransportKeyAgreementTestComponent alice, bob; private TransportKeyAgreementTestComponent alice, bob;
private Identity aliceIdentity, bobIdentity;
@Before @Before
@Override @Override
@@ -56,9 +59,13 @@ public class TransportKeyAgreementIntegrationTest
alice = createComponent(aliceDir, false); alice = createComponent(aliceDir, false);
bob = createComponent(bobDir, false); bob = createComponent(bobDir, false);
// Create identities
aliceIdentity = alice.getIdentityManager().createIdentity("Alice");
bobIdentity = bob.getIdentityManager().createIdentity("Bob");
// Start both lifecycles // Start both lifecycles
startLifecycle(alice, "Alice"); startLifecycle(alice, aliceIdentity);
startLifecycle(bob, "Bob"); startLifecycle(bob, bobIdentity);
} }
private TransportKeyAgreementTestComponent createComponent( private TransportKeyAgreementTestComponent createComponent(
@@ -79,13 +86,11 @@ public class TransportKeyAgreementIntegrationTest
private void startLifecycle( private void startLifecycle(
TransportKeyAgreementTestComponent device, TransportKeyAgreementTestComponent device,
String identityName) throws Exception { Identity identity) throws Exception {
// Listen to message related events first to not miss early ones // Listen to message related events first to not miss early ones
addEventListener(device); addEventListener(device);
// Add an identity for the user // Register identity before starting lifecycle
IdentityManager identityManager = device.getIdentityManager(); device.getIdentityManager().registerIdentity(identity);
Identity identity = identityManager.createIdentity(identityName);
identityManager.registerIdentity(identity);
// Start the lifecycle manager // Start the lifecycle manager
LifecycleManager lifecycleManager = device.getLifecycleManager(); LifecycleManager lifecycleManager = device.getLifecycleManager();
lifecycleManager.startServices(masterKey); // re-using masterKey here lifecycleManager.startServices(masterKey); // re-using masterKey here
@@ -116,8 +121,8 @@ public class TransportKeyAgreementIntegrationTest
ContactId bobId = contactIds.getSecond(); ContactId bobId = contactIds.getSecond();
// Alice and Bob restart and come back with the new transport. // Alice and Bob restart and come back with the new transport.
alice = restartWithNewTransport(alice, aliceDir, "Alice"); alice = restartWithNewTransport(alice, aliceDir, aliceIdentity);
bob = restartWithNewTransport(bob, bobDir, "Bob"); bob = restartWithNewTransport(bob, bobDir, bobIdentity);
// They can still send via the old simplex, // They can still send via the old simplex,
// but not via the new duplex transport // but not via the new duplex transport
@@ -154,6 +159,10 @@ public class TransportKeyAgreementIntegrationTest
// Ensure that private key is not stored anymore. // Ensure that private key is not stored anymore.
assertLocalKeyPairIsNull(alice, bobId); assertLocalKeyPairIsNull(alice, bobId);
assertLocalKeyPairIsNull(bob, aliceId); assertLocalKeyPairIsNull(bob, aliceId);
// Messages can be send over the new transport in both directions.
assertTransportMessageArrives(alice, bob, bobId, newTransportId);
assertTransportMessageArrives(bob, alice, aliceId, newTransportId);
} }
@Test @Test
@@ -164,7 +173,7 @@ public class TransportKeyAgreementIntegrationTest
ContactId bobId = contactIds.getSecond(); ContactId bobId = contactIds.getSecond();
// Alice restarts and comes back with the new transport. // Alice restarts and comes back with the new transport.
alice = restartWithNewTransport(alice, aliceDir, "Alice"); alice = restartWithNewTransport(alice, aliceDir, aliceIdentity);
// Alice can still send via the old simplex, // Alice can still send via the old simplex,
// but not via the new duplex transport // but not via the new duplex transport
@@ -178,7 +187,7 @@ public class TransportKeyAgreementIntegrationTest
syncMessage(alice, bob, bobId, 1, false); syncMessage(alice, bob, bobId, 1, false);
// Bob restarts and comes back with the new transport. // Bob restarts and comes back with the new transport.
bob = restartWithNewTransport(bob, bobDir, "Bob"); bob = restartWithNewTransport(bob, bobDir, bobIdentity);
// Alice's pending KEY message now gets delivered async, so wait for it // Alice's pending KEY message now gets delivered async, so wait for it
awaitPendingMessageDelivery(1); awaitPendingMessageDelivery(1);
@@ -204,12 +213,16 @@ public class TransportKeyAgreementIntegrationTest
// Ensure that private key is not stored anymore. // Ensure that private key is not stored anymore.
assertLocalKeyPairIsNull(alice, bobId); assertLocalKeyPairIsNull(alice, bobId);
assertLocalKeyPairIsNull(bob, aliceId); assertLocalKeyPairIsNull(bob, aliceId);
// Messages can be send over the new transport in both directions.
assertTransportMessageArrives(alice, bob, bobId, newTransportId);
assertTransportMessageArrives(bob, alice, aliceId, newTransportId);
} }
@Test @Test
public void testAliceAlreadyHasTransportWhenAddingBob() throws Exception { public void testAliceAlreadyHasTransportWhenAddingBob() throws Exception {
// Alice restarts and comes back with the new transport. // Alice restarts and comes back with the new transport.
alice = restartWithNewTransport(alice, aliceDir, "Alice"); alice = restartWithNewTransport(alice, aliceDir, aliceIdentity);
// Alice and Bob add each other. // Alice and Bob add each other.
Pair<ContactId, ContactId> contactIds = addContacts(false); Pair<ContactId, ContactId> contactIds = addContacts(false);
@@ -225,7 +238,7 @@ public class TransportKeyAgreementIntegrationTest
// .canSendOutgoingStreams(bobId, newTransportId)); // .canSendOutgoingStreams(bobId, newTransportId));
// Bob restarts and comes back with the new transport. // Bob restarts and comes back with the new transport.
bob = restartWithNewTransport(bob, bobDir, "Bob"); bob = restartWithNewTransport(bob, bobDir, bobIdentity);
// Bob sends his own KEY message. // Bob sends his own KEY message.
syncMessage(bob, alice, aliceId, 1, true); syncMessage(bob, alice, aliceId, 1, true);
@@ -248,6 +261,68 @@ public class TransportKeyAgreementIntegrationTest
// Ensure that private key is not stored anymore. // Ensure that private key is not stored anymore.
assertLocalKeyPairIsNull(alice, bobId); assertLocalKeyPairIsNull(alice, bobId);
assertLocalKeyPairIsNull(bob, aliceId); assertLocalKeyPairIsNull(bob, aliceId);
// Bobs still sends his ACTIVATE message.
syncMessage(bob, alice, aliceId, 1, true);
// Messages can be send over the new transport in both directions.
assertTransportMessageArrives(alice, bob, bobId, newTransportId);
assertTransportMessageArrives(bob, alice, aliceId, newTransportId);
}
@Test
public void testAliceActivatesKeysByIncomingMessage() throws Exception {
// Alice and Bob add each other.
Pair<ContactId, ContactId> contactIds = addContacts(true);
ContactId aliceId = contactIds.getFirst();
ContactId bobId = contactIds.getSecond();
// Alice and Bob restart and come back with the new transport.
alice = restartWithNewTransport(alice, aliceDir, aliceIdentity);
bob = restartWithNewTransport(bob, bobDir, bobIdentity);
// They can still send via the old simplex,
// but not via the new duplex transport
assertTrue(alice.getKeyManager()
.canSendOutgoingStreams(bobId, SIMPLEX_TRANSPORT_ID));
assertFalse(alice.getKeyManager()
.canSendOutgoingStreams(bobId, newTransportId));
assertTrue(bob.getKeyManager()
.canSendOutgoingStreams(aliceId, SIMPLEX_TRANSPORT_ID));
assertFalse(bob.getKeyManager()
.canSendOutgoingStreams(aliceId, newTransportId));
// Bobs has started a session and sends KEY message to Alice
syncMessage(bob, alice, aliceId, 1, true);
// Alice now and sends her own KEY as well as her ACTIVATE message.
syncMessage(alice, bob, bobId, 2, true);
// Bob can already send over the new transport while Alice still can't.
assertFalse(alice.getKeyManager()
.canSendOutgoingStreams(bobId, newTransportId));
assertTrue(bob.getKeyManager()
.canSendOutgoingStreams(aliceId, newTransportId));
// Bob's database mysteriously loses the ACTIVATE message,
// so it won't be send to Alice.
Contact contact = bob.getContactManager().getContact(aliceId);
Group group = getContactGroup(bob, contact);
Map<MessageId, BdfDictionary> map = bob.getClientHelper()
.getMessageMetadataAsDictionary(group.getId());
DatabaseComponent db = bob.getDatabaseComponent();
for (Map.Entry<MessageId, BdfDictionary> e : map.entrySet()) {
if (e.getValue().getBoolean(MSG_KEY_IS_SESSION)) continue;
db.transaction(false, txn -> db.removeMessage(txn, e.getKey()));
}
// Bob sends a message to Alice
assertTransportMessageArrives(bob, alice, aliceId, newTransportId);
// Now without receiving the ACTIVATE, Alice can already send to Bob
assertTrue(alice.getKeyManager()
.canSendOutgoingStreams(bobId, newTransportId));
assertTransportMessageArrives(alice, bob, bobId, newTransportId);
} }
private Pair<ContactId, ContactId> addContacts( private Pair<ContactId, ContactId> addContacts(
@@ -292,12 +367,12 @@ public class TransportKeyAgreementIntegrationTest
} }
private TransportKeyAgreementTestComponent restartWithNewTransport( private TransportKeyAgreementTestComponent restartWithNewTransport(
TransportKeyAgreementTestComponent device, File dir, String name) TransportKeyAgreementTestComponent device, File dir,
throws Exception { Identity identity) throws Exception {
tearDown(device); tearDown(device);
TransportKeyAgreementTestComponent newDevice = TransportKeyAgreementTestComponent newDevice =
createComponent(dir, true); createComponent(dir, true);
startLifecycle(newDevice, name); startLifecycle(newDevice, identity);
return newDevice; return newDevice;
} }
@@ -312,7 +387,7 @@ public class TransportKeyAgreementIntegrationTest
throws Exception { throws Exception {
Contact contact = device.getContactManager().getContact(contactId); Contact contact = device.getContactManager().getContact(contactId);
Group group = getContactGroup(device, contact); Group group = getContactGroup(device, contact);
Map<MessageId, BdfDictionary> map = bob.getClientHelper() Map<MessageId, BdfDictionary> map = device.getClientHelper()
.getMessageMetadataAsDictionary(group.getId()); .getMessageMetadataAsDictionary(group.getId());
for (Map.Entry<MessageId, BdfDictionary> e : map.entrySet()) { for (Map.Entry<MessageId, BdfDictionary> e : map.entrySet()) {
if (!e.getValue().getBoolean(MSG_KEY_IS_SESSION)) continue; if (!e.getValue().getBoolean(MSG_KEY_IS_SESSION)) continue;
@@ -327,4 +402,14 @@ public class TransportKeyAgreementIntegrationTest
MAJOR_VERSION, c); MAJOR_VERSION, c);
} }
private void assertTransportMessageArrives(
TransportKeyAgreementTestComponent from,
TransportKeyAgreementTestComponent to, ContactId toId,
TransportId transportId) throws Exception {
TransportProperties p = new TransportProperties();
p.putBoolean("foo", true);
from.getTransportPropertyManager().mergeLocalProperties(transportId, p);
syncMessage(from, to, toId, transportId, 1, true);
}
} }

View File

@@ -3,7 +3,9 @@ package org.briarproject.bramble.transport.agreement;
import org.briarproject.bramble.BrambleCoreModule; import org.briarproject.bramble.BrambleCoreModule;
import org.briarproject.bramble.api.client.ContactGroupFactory; import org.briarproject.bramble.api.client.ContactGroupFactory;
import org.briarproject.bramble.api.contact.ContactManager; import org.briarproject.bramble.api.contact.ContactManager;
import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.properties.TransportPropertyManager;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule; import org.briarproject.bramble.test.BrambleCoreIntegrationTestModule;
import org.briarproject.bramble.test.BrambleIntegrationTestComponent; import org.briarproject.bramble.test.BrambleIntegrationTestComponent;
@@ -31,4 +33,8 @@ interface TransportKeyAgreementTestComponent
ContactGroupFactory getContactGroupFactory(); ContactGroupFactory getContactGroupFactory();
SessionParser getSessionParser(); SessionParser getSessionParser();
TransportPropertyManager getTransportPropertyManager();
DatabaseComponent getDatabaseComponent();
} }